├── .clang-format ├── .gitattributes ├── .github └── workflows │ └── nightly.yml ├── .gitignore ├── CMakeLists.txt ├── CMakeSettings.json ├── LICENSE ├── README.md ├── cmake_scripts ├── git.cmake └── rom.cmake ├── docs └── lua │ ├── classes │ ├── CCode.md │ ├── CInstance.md │ ├── CScriptRef.md │ ├── RValue.md │ ├── RefDynamicArrayOfRValue.md │ ├── YYObjectBase.md │ ├── config.config_definition.md │ ├── config.config_entry.md │ ├── config.config_file.md │ ├── definitions │ │ ├── CCode.lua │ │ ├── CInstance.lua │ │ ├── CScriptRef.lua │ │ ├── RValue.lua │ │ ├── RefDynamicArrayOfRValue.lua │ │ ├── YYObjectBase.lua │ │ ├── config.config_definition.lua │ │ ├── config.config_entry.lua │ │ ├── config.config_file.lua │ │ ├── lua_patch.lua │ │ ├── pointer.lua │ │ └── value_wrapper.lua │ ├── lua_patch.md │ ├── pointer.md │ └── value_wrapper.md │ └── tables │ ├── EVariableType.md │ ├── ImGui.md │ ├── RValueType.md │ ├── YYObjectBaseType.md │ ├── _ENV - Plugin Specific Global Table.md │ ├── config.md │ ├── definitions │ ├── EVariableType.lua │ ├── RValueType.lua │ ├── YYObjectBaseType.lua │ ├── _ENV - Plugin Specific Global Table.lua │ ├── config.lua │ ├── gm.CInstance.lua │ ├── gm.lua │ ├── gui.lua │ ├── log.lua │ ├── memory.lua │ ├── mods.lua │ ├── path.lua │ └── paths.lua │ ├── gm.CInstance.md │ ├── gm.md │ ├── gui.md │ ├── log.md │ ├── memory.md │ ├── mods.md │ ├── path.md │ ├── paths.md │ └── toml.md ├── examples ├── plugins │ ├── ReturnOfModding-DebugToolkit │ │ ├── lib_debug.lua │ │ ├── main.lua │ │ └── manifest.json │ ├── ReturnOfModding-ShareItem │ │ ├── main.lua │ │ └── manifest.json │ ├── sarn-coolguy │ │ ├── main.lua │ │ └── manifest.json │ └── sarn-coolguy_setup │ │ ├── main.lua │ │ ├── manifest.json │ │ └── survivor_setup.lua └── plugins_data │ └── sarn-coolguy │ └── spritesheet_sniper_walk_blue.png ├── linux_build.sh ├── lua_doc_gen.txt ├── src ├── common.hpp ├── dll_proxy │ ├── dll_proxy.cpp │ ├── dll_proxy.hpp │ └── version.def ├── gui │ ├── gui.cpp │ ├── gui.hpp │ ├── imgui_config.hpp │ ├── renderer.cpp │ └── renderer.hpp ├── lua │ ├── bindings │ │ ├── game_maker.cpp │ │ ├── game_maker.hpp │ │ ├── gui_ext.cpp │ │ └── gui_ext.hpp │ ├── lua_manager_extension.cpp │ ├── lua_manager_extension.hpp │ └── lua_module_ext.hpp ├── main.cpp ├── pointers.cpp ├── pointers.hpp ├── resources.rc ├── rorr │ ├── gm │ │ ├── CCode.hpp │ │ ├── CHashMap.hpp │ │ ├── CInstance.cpp │ │ ├── CInstance.hpp │ │ ├── CInstance_hooks.hpp │ │ ├── CRoom.hpp │ │ ├── CScript.hpp │ │ ├── CScriptRef.hpp │ │ ├── Code_Execute.hpp │ │ ├── Code_Execute_hook.hpp │ │ ├── Code_Execute_trace.hpp │ │ ├── Code_Function_GET_the_function.hpp │ │ ├── Code_Function_GET_the_function_t.hpp │ │ ├── EJSRetValBool.hpp │ │ ├── EVariableType.hpp │ │ ├── GetSaveFileName_hook.hpp │ │ ├── GetSaveFileName_t.hpp │ │ ├── MemoryManager.hpp │ │ ├── MurMurHash.cpp │ │ ├── MurMurHash.hpp │ │ ├── RToken.hpp │ │ ├── RValue.cpp │ │ ├── RValue.hpp │ │ ├── RVariableRoutine.hpp │ │ ├── Script_Data.hpp │ │ ├── StructCreate.hpp │ │ ├── VMBuffer.hpp │ │ ├── VMExec.hpp │ │ ├── Variable_BuiltIn.hpp │ │ ├── YYGMLException.hpp │ │ ├── YYGMLFuncs.hpp │ │ ├── YYObjectBase.hpp │ │ ├── YYSetScriptRef.hpp │ │ ├── YYShader.cpp │ │ ├── YYShader.hpp │ │ ├── debug_console.hpp │ │ ├── inputs.hpp │ │ ├── pin_map.hpp │ │ ├── save_file_serialize_hook.hpp │ │ └── save_file_serialize_t.hpp │ ├── rorr_hooks.hpp │ ├── rorr_pointers.hpp │ └── rorr_pointers_layout_info.hpp ├── version.cpp.in └── version.hpp └── thunderstore ├── icon.png └── thunderstore.toml /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -4 3 | AlignAfterOpenBracket: Align 4 | AlignArrayOfStructures: None 5 | AlignConsecutiveAssignments: 6 | Enabled: true 7 | AcrossEmptyLines: false 8 | AcrossComments: false 9 | AlignCompound: true 10 | PadOperators: true 11 | AlignConsecutiveBitFields: 12 | Enabled: true 13 | AcrossEmptyLines: true 14 | AcrossComments: true 15 | AlignCompound: true 16 | PadOperators: true 17 | AlignConsecutiveDeclarations: 18 | Enabled: false 19 | AlignConsecutiveMacros: 20 | Enabled: true 21 | AlignConsecutiveShortCaseStatements: 22 | Enabled: true 23 | AcrossEmptyLines: false 24 | AcrossComments: false 25 | AlignCaseColons: false 26 | AlignEscapedNewlines: Left 27 | AlignOperands: Align 28 | AlignTrailingComments: 29 | Kind: Always 30 | AllowAllArgumentsOnNextLine: false 31 | AllowAllParametersOfDeclarationOnNextLine: false 32 | AllowShortBlocksOnASingleLine: Never 33 | AllowShortCaseLabelsOnASingleLine: true 34 | AllowShortEnumsOnASingleLine: false 35 | AllowShortFunctionsOnASingleLine: None 36 | AllowShortIfStatementsOnASingleLine: Never 37 | AllowShortLambdasOnASingleLine: None 38 | AllowShortLoopsOnASingleLine: false 39 | AlwaysBreakAfterReturnType: None 40 | AlwaysBreakBeforeMultilineStrings: false 41 | AlwaysBreakTemplateDeclarations: Yes 42 | BinPackArguments: false 43 | BinPackParameters: false 44 | BitFieldColonSpacing: Both 45 | BreakAfterAttributes: Leave 46 | BreakBeforeBinaryOperators: NonAssignment 47 | BreakBeforeBraces: Allman 48 | BreakBeforeConceptDeclarations: Always 49 | BreakConstructorInitializers: AfterColon 50 | BreakStringLiterals: true 51 | ColumnLimit: 120 52 | CompactNamespaces: false 53 | ConstructorInitializerIndentWidth: 4 54 | TabWidth: 4 55 | UseTab: ForIndentation 56 | SpacesInSquareBrackets: false 57 | SpaceBeforeParens: ControlStatements 58 | SpaceBeforeJsonColon: false 59 | BreakInheritanceList: AfterColon 60 | BreakBeforeTernaryOperators: false 61 | ContinuationIndentWidth: 4 62 | Cpp11BracedListStyle: true 63 | DerivePointerAlignment: true 64 | EmptyLineAfterAccessModifier: Leave 65 | EmptyLineBeforeAccessModifier: Always 66 | FixNamespaceComments: true 67 | IncludeBlocks: Regroup 68 | IndentAccessModifiers: false 69 | IndentCaseBlocks: false 70 | IndentCaseLabels: false 71 | IndentExternBlock: Indent 72 | IndentPPDirectives: BeforeHash 73 | IndentRequiresClause: true 74 | IndentWidth: 4 75 | IndentWrappedFunctionNames: true 76 | InsertBraces: true 77 | InsertNewlineAtEOF: true 78 | IntegerLiteralSeparator: 79 | Hex: 2 80 | HexMinDigits: 2 81 | DecimalMinDigits: 5 82 | Decimal: 3 83 | BinaryMinDigits: 4 84 | Binary: 2 85 | KeepEmptyLinesAtTheStartOfBlocks: false 86 | LambdaBodyIndentation: Signature 87 | Language: Cpp 88 | MaxEmptyLinesToKeep: 2 89 | NamespaceIndentation: All 90 | PackConstructorInitializers: Never 91 | PenaltyReturnTypeOnItsOwnLine: 0 92 | PenaltyExcessCharacter: 0 93 | PointerAlignment: Left 94 | QualifierAlignment: Left 95 | ReferenceAlignment: Pointer 96 | ReflowComments: false 97 | RemoveBracesLLVM: false 98 | RequiresClausePosition: OwnLine 99 | RequiresExpressionIndentation: OuterScope 100 | SeparateDefinitionBlocks: Always 101 | SortIncludes: CaseInsensitive 102 | SortUsingDeclarations: Lexicographic 103 | SpaceAfterCStyleCast: false 104 | SpaceAfterLogicalNot: false 105 | SpaceAfterTemplateKeyword: false 106 | SpaceAroundPointerQualifiers: Default 107 | SpaceBeforeInheritanceColon: true 108 | SpaceBeforeAssignmentOperators: true 109 | SpaceBeforeCaseColon: false 110 | SpaceBeforeCpp11BracedList: false 111 | SpaceBeforeCtorInitializerColon: true 112 | SpaceBeforeRangeBasedForLoopColon: true 113 | SpaceBeforeSquareBrackets: false 114 | SpacesBeforeTrailingComments: 1 115 | SpacesInAngles: Never 116 | SpacesInContainerLiterals: false 117 | SpacesInLineCommentPrefix: 118 | Minimum: 1 119 | Standard: Auto 120 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: Nightly Build 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build_nightly: 8 | runs-on: windows-latest 9 | name: Build Nightly 10 | outputs: 11 | full_sha: ${{ steps.var.outputs.full_sha }} 12 | short_sha: ${{ steps.var.outputs.short_sha }} 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Setup MSVC environment 17 | uses: ilammy/msvc-dev-cmd@v1 18 | with: 19 | arch: amd64 20 | 21 | - name: Generate CMake project 22 | run: cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo -D FINAL=YES -S. -Bbuild -G Ninja 23 | 24 | - name: Prepare 64bit release DLL 25 | shell: bash 26 | run: | 27 | set -x 28 | 29 | namespace="ReturnOfModding" 30 | mod_name="ReturnOfModding" 31 | 32 | # Get latest version number from thunderstore 33 | version_number=$(curl --compressed -s "https://thunderstore.io/c/risk-of-rain-returns/api/v1/package/" | jq --arg package_name "$namespace-$mod_name" '.[]? | select(.full_name|startswith($package_name)) | .versions[0]?.version_number' || true) 34 | 35 | # If version_number is empty, set it to "1.0.0" 36 | if [ -z "$version_number" ]; then 37 | version_number="1.0.0" 38 | fi 39 | 40 | # Remove quotes from output 41 | version_number=$(echo "$version_number" | tr -d '"') 42 | 43 | # Increment the patch version number 44 | version_number=$(echo $version_number | awk -F. -v OFS=. 'NF==1{print ++$NF}; NF>1{$NF=sprintf("%0*d", length($NF), ($NF+1)); print}') 45 | 46 | # For the FILEVERSION we want a , format 47 | version_number_comma=$(echo $version_number | tr . ,) 48 | 49 | cd src 50 | sed -i 's/FILEVERSION .*/FILEVERSION '"$version_number_comma"'/' resources.rc 51 | sed -i 's/"ProductVersion", *"[^"]*"/"ProductVersion", "'"$version_number"'"/g' resources.rc 52 | cd .. 53 | 54 | - name: Build 64bit release DLL 55 | run: | 56 | cmake --build ./build --config RelWithDebInfo --target ReturnOfModding -- 57 | 58 | - name: Upload Artifact 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: binary 62 | path: | 63 | build/version.dll 64 | build/version.pdb 65 | 66 | - name: Generate Build Info 67 | id: var 68 | run: | 69 | echo "full_sha=$(git rev-parse HEAD)" >> $env:GITHUB_OUTPUT 70 | echo "short_sha=$(git rev-parse --short HEAD)" >> $env:GITHUB_OUTPUT 71 | 72 | create_release: 73 | runs-on: ubuntu-latest 74 | name: Create Release 75 | needs: build_nightly 76 | steps: 77 | - uses: actions/checkout@v3 78 | 79 | - name: Delete Existing Release 80 | id: delete_release 81 | uses: actions/github-script@v6 82 | with: 83 | script: | 84 | const owner = context.repo.owner; 85 | const repo = context.repo.repo; 86 | const tag = "nightly"; 87 | 88 | // List all releases and find the release by tag 89 | const releases = await github.rest.repos.listReleases({ 90 | owner: owner, 91 | repo: repo, 92 | }); 93 | 94 | const release = releases.data.find(release => release.tag_name === tag); 95 | 96 | // Check if the release exists and delete it 97 | if (release) { 98 | await github.rest.repos.deleteRelease({ 99 | owner: owner, 100 | repo: repo, 101 | release_id: release.id, 102 | }); 103 | console.log(`Deleted release with ID ${release.id}`); 104 | } else { 105 | console.log("No existing release to delete"); 106 | } 107 | 108 | // Delete the tag 109 | try { 110 | await github.rest.git.deleteRef({ 111 | owner: owner, 112 | repo: repo, 113 | ref: `tags/${tag}`, 114 | }); 115 | console.log(`Deleted tag ${tag}`); 116 | } catch (error) { 117 | console.error(`Error deleting tag: ${error.message}`); 118 | } 119 | 120 | - name: Download Artifact 121 | uses: actions/download-artifact@v4 122 | with: 123 | name: binary 124 | 125 | - name: Echo build sha256 126 | id: build_sha 127 | run: | 128 | sha256sum version.dll > sha256.checksum 129 | echo "build_sha=$(cat sha256.checksum)" >> $GITHUB_OUTPUT 130 | cat sha256.checksum 131 | 132 | - name: Nightly Release 133 | uses: softprops/action-gh-release@v1 134 | with: 135 | name: Nightly [${{ needs.build_nightly.outputs.short_sha }}] 136 | tag_name: nightly 137 | body: | 138 | **This release has been built by Github Actions** 139 | [Link to build](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) 140 | 141 | Build SHA256: 142 | ``` 143 | ${{ steps.build_sha.outputs.build_sha }} 144 | ``` 145 | To verify the build SHA256 during the action, click the build link, go-to "Create Release", open the Echo build sha256 step and read the sha256. 146 | 147 | You can download the build artifacts, generate a SHA256 checksum and compare it with the below binary. 148 | Build artifacts ARE NOT automatically the same as release assets since release assets can be modified afterwards. 149 | 150 | Full Commit Hash: 151 | ``` 152 | ${{ needs.build_nightly.outputs.full_sha }} 153 | ``` 154 | files: | 155 | version.dll 156 | 157 | - name: Setup dotnet 158 | uses: actions/setup-dotnet@v3 159 | with: 160 | dotnet-version: 7.0.x 161 | 162 | - name: Setup TCLI 163 | run: dotnet tool install --global tcli 164 | 165 | - name: Thunderstore Release 166 | run: | 167 | set -x 168 | 169 | namespace="ReturnOfModding" 170 | mod_name="ReturnOfModding" 171 | 172 | # Get latest version number from thunderstore 173 | version_number=$(curl --compressed -s "https://thunderstore.io/c/risk-of-rain-returns/api/v1/package/" | jq --arg package_name "$namespace-$mod_name" '.[]? | select(.full_name|startswith($package_name)) | .versions[0]?.version_number' || true) 174 | 175 | # If version_number is empty, set it to "1.0.0" 176 | if [ -z "$version_number" ]; then 177 | version_number="1.0.0" 178 | fi 179 | 180 | # Remove quotes from output 181 | version_number=$(echo "$version_number" | tr -d '"') 182 | 183 | # Increment the patch version number 184 | version_number=$(echo $version_number | awk -F. -v OFS=. 'NF==1{print ++$NF}; NF>1{$NF=sprintf("%0*d", length($NF), ($NF+1)); print}') 185 | 186 | cd thunderstore 187 | sed -i 's/versionNumber = ".*"/versionNumber = "'"$version_number"'"/' thunderstore.toml 188 | 189 | tcli publish --token ${{ secrets.TCLI_AUTH_TOKEN }} 190 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE 2 | .vs/ 3 | .vscode/* 4 | !.vscode/launch.json 5 | .cache/ 6 | 7 | # output directory 8 | build/ 9 | out/ 10 | __pycache__/ 11 | 12 | # precompiled headers 13 | *.ipch 14 | *.gch 15 | *.pch 16 | 17 | # generated by CMAKE 18 | version.cpp 19 | 20 | node_modules -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") 4 | 5 | project(ReturnOfModding CXX C ASM_MASM) 6 | 7 | set(SRC_DIR "${PROJECT_SOURCE_DIR}/src") 8 | 9 | # Fetch modules 10 | message("\nFetching modules") 11 | include(cmake_scripts/git.cmake) 12 | include(cmake_scripts/rom.cmake) 13 | 14 | message(STATUS "ReturnOfModding") 15 | file(GLOB_RECURSE SRC_MAIN 16 | "${SRC_DIR}/**.hpp" 17 | "${SRC_DIR}/**.h" 18 | "${SRC_DIR}/**.cpp" 19 | "${SRC_DIR}/**.cc" 20 | "${SRC_DIR}/**.cxx" 21 | "${SRC_DIR}/**.asm" 22 | "${SRC_DIR}/**.def" 23 | "${SRC_DIR}/**.rc" 24 | ) 25 | 26 | add_compile_options(/bigobj) 27 | add_compile_options("$<$:/utf-8>") 28 | add_compile_options("$<$:/utf-8>") 29 | 30 | if (FINAL) 31 | add_compile_definitions(FINAL) 32 | endif() 33 | 34 | add_library(ReturnOfModding MODULE "${SRC_MAIN}") 35 | 36 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 37 | set_property(TARGET ReturnOfModding PROPERTY CXX_STANDARD 23) 38 | 39 | source_group(TREE ${SRC_DIR} PREFIX "src" FILES ${SRC_MAIN}) 40 | 41 | target_include_directories(ReturnOfModding PRIVATE 42 | "${SRC_DIR}" 43 | ) 44 | 45 | target_precompile_headers(ReturnOfModding PRIVATE "${SRC_DIR}/common.hpp") 46 | 47 | target_link_libraries(ReturnOfModding PRIVATE ReturnOfModdingBase) 48 | 49 | # Warnings as errors 50 | set_property(TARGET ReturnOfModding PROPERTY COMPILE_WARNING_AS_ERROR ON) 51 | 52 | add_compile_definitions(ReturnOfModding 53 | "_CRT_SECURE_NO_WARNINGS" 54 | "NOMINMAX" 55 | "WIN32_LEAN_AND_MEAN" 56 | "IMGUI_USER_CONFIG=\"${PROJECT_SOURCE_DIR}/src/gui/imgui_config.hpp\"" 57 | ) 58 | 59 | if (MSVC) 60 | if (FINAL) 61 | # Aggresive inlining (Release) 62 | string(REPLACE "Ob2" "Ob3" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") 63 | # Aggresive inlining (RelWithDebInfo) 64 | string(REPLACE "Ob1" "Ob3" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") 65 | # Enable intrinsics 66 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Oi") 67 | # Favor fast code 68 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Ot") 69 | # -ffast-math (fused multiply-add if the arch allows) 70 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:fast") 71 | # Whole program optimization 72 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GL") 73 | # Function-level linking 74 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Gy") 75 | # Disable Buffer Security Check 76 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GS-") 77 | # Package global data in COMDAT sections for optimization. 78 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Gw") 79 | 80 | # For all objects: 81 | # - strip unused functions 82 | # - fold identical functions 83 | # - link-time code generation 84 | string(REPLACE "INCREMENTAL" "INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") 85 | string(REPLACE "INCREMENTAL" "INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") 86 | string(REPLACE "INCREMENTAL" "INCREMENTAL:NO" CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO}") 87 | set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /OPT:ICF,REF /LTCG") 88 | set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /OPT:ICF,REF /LTCG") 89 | set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO} /OPT:ICF,REF /LTCG") 90 | 91 | set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /PDBALTPATH:version.pdb") 92 | set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /PDBALTPATH:version.pdb") 93 | set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO} /PDBALTPATH:version.pdb") 94 | endif() 95 | endif() 96 | 97 | set_target_properties(ReturnOfModding PROPERTIES OUTPUT_NAME "version") 98 | -------------------------------------------------------------------------------- /CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "x64-Release-FastCompile", 5 | "generator": "Ninja", 6 | "configurationType": "RelWithDebInfo", 7 | "inheritEnvironments": [ "msvc_x64_x64" ], 8 | "buildRoot": "${projectDir}\\out\\build\\${name}", 9 | "installRoot": "${projectDir}\\out\\install\\${name}", 10 | "cmakeCommandArgs": "", 11 | "buildCommandArgs": "", 12 | "ctestCommandArgs": "" 13 | }, 14 | { 15 | "name": "x64-Release-FINAL", 16 | "generator": "Ninja", 17 | "configurationType": "RelWithDebInfo", 18 | "inheritEnvironments": [ "msvc_x64_x64" ], 19 | "buildRoot": "${projectDir}\\out\\build\\${name}", 20 | "installRoot": "${projectDir}\\out\\install\\${name}", 21 | "cmakeCommandArgs": "", 22 | "buildCommandArgs": "", 23 | "ctestCommandArgs": "", 24 | "variables": [ 25 | { 26 | "name": "FINAL", 27 | "value": "YES", 28 | "type": "BOOL" 29 | } 30 | ] 31 | }, 32 | { 33 | "name": "x64-Debug", 34 | "generator": "Ninja", 35 | "configurationType": "Debug", 36 | "buildRoot": "${projectDir}\\out\\build\\${name}", 37 | "installRoot": "${projectDir}\\out\\install\\${name}", 38 | "cmakeCommandArgs": "", 39 | "buildCommandArgs": "", 40 | "ctestCommandArgs": "", 41 | "inheritEnvironments": [ "msvc_x64_x64" ], 42 | "variables": [] 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Return Of Modding 2 | 3 | [Risk of Rain Returns Modding Discord](https://discord.gg/VjS57cszMq) 4 | 5 | --- 6 | 7 | Return Of Modding is a modding plugin / framework for Risk of Rain Returns. 8 | 9 | (A game made with GameMaker 2023.6 ultimately transpiled from GML to C++ with the GameMaker YYC compiler) 10 | 11 | It's using [ReturnOfModding](https://github.com/xiaoxiao921/ReturnOfModdingBase) as a base. You can check its README for more information on how it works. 12 | 13 | ## Mod Manager Installation 14 | 15 | - [Follow the instructions here.](https://github.com/ebkr/r2modmanPlus?tab=readme-ov-file#first-time-installing) 16 | 17 | ## Manual Installation 18 | 19 | - Place the main ReturnOfModding file, called `version.dll`, next to the game executable called `Risk of Rain Returns.exe` inside the game folder. 20 | 21 | - To uninstall the mod loader or revert to a vanilla experience without mods, you can simply rename or delete the `version.dll` file. 22 | 23 | ## Credits 24 | 25 | This project wouldn't have been possible without 26 | 27 | - [Archie-osu](https://github.com/Archie-osu) [with their YYToolkit project](https://github.com/AurieFramework/YYToolkit) 28 | - [ModShovel](https://github.com/nkrapivin/modshovel) 29 | - People from the Modding Discord with their feedback. 30 | -------------------------------------------------------------------------------- /cmake_scripts/git.cmake: -------------------------------------------------------------------------------- 1 | find_package(Git) 2 | if(Git_FOUND) 3 | message("Git found: ${GIT_EXECUTABLE}") 4 | 5 | # the commit's SHA1, and whether the building workspace was dirty or not 6 | execute_process(COMMAND 7 | "${GIT_EXECUTABLE}" describe --match=NeVeRmAtCh --always --abbrev=40 --dirty 8 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 9 | OUTPUT_VARIABLE GIT_SHA1 10 | ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) 11 | 12 | # the date of the commit 13 | execute_process(COMMAND 14 | "${GIT_EXECUTABLE}" log -1 --format=%ad --date=local 15 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 16 | OUTPUT_VARIABLE GIT_DATE 17 | ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) 18 | 19 | # the subject of the commit 20 | execute_process(COMMAND 21 | "${GIT_EXECUTABLE}" log -1 --format=%s 22 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 23 | OUTPUT_VARIABLE GIT_COMMIT_SUBJECT 24 | ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) 25 | 26 | # Commit messages may have quotes in them, which can affect the const char* variable. 27 | string(REPLACE "\"" "\\\"" GIT_COMMIT_SUBJECT "${GIT_COMMIT_SUBJECT}") 28 | 29 | # branch name 30 | execute_process(COMMAND 31 | "${GIT_EXECUTABLE}" branch --show-current 32 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 33 | OUTPUT_VARIABLE GIT_BRANCH 34 | ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) 35 | 36 | # generate version.cpp 37 | configure_file("${SRC_DIR}/version.cpp.in" "${SRC_DIR}/version.cpp" @ONLY) 38 | endif() -------------------------------------------------------------------------------- /cmake_scripts/rom.cmake: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | 3 | set(LUA_USE_LUAJIT false) 4 | set(LUA_GIT_HASH 5d708c3f9cae12820e415d4f89c9eacbe2ab964b) # https://github.com/lua/lua/releases/tag/v5.4.4 5 | 6 | FetchContent_Declare( 7 | rom 8 | GIT_REPOSITORY https://github.com/xiaoxiao921/ReturnOfModdingBase.git 9 | GIT_TAG 4e66bfbb444ad552441fcf34c638903baf97fdbe 10 | ) 11 | FetchContent_MakeAvailable(rom) 12 | -------------------------------------------------------------------------------- /docs/lua/classes/CCode.md: -------------------------------------------------------------------------------- 1 | # Class: CCode 2 | 3 | Class representing a game function 4 | 5 | ## Fields (2) 6 | 7 | ### `index` 8 | 9 | Index within the internal GM game functions table 10 | 11 | - Type: `number` 12 | 13 | ### `name` 14 | 15 | Name of the game function 16 | 17 | - Type: `string` 18 | 19 | -------------------------------------------------------------------------------- /docs/lua/classes/CInstance.md: -------------------------------------------------------------------------------- 1 | # Class: CInstance 2 | 3 | Class representing a game maker object instance. 4 | 5 | You can use most if not all of the builtin game maker variables (For example `myCInstance.x`) [listed here](https://manual.gamemaker.io/monthly/en/GameMaker_Language/GML_Reference/Asset_Management/Instances/Instance_Variables/Instance_Variables.htm). 6 | 7 | To know the specific instance variables of a given object defined by the game call dump_vars() on the instance 8 | 9 | ## Fields (31) 10 | 11 | ### `id` 12 | 13 | - Type: `number` 14 | 15 | ### `object_index` 16 | 17 | - Type: `number` 18 | 19 | ### `sprite_index` 20 | 21 | - Type: `number` 22 | 23 | ### `image_index` 24 | 25 | - Type: `number` 26 | 27 | ### `image_speed` 28 | 29 | - Type: `number` 30 | 31 | ### `image_xscale` 32 | 33 | - Type: `number` 34 | 35 | ### `image_yscale` 36 | 37 | - Type: `number` 38 | 39 | ### `image_angle` 40 | 41 | - Type: `number` 42 | 43 | ### `image_alpha` 44 | 45 | - Type: `number` 46 | 47 | ### `image_blend` 48 | 49 | - Type: `number` 50 | 51 | ### `x` 52 | 53 | - Type: `number` 54 | 55 | ### `y` 56 | 57 | - Type: `number` 58 | 59 | ### `xstart` 60 | 61 | - Type: `number` 62 | 63 | ### `ystart` 64 | 65 | - Type: `number` 66 | 67 | ### `xprevious` 68 | 69 | - Type: `number` 70 | 71 | ### `yprevious` 72 | 73 | - Type: `number` 74 | 75 | ### `direction` 76 | 77 | - Type: `number` 78 | 79 | ### `speed` 80 | 81 | - Type: `number` 82 | 83 | ### `friction` 84 | 85 | - Type: `number` 86 | 87 | ### `gravity_direction` 88 | 89 | - Type: `number` 90 | 91 | ### `gravity` 92 | 93 | - Type: `number` 94 | 95 | ### `hspeed` 96 | 97 | - Type: `number` 98 | 99 | ### `vspeed` 100 | 101 | - Type: `number` 102 | 103 | ### `bbox` 104 | 105 | - Type: `number[4] array` 106 | 107 | ### `timer` 108 | 109 | - Type: `number[12] array` 110 | 111 | ### `layer` 112 | 113 | - Type: `number` 114 | 115 | ### `mask_index` 116 | 117 | - Type: `number` 118 | 119 | ### `m_nMouseOver` 120 | 121 | - Type: `number` 122 | 123 | ### `depth` 124 | 125 | - Type: `number` 126 | 127 | ### `i_currentdepth` 128 | 129 | - Type: `number` 130 | 131 | ### `object_name` 132 | 133 | - Type: `string` 134 | 135 | -------------------------------------------------------------------------------- /docs/lua/classes/CScriptRef.md: -------------------------------------------------------------------------------- 1 | # Class: CScriptRef 2 | 3 | Class representing a game maker script reference. 4 | 5 | Can be called by having an instance and doing `someScriptRefInstance(self, other, someExtraArg)`. 6 | 7 | Atleast 2 args 'self' and 'other' game maker instances / structs need to be passed when calling the script. 8 | 9 | lua nil can also be passed if needed for those two args. 10 | 11 | Can also be hooked with a pre / post script hook. The `gml_Script_` prefix may need to be removed for the hook to work. Use the `script_name` field to retrieve the name. 12 | 13 | -------------------------------------------------------------------------------- /docs/lua/classes/RValue.md: -------------------------------------------------------------------------------- 1 | # Class: RValue 2 | 3 | Class representing a value coming from the game maker engine 4 | 5 | ## Fields (3) 6 | 7 | ### `type` 8 | 9 | - Type: `RValueType` 10 | 11 | ### `value` 12 | 13 | - Type: `The actual value behind the RValue, or RValue if the type is not handled yet.` 14 | 15 | ### `tostring` 16 | 17 | - Type: `string representation of the RValue` 18 | 19 | ## Constructors (3) 20 | 21 | ### `new(value)` 22 | 23 | Returns an RValue instance 24 | 25 | - **Parameters:** 26 | - `value` (boolean): value 27 | 28 | **Example Usage:** 29 | ```lua 30 | myInstance = RValue:new(value) 31 | ``` 32 | 33 | ### `new(value)` 34 | 35 | Returns an RValue instance 36 | 37 | - **Parameters:** 38 | - `value` (number): value 39 | 40 | **Example Usage:** 41 | ```lua 42 | myInstance = RValue:new(value) 43 | ``` 44 | 45 | ### `new(value)` 46 | 47 | Returns an RValue instance 48 | 49 | - **Parameters:** 50 | - `value` (string): value 51 | 52 | **Example Usage:** 53 | ```lua 54 | myInstance = RValue:new(value) 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /docs/lua/classes/RefDynamicArrayOfRValue.md: -------------------------------------------------------------------------------- 1 | # Class: RefDynamicArrayOfRValue 2 | 3 | Class representing a game maker RValue array 4 | 5 | -------------------------------------------------------------------------------- /docs/lua/classes/YYObjectBase.md: -------------------------------------------------------------------------------- 1 | # Class: YYObjectBase 2 | 3 | Class representing an object coming from the game maker engine 4 | 5 | ## Fields (3) 6 | 7 | ### `type` 8 | 9 | - Type: `YYObjectBaseType` 10 | 11 | ### `cinstance` 12 | 13 | - Type: `CInstance or nil if not a CInstance` 14 | 15 | ### `script_name` 16 | 17 | Can be used to then hook the function with a pre / post script hook. The `gml_Script_` prefix may need to be removed for the hook to work. 18 | 19 | - Type: `string or nil if not a SCRIPTREF` 20 | 21 | -------------------------------------------------------------------------------- /docs/lua/classes/config.config_definition.md: -------------------------------------------------------------------------------- 1 | # Class: config.config_definition 2 | 3 | Section and key of a setting. 4 | 5 | ## Fields (2) 6 | 7 | ### `section` 8 | 9 | Group of the setting. All settings within a config file are grouped by this. 10 | 11 | - Type: `string` 12 | 13 | ### `key` 14 | 15 | Name of the setting. 16 | 17 | - Type: `string` 18 | 19 | -------------------------------------------------------------------------------- /docs/lua/classes/config.config_entry.md: -------------------------------------------------------------------------------- 1 | # Class: config.config_entry 2 | 3 | Provides access to a single setting inside of a config_file. 4 | 5 | ## Fields (1) 6 | 7 | ### `description` 8 | 9 | Simple description of the setting shown to the user. 10 | 11 | - Type: `string` 12 | 13 | ## Functions (2) 14 | 15 | ### `get()` 16 | 17 | - **Returns:** 18 | - `boolean|number|string`: Value of this setting 19 | 20 | **Example Usage:** 21 | ```lua 22 | boolean|number|string = config.config_entry:get() 23 | ``` 24 | 25 | ### `set(boolean|number|string)` 26 | 27 | - **Parameters:** 28 | - `boolean|number|string` (New value of this setting.) 29 | 30 | **Example Usage:** 31 | ```lua 32 | config.config_entry:set(boolean|number|string) 33 | ``` 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/lua/classes/config.config_file.md: -------------------------------------------------------------------------------- 1 | # Class: config.config_file 2 | 3 | A helper class to handle persistent data. 4 | 5 | ## Fields (3) 6 | 7 | ### `owner_guid` 8 | 9 | The owner GUID of this config file. 10 | 11 | - Type: `string` 12 | 13 | ### `config_file_path` 14 | 15 | The file path of this config file. 16 | 17 | - Type: `string` 18 | 19 | ### `entries` 20 | 21 | All config entries of the config file. 22 | 23 | - Type: `table` 24 | 25 | ## Constructors (1) 26 | 27 | ### `new(config_path, save_on_init)` 28 | 29 | Create a new config file at the specified config path. 30 | 31 | - **Parameters:** 32 | - `config_path` (string): Full path to a file that contains settings. The file will be created as needed. It's recommended to use `.cfg` as the file extension. The mod manager will pick it up and make it show nicely inside the mod manager UI. 33 | - `save_on_init` (boolean): If the config file/directory doesn't exist, create it immediately. 34 | 35 | **Example Usage:** 36 | ```lua 37 | myInstance = config.config_file:new(config_path, save_on_init) 38 | ``` 39 | 40 | ## Functions (4) 41 | 42 | ### `bind(section, key, default_value, description)` 43 | 44 | Create a new setting. The setting is saved to drive and loaded automatically. 45 | Each section and key pair can be used to add only one setting, 46 | trying to add a second setting will throw an exception. 47 | 48 | - **Parameters:** 49 | - `section` (string): Section/category/group of the setting. Settings are grouped by this. 50 | - `key` (string): Name of the setting. 51 | - `default_value` (boolean|number|string): Value of the setting if the setting was not created yet. 52 | - `description` (string): Simple description of the setting shown to the user. 53 | 54 | - **Returns:** 55 | - `config.config_entry`: new config_entry object. 56 | 57 | **Example Usage:** 58 | ```lua 59 | config.config_entry = config.config_file:bind(section, key, default_value, description) 60 | ``` 61 | 62 | ### `remove(section, key)` 63 | 64 | Removes a setting from the config file. 65 | 66 | - **Parameters:** 67 | - `section` (string): Section/category/group of the setting. Settings are grouped by this. 68 | - `key` (string): Name of the setting. 69 | 70 | **Example Usage:** 71 | ```lua 72 | config.config_file:remove(section, key) 73 | ``` 74 | 75 | ### `save()` 76 | 77 | Writes the config to disk. 78 | 79 | **Example Usage:** 80 | ```lua 81 | config.config_file:save() 82 | ``` 83 | 84 | ### `reload()` 85 | 86 | Reloads the config from disk. Unsaved changes are lost. 87 | 88 | **Example Usage:** 89 | ```lua 90 | config.config_file:reload() 91 | ``` 92 | 93 | 94 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/CCode.lua: -------------------------------------------------------------------------------- 1 | ---@meta CCode 2 | 3 | -- Class representing a game function 4 | ---@class (exact) CCode 5 | ---@field index number # Index within the internal GM game functions table 6 | ---@field name string # Name of the game function 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/CInstance.lua: -------------------------------------------------------------------------------- 1 | ---@meta CInstance 2 | 3 | -- Class representing a game maker object instance. 4 | -- 5 | --You can use most if not all of the builtin game maker variables (For example `myCInstance.x`) [listed here](https://manual.gamemaker.io/monthly/en/GameMaker_Language/GML_Reference/Asset_Management/Instances/Instance_Variables/Instance_Variables.htm). 6 | -- 7 | --To know the specific instance variables of a given object defined by the game call dump_vars() on the instance 8 | ---@class (exact) CInstance 9 | ---@field id number 10 | ---@field object_index number 11 | ---@field sprite_index number 12 | ---@field image_index number 13 | ---@field image_speed number 14 | ---@field image_xscale number 15 | ---@field image_yscale number 16 | ---@field image_angle number 17 | ---@field image_alpha number 18 | ---@field image_blend number 19 | ---@field x number 20 | ---@field y number 21 | ---@field xstart number 22 | ---@field ystart number 23 | ---@field xprevious number 24 | ---@field yprevious number 25 | ---@field direction number 26 | ---@field speed number 27 | ---@field friction number 28 | ---@field gravity_direction number 29 | ---@field gravity number 30 | ---@field hspeed number 31 | ---@field vspeed number 32 | ---@field bbox number[4] array 33 | ---@field timer number[12] array 34 | ---@field layer number 35 | ---@field mask_index number 36 | ---@field m_nMouseOver number 37 | ---@field depth number 38 | ---@field i_currentdepth number 39 | ---@field object_name string 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/CScriptRef.lua: -------------------------------------------------------------------------------- 1 | ---@meta CScriptRef 2 | 3 | -- Class representing a game maker script reference. 4 | -- 5 | --Can be called by having an instance and doing `someScriptRefInstance(self, other, someExtraArg)`. 6 | -- 7 | --Atleast 2 args 'self' and 'other' game maker instances / structs need to be passed when calling the script. 8 | -- 9 | --lua nil can also be passed if needed for those two args. 10 | -- 11 | --Can also be hooked with a pre / post script hook. The `gml_Script_` prefix may need to be removed for the hook to work. Use the `script_name` field to retrieve the name. 12 | ---@class (exact) CScriptRef 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/RValue.lua: -------------------------------------------------------------------------------- 1 | ---@meta RValue 2 | 3 | -- Class representing a value coming from the game maker engine 4 | ---@class (exact) RValue 5 | ---@field type RValueType 6 | ---@field value The actual value behind the RValue, or RValue if the type is not handled yet. 7 | ---@field tostring string representation of the RValue 8 | 9 | -- Returns an RValue instance 10 | ---@param value boolean value 11 | ---@return RValue 12 | function RValue:new(value) end 13 | -- Returns an RValue instance 14 | ---@param value number value 15 | ---@return RValue 16 | function RValue:new(value) end 17 | -- Returns an RValue instance 18 | ---@param value string value 19 | ---@return RValue 20 | function RValue:new(value) end 21 | 22 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/RefDynamicArrayOfRValue.lua: -------------------------------------------------------------------------------- 1 | ---@meta RefDynamicArrayOfRValue 2 | 3 | -- Class representing a game maker RValue array 4 | ---@class (exact) RefDynamicArrayOfRValue 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/YYObjectBase.lua: -------------------------------------------------------------------------------- 1 | ---@meta YYObjectBase 2 | 3 | -- Class representing an object coming from the game maker engine 4 | ---@class (exact) YYObjectBase 5 | ---@field type YYObjectBaseType 6 | ---@field cinstance CInstance or nil if not a CInstance 7 | ---@field script_name string or nil if not a SCRIPTREF # Can be used to then hook the function with a pre / post script hook. The `gml_Script_` prefix may need to be removed for the hook to work. 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/config.config_definition.lua: -------------------------------------------------------------------------------- 1 | ---@meta config.config_definition 2 | 3 | -- Section and key of a setting. 4 | ---@class (exact) config.config_definition 5 | ---@field section string # Group of the setting. All settings within a config file are grouped by this. 6 | ---@field key string # Name of the setting. 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/config.config_entry.lua: -------------------------------------------------------------------------------- 1 | ---@meta config.config_entry 2 | 3 | -- Provides access to a single setting inside of a config_file. 4 | ---@class (exact) config.config_entry 5 | ---@field description string # Simple description of the setting shown to the user. 6 | 7 | 8 | 9 | ---@return boolean|number|string # Value of this setting 10 | function config.config_entry:get() end 11 | 12 | ---@param boolean|number|string New value of this setting. 13 | function config.config_entry:set(boolean|number|string) end 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/config.config_file.lua: -------------------------------------------------------------------------------- 1 | ---@meta config.config_file 2 | 3 | -- A helper class to handle persistent data. 4 | ---@class (exact) config.config_file 5 | ---@field owner_guid string # The owner GUID of this config file. 6 | ---@field config_file_path string # The file path of this config file. 7 | ---@field entries table # All config entries of the config file. 8 | 9 | -- Create a new config file at the specified config path. 10 | ---@param config_path string Full path to a file that contains settings. The file will be created as needed. It's recommended to use `.cfg` as the file extension. The mod manager will pick it up and make it show nicely inside the mod manager UI. 11 | ---@param save_on_init boolean If the config file/directory doesn't exist, create it immediately. 12 | ---@return config.config_file 13 | function config.config_file:new(config_path, save_on_init) end 14 | 15 | -- Create a new setting. The setting is saved to drive and loaded automatically. 16 | --Each section and key pair can be used to add only one setting, 17 | --trying to add a second setting will throw an exception. 18 | ---@param section string Section/category/group of the setting. Settings are grouped by this. 19 | ---@param key string Name of the setting. 20 | ---@param default_value boolean|number|string Value of the setting if the setting was not created yet. 21 | ---@param description string Simple description of the setting shown to the user. 22 | ---@return config.config_entry # new config_entry object. 23 | function config.config_file:bind(section, key, default_value, description) end 24 | 25 | -- Removes a setting from the config file. 26 | ---@param section string Section/category/group of the setting. Settings are grouped by this. 27 | ---@param key string Name of the setting. 28 | function config.config_file:remove(section, key) end 29 | 30 | -- Writes the config to disk. 31 | function config.config_file:save() end 32 | 33 | -- Reloads the config from disk. Unsaved changes are lost. 34 | function config.config_file:reload() end 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/lua_patch.lua: -------------------------------------------------------------------------------- 1 | ---@meta lua_patch 2 | 3 | -- Class representing a in-memory patch. 4 | ---@class (exact) lua_patch 5 | 6 | 7 | 8 | 9 | -- Apply the modified value. 10 | function lua_patch:apply() end 11 | 12 | -- Restore the original value. 13 | function lua_patch:restore() end 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/pointer.lua: -------------------------------------------------------------------------------- 1 | ---@meta pointer 2 | 3 | -- Class representing a 64-bit memory address. 4 | ---@class (exact) pointer 5 | 6 | 7 | -- Returns a memory instance, with the given address. 8 | ---@param address integer Address 9 | ---@return pointer 10 | function pointer:new(address) end 11 | 12 | -- Adds an offset to the current memory address and returns a new pointer object. 13 | ---@param offset integer offset 14 | ---@return pointer # new pointer object. 15 | function pointer:add(offset) end 16 | 17 | -- Subs an offset to the current memory address and returns a new pointer object. 18 | ---@param offset integer offset 19 | ---@return pointer # new pointer object. 20 | function pointer:sub(offset) end 21 | 22 | -- Rips the current memory address and returns a new pointer object. 23 | ---@param offset integer offset 24 | ---@return pointer # new pointer object. 25 | function pointer:rip(offset) end 26 | 27 | -- Rips (cmp instruction) the current memory address and returns a new pointer object. 28 | ---@param offset integer offset 29 | ---@return pointer # new pointer object. 30 | function pointer:rip_cmp(offset) end 31 | 32 | -- Retrieves the value stored at the memory address as the specified type. 33 | ---@return number # the value stored at the memory address as the specified type. 34 | function pointer:get_byte() end 35 | 36 | -- Retrieves the value stored at the memory address as the specified type. 37 | ---@return number # the value stored at the memory address as the specified type. 38 | function pointer:get_word() end 39 | 40 | -- Retrieves the value stored at the memory address as the specified type. 41 | ---@return number # the value stored at the memory address as the specified type. 42 | function pointer:get_dword() end 43 | 44 | -- Retrieves the value stored at the memory address as the specified type. 45 | ---@return number # the value stored at the memory address as the specified type. 46 | function pointer:get_float() end 47 | 48 | -- Retrieves the value stored at the memory address as the specified type. 49 | ---@return number # the value stored at the memory address as the specified type. 50 | function pointer:get_double() end 51 | 52 | -- Retrieves the value stored at the memory address as the specified type. 53 | ---@return number # the value stored at the memory address as the specified type. 54 | function pointer:get_qword() end 55 | 56 | -- Sets the value at the memory address to the specified value of the given type. 57 | ---@param value number new value. 58 | function pointer:set_byte(value) end 59 | 60 | -- Sets the value at the memory address to the specified value of the given type. 61 | ---@param value number new value. 62 | function pointer:set_word(value) end 63 | 64 | -- Sets the value at the memory address to the specified value of the given type. 65 | ---@param value number new value. 66 | function pointer:set_dword(value) end 67 | 68 | -- Sets the value at the memory address to the specified value of the given type. 69 | ---@param value number new value. 70 | function pointer:set_float(value) end 71 | 72 | -- Sets the value at the memory address to the specified value of the given type. 73 | ---@param value number new value. 74 | function pointer:set_double(value) end 75 | 76 | -- Sets the value at the memory address to the specified value of the given type. 77 | ---@param value number new value. 78 | function pointer:set_qword(value) end 79 | 80 | -- Retrieves the value stored at the memory address as the specified type. 81 | ---@return string # the value stored at the memory address as the specified type. 82 | function pointer:get_string() end 83 | 84 | -- Sets the value at the memory address to the specified value of the given type. 85 | ---@param value string new value. 86 | function pointer:set_string(value) end 87 | 88 | -- Creates a memory patch for modifying the value at the memory address with the specified value. 89 | --The modified value is applied when you call the apply function on the lua_patch object. 90 | --The original value is restored when you call the restore function on the lua_patch object. 91 | ---@param value number new value. 92 | ---@return lua_patch # memory patch instance for modifying the value at the memory address with the specified value. Can call apply / restore on the object. 93 | function pointer:patch_byte(value) end 94 | 95 | -- Creates a memory patch for modifying the value at the memory address with the specified value. 96 | --The modified value is applied when you call the apply function on the lua_patch object. 97 | --The original value is restored when you call the restore function on the lua_patch object. 98 | ---@param value number new value. 99 | ---@return lua_patch # memory patch instance for modifying the value at the memory address with the specified value. Can call apply / restore on the object. 100 | function pointer:patch_word(value) end 101 | 102 | -- Creates a memory patch for modifying the value at the memory address with the specified value. 103 | --The modified value is applied when you call the apply function on the lua_patch object. 104 | --The original value is restored when you call the restore function on the lua_patch object. 105 | ---@param value number new value. 106 | ---@return lua_patch # memory patch instance for modifying the value at the memory address with the specified value. Can call apply / restore on the object. 107 | function pointer:patch_dword(value) end 108 | 109 | -- Creates a memory patch for modifying the value at the memory address with the specified value. 110 | --The modified value is applied when you call the apply function on the lua_patch object. 111 | --The original value is restored when you call the restore function on the lua_patch object. 112 | ---@param value number new value. 113 | ---@return lua_patch # memory patch instance for modifying the value at the memory address with the specified value. Can call apply / restore on the object. 114 | function pointer:patch_qword(value) end 115 | 116 | -- Creates a memory patch for modifying the value at the memory address with the specified value. 117 | --The modified value is applied when you call the apply function on the lua_patch object. 118 | --The original value is restored when you call the restore function on the lua_patch object. 119 | ---@param value number new value. 120 | ---@return lua_patch # memory patch instance for modifying the value at the memory address with the specified value. Can call apply / restore on the object. 121 | function pointer:patch_float(value) end 122 | 123 | -- Creates a memory patch for modifying the value at the memory address with the specified value. 124 | --The modified value is applied when you call the apply function on the lua_patch object. 125 | --The original value is restored when you call the restore function on the lua_patch object. 126 | ---@param value number new value. 127 | ---@return lua_patch # memory patch instance for modifying the value at the memory address with the specified value. Can call apply / restore on the object. 128 | function pointer:patch_double(value) end 129 | 130 | ---@return boolean # Returns true if the address is null. 131 | function pointer:is_null() end 132 | 133 | ---@return boolean # Returns true if the address is not null. 134 | function pointer:is_valid() end 135 | 136 | -- Dereferences the memory address and returns a new pointer object pointing to the value at that address. 137 | ---@return pointer # A new pointer object pointing to the value at that address. 138 | function pointer:deref() end 139 | 140 | -- Retrieves the memory address stored in the pointer object. 141 | ---@return number # The memory address stored in the pointer object as a number. 142 | function pointer:get_address() end 143 | 144 | 145 | -------------------------------------------------------------------------------- /docs/lua/classes/definitions/value_wrapper.lua: -------------------------------------------------------------------------------- 1 | ---@meta value_wrapper 2 | 3 | -- Class for wrapping parameters and return value of functions, used mostly by the dynamic_hook system. 4 | ---@class (exact) value_wrapper 5 | 6 | 7 | 8 | 9 | -- Get the value currently contained by the wrapper. 10 | ---@return any # The current value. 11 | function value_wrapper:get() end 12 | 13 | -- Set the new value contained by the wrapper. 14 | ---@param new_value any The new value. 15 | function value_wrapper:set(new_value) end 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/lua/classes/lua_patch.md: -------------------------------------------------------------------------------- 1 | # Class: lua_patch 2 | 3 | Class representing a in-memory patch. 4 | 5 | ## Functions (2) 6 | 7 | ### `apply()` 8 | 9 | Apply the modified value. 10 | 11 | **Example Usage:** 12 | ```lua 13 | lua_patch:apply() 14 | ``` 15 | 16 | ### `restore()` 17 | 18 | Restore the original value. 19 | 20 | **Example Usage:** 21 | ```lua 22 | lua_patch:restore() 23 | ``` 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/lua/classes/value_wrapper.md: -------------------------------------------------------------------------------- 1 | # Class: value_wrapper 2 | 3 | Class for wrapping parameters and return value of functions, used mostly by the dynamic_hook system. 4 | 5 | ## Functions (2) 6 | 7 | ### `get()` 8 | 9 | Get the value currently contained by the wrapper. 10 | 11 | - **Returns:** 12 | - `any`: The current value. 13 | 14 | **Example Usage:** 15 | ```lua 16 | any = value_wrapper:get() 17 | ``` 18 | 19 | ### `set(new_value)` 20 | 21 | Set the new value contained by the wrapper. 22 | 23 | - **Parameters:** 24 | - `new_value` (any): The new value. 25 | 26 | **Example Usage:** 27 | ```lua 28 | value_wrapper:set(new_value) 29 | ``` 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/lua/tables/EVariableType.md: -------------------------------------------------------------------------------- 1 | # Table: EVariableType 2 | 3 | Table containing all possible kind / type of variable within the GM engine. 4 | 5 | ## Fields (9) 6 | 7 | ### `SELF` 8 | 9 | - Type: `SELF` 10 | 11 | ### `OTHER` 12 | 13 | - Type: `OTHER` 14 | 15 | ### `ALL` 16 | 17 | - Type: `ALL` 18 | 19 | ### `NOONE` 20 | 21 | - Type: `NOONE` 22 | 23 | ### `GLOBAL` 24 | 25 | - Type: `GLOBAL` 26 | 27 | ### `BUILTIN` 28 | 29 | - Type: `BUILTIN` 30 | 31 | ### `LOCAL` 32 | 33 | - Type: `LOCAL` 34 | 35 | ### `STACKTOP` 36 | 37 | - Type: `STACKTOP` 38 | 39 | ### `ARGUMENT` 40 | 41 | - Type: `ARGUMENT` 42 | 43 | -------------------------------------------------------------------------------- /docs/lua/tables/RValueType.md: -------------------------------------------------------------------------------- 1 | # Table: RValueType 2 | 3 | Table containing all possible types of an RValue 4 | 5 | ## Fields (17) 6 | 7 | ### `REAL` 8 | 9 | - Type: `REAL` 10 | 11 | ### `STRING` 12 | 13 | - Type: `STRING` 14 | 15 | ### `ARRAY` 16 | 17 | - Type: `ARRAY` 18 | 19 | ### `PTR` 20 | 21 | - Type: `PTR` 22 | 23 | ### `VEC3` 24 | 25 | - Type: `VEC3` 26 | 27 | ### `UNDEFINED` 28 | 29 | - Type: `UNDEFINED` 30 | 31 | ### `OBJECT` 32 | 33 | - Type: `OBJECT` 34 | 35 | ### `INT32` 36 | 37 | - Type: `INT32` 38 | 39 | ### `VEC4` 40 | 41 | - Type: `VEC4` 42 | 43 | ### `MATRIX` 44 | 45 | - Type: `MATRIX` 46 | 47 | ### `INT64` 48 | 49 | - Type: `INT64` 50 | 51 | ### `ACCESSOR` 52 | 53 | - Type: `ACCESSOR` 54 | 55 | ### `JSNULL` 56 | 57 | - Type: `JSNULL` 58 | 59 | ### `BOOL` 60 | 61 | - Type: `BOOL` 62 | 63 | ### `ITERATOR` 64 | 65 | - Type: `ITERATOR` 66 | 67 | ### `REF` 68 | 69 | - Type: `REF` 70 | 71 | ### `UNSET` 72 | 73 | - Type: `UNSET` 74 | 75 | -------------------------------------------------------------------------------- /docs/lua/tables/YYObjectBaseType.md: -------------------------------------------------------------------------------- 1 | # Table: YYObjectBaseType 2 | 3 | Table containing all possible types of an YYObjectBaseType 4 | 5 | ## Fields (19) 6 | 7 | ### `YYOBJECTBASE` 8 | 9 | - Type: `YYOBJECTBASE` 10 | 11 | ### `CINSTANCE` 12 | 13 | - Type: `CINSTANCE` 14 | 15 | ### `ACCESSOR` 16 | 17 | - Type: `ACCESSOR` 18 | 19 | ### `SCRIPTREF` 20 | 21 | - Type: `SCRIPTREF` 22 | 23 | ### `PROPERTY` 24 | 25 | - Type: `PROPERTY` 26 | 27 | ### `ARRAY` 28 | 29 | - Type: `ARRAY` 30 | 31 | ### `WEAKREF` 32 | 33 | - Type: `WEAKREF` 34 | 35 | ### `CONTAINER` 36 | 37 | - Type: `CONTAINER` 38 | 39 | ### `SEQUENCE` 40 | 41 | - Type: `SEQUENCE` 42 | 43 | ### `SEQUENCEINSTANCE` 44 | 45 | - Type: `SEQUENCEINSTANCE` 46 | 47 | ### `SEQUENCETRACK` 48 | 49 | - Type: `SEQUENCETRACK` 50 | 51 | ### `SEQUENCECURVE` 52 | 53 | - Type: `SEQUENCECURVE` 54 | 55 | ### `SEQUENCECURVECHANNEL` 56 | 57 | - Type: `SEQUENCECURVECHANNEL` 58 | 59 | ### `SEQUENCEKEYFRAMESTORE` 60 | 61 | - Type: `SEQUENCEKEYFRAMESTORE` 62 | 63 | ### `SEQUENCEKEYFRAME` 64 | 65 | - Type: `SEQUENCEKEYFRAME` 66 | 67 | ### `SEQUENCEEVALTREE` 68 | 69 | - Type: `SEQUENCEEVALTREE` 70 | 71 | ### `SEQUENCEEVALNODE` 72 | 73 | - Type: `SEQUENCEEVALNODE` 74 | 75 | ### `SEQUENCEEVENT` 76 | 77 | - Type: `SEQUENCEEVENT` 78 | 79 | ### `NINESLICE` 80 | 81 | - Type: `NINESLICE` 82 | 83 | -------------------------------------------------------------------------------- /docs/lua/tables/_ENV - Plugin Specific Global Table.md: -------------------------------------------------------------------------------- 1 | # Table: _ENV - Plugin Specific Global Table 2 | 3 | Each mod/plugin have their own global table containing helpers, such as: 4 | - Their own guid 5 | 6 | - Path to their own folder inside `config`: Used for data that must persist between sessions that can be manipulated by the user. 7 | 8 | - Path to their own folder inside `plugins_data`: Used for data that must persist between sessions but not be manipulated by the user. 9 | 10 | - Path to their own folder inside `plugins`: Location of .lua, README, manifest.json files. 11 | 12 | You can access other mods helpers through the `mods[OTHER_MOD_GUID]` table. 13 | 14 | **Example Usage:** 15 | 16 | ```lua 17 | print(_ENV._PLUGIN.guid) 18 | 19 | for n in pairs(mods[_ENV._PLUGIN.guid]) do 20 | log.info(n) 21 | end 22 | ``` 23 | 24 | ## Fields (13) 25 | 26 | ### `_PLUGIN.guid` 27 | 28 | Guid of the mod. 29 | 30 | - Type: `string` 31 | 32 | ### `_PLUGIN.version` 33 | 34 | Version of the mod. 35 | 36 | - Type: `string` 37 | 38 | ### `_PLUGIN.dependencies` 39 | 40 | Dependencies of the mod. 41 | 42 | - Type: `table` 43 | 44 | ### `_PLUGIN.dependencies_no_version_number` 45 | 46 | Dependencies of the mod without the version numbers. 47 | 48 | - Type: `table` 49 | 50 | ### `_PLUGIN.config_mod_folder_path` 51 | 52 | Path to the mod folder inside `config` 53 | 54 | - Type: `string` 55 | 56 | ### `_PLUGIN.plugins_data_mod_folder_path` 57 | 58 | Path to the mod folder inside `plugins_data` 59 | 60 | - Type: `string` 61 | 62 | ### `_PLUGIN.plugins_mod_folder_path` 63 | 64 | Path to the mod folder inside `plugins` 65 | 66 | - Type: `string` 67 | 68 | ### `_PLUGIN.this` 69 | 70 | - Type: `lua_module*` 71 | 72 | ### `!guid` 73 | 74 | Guid of the mod. 75 | 76 | - Type: `string` 77 | 78 | ### `!config_mod_folder_path` 79 | 80 | Path to the mod folder inside `config` 81 | 82 | - Type: `string` 83 | 84 | ### `!plugins_data_mod_folder_path` 85 | 86 | Path to the mod folder inside `plugins_data` 87 | 88 | - Type: `string` 89 | 90 | ### `!plugins_mod_folder_path` 91 | 92 | Path to the mod folder inside `plugins` 93 | 94 | - Type: `string` 95 | 96 | ### `!this` 97 | 98 | - Type: `lua_module*` 99 | 100 | -------------------------------------------------------------------------------- /docs/lua/tables/config.md: -------------------------------------------------------------------------------- 1 | # Table: config 2 | 3 | Table containing helpers for mod configs. 4 | 5 | ## Fields (1) 6 | 7 | ### `config_files` 8 | 9 | All currently active config_file instances. 10 | 11 | - Type: `table of config.config_file instances` 12 | 13 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/EVariableType.lua: -------------------------------------------------------------------------------- 1 | ---@meta EVariableType 2 | 3 | -- Table containing all possible kind / type of variable within the GM engine. 4 | ---@class (exact) EVariableType 5 | ---@field SELF SELF 6 | ---@field OTHER OTHER 7 | ---@field ALL ALL 8 | ---@field NOONE NOONE 9 | ---@field GLOBAL GLOBAL 10 | ---@field BUILTIN BUILTIN 11 | ---@field LOCAL LOCAL 12 | ---@field STACKTOP STACKTOP 13 | ---@field ARGUMENT ARGUMENT 14 | 15 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/RValueType.lua: -------------------------------------------------------------------------------- 1 | ---@meta RValueType 2 | 3 | -- Table containing all possible types of an RValue 4 | ---@class (exact) RValueType 5 | ---@field REAL REAL 6 | ---@field STRING STRING 7 | ---@field ARRAY ARRAY 8 | ---@field PTR PTR 9 | ---@field VEC3 VEC3 10 | ---@field UNDEFINED UNDEFINED 11 | ---@field OBJECT OBJECT 12 | ---@field INT32 INT32 13 | ---@field VEC4 VEC4 14 | ---@field MATRIX MATRIX 15 | ---@field INT64 INT64 16 | ---@field ACCESSOR ACCESSOR 17 | ---@field JSNULL JSNULL 18 | ---@field BOOL BOOL 19 | ---@field ITERATOR ITERATOR 20 | ---@field REF REF 21 | ---@field UNSET UNSET 22 | 23 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/YYObjectBaseType.lua: -------------------------------------------------------------------------------- 1 | ---@meta YYObjectBaseType 2 | 3 | -- Table containing all possible types of an YYObjectBaseType 4 | ---@class (exact) YYObjectBaseType 5 | ---@field YYOBJECTBASE YYOBJECTBASE 6 | ---@field CINSTANCE CINSTANCE 7 | ---@field ACCESSOR ACCESSOR 8 | ---@field SCRIPTREF SCRIPTREF 9 | ---@field PROPERTY PROPERTY 10 | ---@field ARRAY ARRAY 11 | ---@field WEAKREF WEAKREF 12 | ---@field CONTAINER CONTAINER 13 | ---@field SEQUENCE SEQUENCE 14 | ---@field SEQUENCEINSTANCE SEQUENCEINSTANCE 15 | ---@field SEQUENCETRACK SEQUENCETRACK 16 | ---@field SEQUENCECURVE SEQUENCECURVE 17 | ---@field SEQUENCECURVECHANNEL SEQUENCECURVECHANNEL 18 | ---@field SEQUENCEKEYFRAMESTORE SEQUENCEKEYFRAMESTORE 19 | ---@field SEQUENCEKEYFRAME SEQUENCEKEYFRAME 20 | ---@field SEQUENCEEVALTREE SEQUENCEEVALTREE 21 | ---@field SEQUENCEEVALNODE SEQUENCEEVALNODE 22 | ---@field SEQUENCEEVENT SEQUENCEEVENT 23 | ---@field NINESLICE NINESLICE 24 | 25 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/_ENV - Plugin Specific Global Table.lua: -------------------------------------------------------------------------------- 1 | ---@meta _ENV - Plugin Specific Global Table 2 | 3 | -- Each mod/plugin have their own global table containing helpers, such as: 4 | --- Their own guid 5 | -- 6 | --- Path to their own folder inside `config`: Used for data that must persist between sessions that can be manipulated by the user. 7 | -- 8 | --- Path to their own folder inside `plugins_data`: Used for data that must persist between sessions but not be manipulated by the user. 9 | -- 10 | --- Path to their own folder inside `plugins`: Location of .lua, README, manifest.json files. 11 | -- 12 | --You can access other mods helpers through the `mods[OTHER_MOD_GUID]` table. 13 | -- 14 | --**Example Usage:** 15 | -- 16 | --```lua 17 | --print(_ENV._PLUGIN.guid) 18 | -- 19 | --for n in pairs(mods[_ENV._PLUGIN.guid]) do 20 | -- log.info(n) 21 | --end 22 | --``` 23 | ---@class (exact) _ENV - Plugin Specific Global Table 24 | ---@field _PLUGIN.guid string # Guid of the mod. 25 | ---@field _PLUGIN.version string # Version of the mod. 26 | ---@field _PLUGIN.dependencies table # Dependencies of the mod. 27 | ---@field _PLUGIN.dependencies_no_version_number table # Dependencies of the mod without the version numbers. 28 | ---@field _PLUGIN.config_mod_folder_path string # Path to the mod folder inside `config` 29 | ---@field _PLUGIN.plugins_data_mod_folder_path string # Path to the mod folder inside `plugins_data` 30 | ---@field _PLUGIN.plugins_mod_folder_path string # Path to the mod folder inside `plugins` 31 | ---@field _PLUGIN.this lua_module* 32 | ---@field !guid string # Guid of the mod. 33 | ---@field !config_mod_folder_path string # Path to the mod folder inside `config` 34 | ---@field !plugins_data_mod_folder_path string # Path to the mod folder inside `plugins_data` 35 | ---@field !plugins_mod_folder_path string # Path to the mod folder inside `plugins` 36 | ---@field !this lua_module* 37 | 38 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/config.lua: -------------------------------------------------------------------------------- 1 | ---@meta config 2 | 3 | -- Table containing helpers for mod configs. 4 | ---@class (exact) config 5 | ---@field config_files table of config.config_file instances # All currently active config_file instances. 6 | 7 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/gm.CInstance.lua: -------------------------------------------------------------------------------- 1 | ---@meta gm.CInstance 2 | 3 | ---@class (exact) gm.CInstance 4 | ---@field instances_all CInstance table of all (active or unactive) game maker object instances 5 | ---@field instances_active CInstance table of all active game maker object instances 6 | ---@field instance_id_to_CInstance table of all game maker object instances ids to their corresponding CInstance 7 | 8 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/gm.lua: -------------------------------------------------------------------------------- 1 | ---@meta gm 2 | 3 | -- Table containing helpers for interacting with the game maker engine. 4 | ---@class (exact) gm 5 | ---@field constants table of gml/game constants name to their asset index. 6 | ---@field constant_types table of gml/game constants name to their type name 7 | ---@field constants_type_sorted constants_type_sorted[type_name][i] = constant_name 8 | 9 | -- Registers a callback that will be called right before any object function is called. Note: for script functions, use pre_script_hook / post_script_hook 10 | ---@param function_name string (optional) Function name to hook. If you pass a valid name, the hook will be a lot faster to execute. Example valid function name: `gml_Object_oStartMenu_Step_2` 11 | ---@param callback function callback that match signature function ( self (CInstance), other (CInstance) ) for **fast** overload and ( self (CInstance), other (CInstance), code (CCode), result (RValue), flags (number) ) for **non fast** overload. 12 | function gm.pre_code_execute(function_name, callback) end 13 | 14 | -- Registers a callback that will be called right after any object function is called. Note: for script functions, use pre_script_hook / post_script_hook 15 | ---@param function_name string (optional) Function name to hook. If you pass a valid name, the hook will be a lot faster to execute. Example valid function name: `gml_Object_oStartMenu_Step_2` 16 | ---@param callback function callback that match signature function ( self (CInstance), other (CInstance) ) for **fast** overload and ( self (CInstance), other (CInstance), code (CCode), result (RValue), flags (number) ) for **non fast** overload. 17 | function gm.post_code_execute(function_name, callback) end 18 | 19 | -- Registers a callback that will be called right before any script function is called. Note: for object functions, use pre_code_execute / post_code_execute 20 | ---@param function_index number index of the game script / builtin game maker function to hook, for example `gm.constants.callback_execute` 21 | ---@param callback function callback that match signature function ( self (CInstance), other (CInstance), result (RValue), args (RValue array) ) -> Return true or false depending on if you want the orig method to be called. 22 | function gm.pre_script_hook(function_index, callback) end 23 | 24 | -- Registers a callback that will be called right after any script function is called. Note: for object functions, use pre_code_execute / post_code_execute 25 | ---@param function_index number index of the game script / builtin game maker function to hook, for example `gm.constants.callback_execute` 26 | ---@param callback function callback that match signature function ( self (CInstance), other (CInstance), result (RValue), args (RValue array) ) 27 | function gm.post_script_hook(function_index, callback) end 28 | 29 | ---@param name string name of the variable 30 | ---@return value # The actual value behind the RValue, or RValue if the type is not handled yet. 31 | function gm.variable_global_get(name) end 32 | 33 | ---@param name string name of the variable 34 | ---@param new_value any new value 35 | function gm.variable_global_set(name, new_value) end 36 | 37 | ---@param name string name of the function to call 38 | ---@param self CInstance (optional) 39 | ---@param other CInstance (optional) 40 | ---@param args any (optional) 41 | ---@return value # The actual value behind the RValue, or RValue if the type is not handled yet. 42 | function gm.call(name, self, other, args) end 43 | 44 | ---@return YYObjectBase* # The freshly made empty struct 45 | function gm.struct_create() end 46 | 47 | ---@param shader_name string the name of shader. 48 | ---@return value # The id of the shader. 49 | function gm.find_shader_by_name(shader_name) end 50 | 51 | ---@param file_path string the path to the shader source code (must be HLSL). 52 | ---@param name string the shader name. 53 | ---@param id int the id of the shader to replace. 54 | function gm.shader_replace(file_path, name, id) end 55 | 56 | -- **Example Usage** 57 | --```lua 58 | --local shd_test = gm.shader_add(path.combine(PATH, "shd_test"), "shd_test") 59 | --``` 60 | ---@param file_path string the path to the shader source code (must be HLSL). Check https://github.com/GameMakerDiscord/gists/blob/master/HLSL_passthrough for example. 61 | ---@param name string the shader name. 62 | ---@return value # The id of the shader. 63 | function gm.shader_add(file_path, name) end 64 | 65 | -- **Example Usage** 66 | --```lua 67 | --gm.shader_dump(1) 68 | --``` 69 | ---@param id int The id of the shader. 70 | function gm.shader_dump(id) end 71 | 72 | -- **Example Usage** 73 | --```lua 74 | --callable_ref = nil 75 | --gm.pre_script_hook(gm.constants.callable_call, function(self, other, result, args) 76 | -- if callable_ref then 77 | -- if args[1].value == callable_ref then 78 | -- print("GenericCallable ran") 79 | -- end 80 | -- end 81 | --end) 82 | -- 83 | --gm.post_code_execute("gml_Object_pAttack_Create_0", function(self, other) 84 | -- gm.instance_callback_set(self.on_hit, gm.get_script_ref(gm.constants.function_dummy)) 85 | -- callable_ref = self.on_hit.callables[#self.on_hit.callables] 86 | --end) 87 | --``` 88 | ---@param function_index number index of the game script / builtin game maker function to make a CScriptRef with. 89 | ---@return CScriptRef* # The script reference from the passed function index. 90 | function gm.get_script_ref(function_index) end 91 | 92 | -- **Example Usage** 93 | --```lua 94 | --pointer = gm.get_script_function_address(gm.constants.actor_death) 95 | --``` 96 | ---@param function_index number index of the game script / builtin game maker function. 97 | ---@return pointer # A pointer to the found address. 98 | function gm.get_script_function_address(function_index) end 99 | 100 | -- **Example Usage** 101 | --```lua 102 | --pointer = gm.get_object_function_address("gml_Object_oStartMenu_Step_2") 103 | --``` 104 | ---@param function_name string the name of target function. 105 | ---@return pointer # A pointer to the found address. 106 | function gm.get_object_function_address(function_name) end 107 | 108 | 109 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/gui.lua: -------------------------------------------------------------------------------- 1 | ---@meta gui 2 | 3 | ---@class (exact) gui 4 | 5 | -- Registers a function that will be called under your dedicated space in the imgui main menu bar. 6 | --**Example Usage:** 7 | --```lua 8 | --gui.add_to_menu_bar(function() 9 | -- if ImGui.BeginMenu("Ayo") then 10 | -- if ImGui.Button("Label") then 11 | -- log.info("hi") 12 | -- end 13 | -- ImGui.EndMenu() 14 | -- end 15 | --end) 16 | --``` 17 | ---@param imgui_rendering function Function that will be called under your dedicated space in the imgui main menu bar. 18 | function gui.add_to_menu_bar(imgui_rendering) end 19 | 20 | -- Registers a function that will be called every rendering frame, regardless of the gui is in its open state. You can call ImGui functions in it, please check the ImGui.md documentation file for more info. 21 | --**Example Usage:** 22 | --```lua 23 | --gui.add_always_draw_imgui(function() 24 | -- if ImGui.Begin("My Custom Window") then 25 | -- if ImGui.Button("Label") then 26 | -- log.info("hi") 27 | -- end 28 | -- 29 | -- end 30 | -- ImGui.End() 31 | --end) 32 | --``` 33 | ---@param imgui_rendering function Function that will be called every rendering frame, regardless of the gui is in its open state. You can call ImGui functions in it, please check the ImGui.md documentation file for more info. 34 | function gui.add_always_draw_imgui(imgui_rendering) end 35 | 36 | -- Registers a function that will be called every rendering frame, only if the gui is in its open state. You can call ImGui functions in it, please check the ImGui.md documentation file for more info. 37 | --**Example Usage:** 38 | --```lua 39 | --gui.add_imgui(function() 40 | -- if ImGui.Begin("My Custom Window") then 41 | -- if ImGui.Button("Label") then 42 | -- log.info("hi") 43 | -- end 44 | -- 45 | -- end 46 | -- ImGui.End() 47 | --end) 48 | --``` 49 | ---@param imgui_rendering function Function that will be called every rendering frame, only if the gui is in its open state. You can call ImGui functions in it, please check the ImGui.md documentation file for more info. 50 | function gui.add_imgui(imgui_rendering) end 51 | 52 | ---@return boolean # Returns true if the GUI is open. 53 | function gui.is_open() end 54 | 55 | -- Opens or closes the GUI. 56 | function gui.toggle() end 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/log.lua: -------------------------------------------------------------------------------- 1 | ---@meta log 2 | 3 | -- Table containing functions for printing to console / log file. 4 | ---@class (exact) log 5 | 6 | -- Logs an informational message. 7 | ---@param args any 8 | function log.info(args) end 9 | 10 | -- Logs a warning message. 11 | ---@param args any 12 | function log.warning(args) end 13 | 14 | -- Logs a debug message. 15 | ---@param args any 16 | function log.debug(args) end 17 | 18 | -- Logs an error message. This is a mirror of lua classic `error` function. 19 | ---@param arg any 20 | ---@param level integer 21 | function log.error(arg, level) end 22 | 23 | -- Refresh the log filters (Console and File) from the config file. 24 | function log.refresh_filters() end 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/memory.lua: -------------------------------------------------------------------------------- 1 | ---@meta memory 2 | 3 | -- Table containing helper functions related to process memory. 4 | ---@class (exact) memory 5 | 6 | -- Returns the base address of a specified module within the current process. Returns a pointer:is_null() == true pointer otherwise. 7 | ---@param module_name (optional) string The name of the module for which the base address is to be retrieved. Example: "ntdll.dll". If not provided, the API resolves this to the current targeted main module name automatically. 8 | ---@return pointer # A pointer to the found address. 9 | function memory.get_module_base_address(module_name (optional)) end 10 | 11 | -- Scans the specified memory pattern within the target main module and returns a pointer to the found address. Returns a pointer:is_null() == true pointer otherwise. 12 | ---@param module_name string module name. Example: "ntdll.dll" 13 | ---@param pattern string byte pattern (IDA format) 14 | ---@return pointer # A pointer to the found address. 15 | function memory.scan_pattern_from_module(module_name, pattern) end 16 | 17 | -- Scans the specified memory pattern within the target main module and returns a pointer to the found address. Returns a pointer:is_null() == true pointer otherwise. 18 | ---@param pattern string byte pattern (IDA format) 19 | ---@return pointer # A pointer to the found address. 20 | function memory.scan_pattern(pattern) end 21 | 22 | ---@param size integer The number of bytes to allocate on the heap. 23 | ---@return pointer # A pointer to the newly allocated memory. 24 | function memory.allocate(size) end 25 | 26 | ---@param ptr pointer The pointer that must be freed. 27 | function memory.free(ptr) end 28 | 29 | -- **Example Usage:** 30 | --```lua 31 | --local ptr = memory.scan_pattern("some ida sig") 32 | ---- Check the implementation of the asmjit::TypeId get_type_id function if you are unsure what to use for return type / parameters types 33 | --memory.dynamic_hook("test_hook", "float", {"const char*"}, ptr, 34 | --{function(ret_val, str) 35 | -- 36 | -- --str:set("replaced str") 37 | -- ret_val:set(69.69) 38 | -- log.info("pre callback from lua", ret_val:get(), str:get()) 39 | -- 40 | -- -- false for skipping the original function call 41 | -- return false 42 | --end, 43 | --function(ret_val, str) 44 | -- log.info("post callback from lua 1", ret_val:get(), str:get()) 45 | -- ret_val:set(79.69) 46 | -- log.info("post callback from lua 2", ret_val:get(), str:get()) 47 | --end}) 48 | --``` 49 | ---@param hook_name string The name of the hook. 50 | ---@param return_type string Type of the return value of the detoured function. 51 | ---@param param_types table Types of the parameters of the detoured function. 52 | ---@param target_func_ptr memory.pointer The pointer to the function to detour. 53 | ---@param callbacks table Table first element (can be nil): Pre function callback, lua function that will be called before the original function is about to be called. Pre function callback must match the following signature: ( return_value (value_wrapper), arg1 (value_wrapper), arg2 (value_wrapper), ... ) -> Returns true or false (boolean) depending on whether you want the original function to be called. Table second element (can be nil): function that will be called after the original function. Post function callback must match the following signature: ( return_value (value_wrapper), arg1 (value_wrapper), arg2 (value_wrapper), ... ) -> No return value. 54 | ---@return number # Unique identifier for later disabling / enabling the hook on the fly. 55 | function memory.dynamic_hook(hook_name, return_type, param_types, target_func_ptr, callbacks) end 56 | 57 | -- **Example Usage:** 58 | --```lua 59 | --local ptr = memory.scan_pattern("some ida sig") 60 | --gm.dynamic_hook_mid("test_hook", {"rax", "rcx", "[rcx+rdx*4+11]"}, {"int", "RValue*", "int"}, 0, ptr, function(args) 61 | -- log.info("trigger", args[1]:get(), args[2].value, args[3]:set(1)) 62 | -- return ptr:add(246) 63 | --end) 64 | --``` 65 | --But scan_pattern may be affected by the other hooks. 66 | ---@param hook_name string The name of the hook. 67 | ---@param param_captures_targets table Addresses of the parameters which you want to capture. 68 | ---@param param_captures_types table Types of the parameters which you want to capture. 69 | ---@param stack_restore_offset int An offset used to restore stack, only need when you want to customize the jump location. 70 | ---@param target_func_ptr memory.pointer The pointer to the function to detour. 71 | ---@param mid_callback function The function that will be called when the program reaches the position. The callback must match the following signature: ( args (can be a value_wrapper, or a lua usertype directly, depending if you used `add_type_info_from_string` through some c++ code and exposed it to the lua vm) ) -> Returns memory.pointer if you want to customize the jump location. Be careful when customizing the jump location, you need to restore the registers and the stack before the jump. 72 | ---@return number # Unique identifier for later disabling / enabling the hook on the fly. 73 | function memory.dynamic_hook_mid(hook_name, param_captures_targets, param_captures_types, stack_restore_offset, target_func_ptr, mid_callback) end 74 | 75 | ---@param identifier number The identifier returned by the `dynamic_hook` family functions. 76 | function memory.dynamic_hook_enable(identifier) end 77 | 78 | ---@param identifier number The identifier returned by the `dynamic_hook` family functions. 79 | function memory.dynamic_hook_disable(identifier) end 80 | 81 | -- **Example Usage:** 82 | --```lua 83 | ---- the sig in this example leads to an implementation of memcpy_s 84 | --local ptr = memory.scan_pattern("48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 49 8B D9 49 8B F0 48 8B FA") 85 | --if ptr:is_valid() then 86 | -- local dest_size = 8 87 | -- local dest_ptr = memory.allocate(dest_size) 88 | -- dest_ptr:set_qword(0) 89 | -- 90 | -- local src_size = 8 91 | -- local src_ptr = memory.allocate(src_size) 92 | -- src_ptr:set_qword(123) 93 | -- 94 | -- -- Check the implementation of the asmjit::TypeId get_type_id function if you are unsure what to use for return type / parameters types 95 | -- local func_to_call_test_global_name = memory.dynamic_call("int", {"void*", "uint64_t", "void*", "uint64_t"}, ptr) 96 | -- -- print zero. 97 | -- log.info(dest_ptr:get_qword()) 98 | -- -- note: don't pass memory.pointer objects directly when you call the function, but use get_address() instead. 99 | -- local call_res_test = _G[func_to_call_test_global_name](dest_ptr:get_address(), dest_size, src_ptr:get_address(), src_size) 100 | -- -- print 123. 101 | -- log.info(dest_ptr:get_qword()) 102 | --end 103 | --``` 104 | ---@param return_type string Type of the return value of the function to call. 105 | ---@param param_types table Types of the parameters of the function to call. 106 | ---@param target_func_ptr memory.pointer The pointer to the function to call. 107 | ---@return string # Key name of the function that you can now call from lua. 108 | function memory.dynamic_call(return_type, param_types, target_func_ptr) end 109 | 110 | -- **Example Usage:** 111 | --```lua 112 | --memory.dynamic_hook("test", "RValue*", {"CInstance*","CInstance*","RValue*","int","RValue**"}, 113 | --ptr, function (ret_val, skill, player, result, arg_num, args_ptr) 114 | -- log.info(memory.resolve_pointer_to_type(memory.get_usertype_pointer(skill), "YYObjectBase*").skill_id) 115 | -- log.info(memory.resolve_pointer_to_type(args_ptr:deref():get_address(), "RValue*").value) 116 | -- log.info(memory.resolve_pointer_to_type(args_ptr:add(8):deref():get_address(), "RValue*").value) 117 | --end) 118 | --``` 119 | ---@param target_address number The object target as a lua number. 120 | ---@param target_type string Target type (must be a pointer type). 121 | ---@return lua usertype. # 122 | function memory.resolve_pointer_to_type(target_address, target_type) end 123 | 124 | ---@param usertype_object any_usertype A lua usertype instance. 125 | ---@return number # The object address as a lua number. 126 | function memory.get_usertype_pointer(usertype_object) end 127 | 128 | 129 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/mods.lua: -------------------------------------------------------------------------------- 1 | ---@meta mods 2 | 3 | ---@class (exact) mods 4 | ---@field [Mod GUID] string # Each mod once loaded will have a key in this table, the key will be their guid string and the value their `_ENV`. 5 | 6 | ---@return table # Table containing the order in which mods are loaded by the mod loader. 7 | function mods.loading_order() end 8 | 9 | -- Registers a callback that will be called once all mods are loaded. Will be called instantly if mods are already loaded and that you are just hot-reloading your mod. 10 | ---@param callback function callback that will be called once all mods are loaded. The callback function should match signature func() 11 | function mods.on_all_mods_loaded(callback) end 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/path.lua: -------------------------------------------------------------------------------- 1 | ---@meta path 2 | 3 | -- Table containing helpers for manipulating file or directory paths 4 | ---@class (exact) path 5 | 6 | -- Combines strings into a path. 7 | ---@param path string Any amount of string is accepted. 8 | ---@return string # Returns the combined path 9 | function path.combine(path) end 10 | 11 | -- Retrieves the parent directory of the specified path, including both absolute and relative paths. 12 | ---@param path string The path for which to retrieve the parent directory. 13 | ---@return string # Returns the parent path 14 | function path.get_parent(path) end 15 | 16 | ---@param root_path string The path to the directory to search. 17 | ---@return string table # Returns the names of subdirectories under the given root_path 18 | function path.get_directories(root_path) end 19 | 20 | ---@param root_path string The path to the directory to search. 21 | ---@return string table # Returns the names of all the files under the given root_path 22 | function path.get_files(root_path) end 23 | 24 | ---@param path string The path for which to retrieve the filename. 25 | ---@return string # Returns the filename identified by the path. 26 | function path.filename(path) end 27 | 28 | ---@param path string The path for which to retrieve the stem. 29 | ---@return string # Returns the stem of the filename identified by the path (i.e. the filename without the final extension). 30 | function path.stem(path) end 31 | 32 | ---@param path string The path to the new directory to create. 33 | ---@return boolean # true if a directory was newly created for the directory p resolves to, false otherwise. 34 | function path.create_directory(path) end 35 | 36 | ---@param path string The path to check. 37 | ---@return boolean # true if the path exists, false otherwise. 38 | function path.exists(path) end 39 | 40 | -- Registers a callback that will be called when a file changes. 41 | --**Example Usage:** 42 | --```lua 43 | --path.add_file_watcher(_ENV["!config_mod_folder_path"], function (file_name, timestamp) 44 | -- log.info(file_name, timestamp) 45 | --end) 46 | --``` 47 | ---@param path string The path to add file watcher. 48 | ---@param callback function callback that match signature function ( file_name, timestamp ). 49 | function path.add_file_watcher(path, callback) end 50 | 51 | 52 | -------------------------------------------------------------------------------- /docs/lua/tables/definitions/paths.lua: -------------------------------------------------------------------------------- 1 | ---@meta paths 2 | 3 | -- Table containing helpers for retrieving project related IO file/folder paths. 4 | ---@class (exact) paths 5 | 6 | -- Used for data that must persist between sessions and that can be manipulated by the user. 7 | ---@return string # Returns the config folder path 8 | function paths.config() end 9 | 10 | -- Used for data that must persist between sessions but not be manipulated by the user. 11 | ---@return string # Returns the plugins_data folder path 12 | function paths.plugins_data() end 13 | 14 | -- Location of .lua, README, manifest.json files. 15 | ---@return string # Returns the plugins folder path 16 | function paths.plugins() end 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/lua/tables/gm.CInstance.md: -------------------------------------------------------------------------------- 1 | # Table: gm.CInstance 2 | 3 | ## Fields (3) 4 | 5 | ### `instances_all` 6 | 7 | - Type: `CInstance table of all (active or unactive) game maker object instances` 8 | 9 | ### `instances_active` 10 | 11 | - Type: `CInstance table of all active game maker object instances` 12 | 13 | ### `instance_id_to_CInstance` 14 | 15 | - Type: `table of all game maker object instances ids to their corresponding CInstance` 16 | 17 | -------------------------------------------------------------------------------- /docs/lua/tables/gm.md: -------------------------------------------------------------------------------- 1 | # Table: gm 2 | 3 | Table containing helpers for interacting with the game maker engine. 4 | 5 | ## Fields (3) 6 | 7 | ### `constants` 8 | 9 | - Type: `table of gml/game constants name to their asset index.` 10 | 11 | ### `constant_types` 12 | 13 | - Type: `table of gml/game constants name to their type name` 14 | 15 | ### `constants_type_sorted` 16 | 17 | - Type: `constants_type_sorted[type_name][i] = constant_name` 18 | 19 | ## Functions (15) 20 | 21 | ### `pre_code_execute(function_name, callback)` 22 | 23 | Registers a callback that will be called right before any object function is called. Note: for script functions, use pre_script_hook / post_script_hook 24 | 25 | - **Parameters:** 26 | - `function_name` (string (optional)): Function name to hook. If you pass a valid name, the hook will be a lot faster to execute. Example valid function name: `gml_Object_oStartMenu_Step_2` 27 | - `callback` (function): callback that match signature function ( self (CInstance), other (CInstance) ) for **fast** overload and ( self (CInstance), other (CInstance), code (CCode), result (RValue), flags (number) ) for **non fast** overload. 28 | 29 | **Example Usage:** 30 | ```lua 31 | gm.pre_code_execute(function_name, callback) 32 | ``` 33 | 34 | ### `post_code_execute(function_name, callback)` 35 | 36 | Registers a callback that will be called right after any object function is called. Note: for script functions, use pre_script_hook / post_script_hook 37 | 38 | - **Parameters:** 39 | - `function_name` (string (optional)): Function name to hook. If you pass a valid name, the hook will be a lot faster to execute. Example valid function name: `gml_Object_oStartMenu_Step_2` 40 | - `callback` (function): callback that match signature function ( self (CInstance), other (CInstance) ) for **fast** overload and ( self (CInstance), other (CInstance), code (CCode), result (RValue), flags (number) ) for **non fast** overload. 41 | 42 | **Example Usage:** 43 | ```lua 44 | gm.post_code_execute(function_name, callback) 45 | ``` 46 | 47 | ### `pre_script_hook(function_index, callback)` 48 | 49 | Registers a callback that will be called right before any script function is called. Note: for object functions, use pre_code_execute / post_code_execute 50 | 51 | - **Parameters:** 52 | - `function_index` (number): index of the game script / builtin game maker function to hook, for example `gm.constants.callback_execute` 53 | - `callback` (function): callback that match signature function ( self (CInstance), other (CInstance), result (RValue), args (RValue array) ) -> Return true or false depending on if you want the orig method to be called. 54 | 55 | **Example Usage:** 56 | ```lua 57 | gm.pre_script_hook(function_index, callback) 58 | ``` 59 | 60 | ### `post_script_hook(function_index, callback)` 61 | 62 | Registers a callback that will be called right after any script function is called. Note: for object functions, use pre_code_execute / post_code_execute 63 | 64 | - **Parameters:** 65 | - `function_index` (number): index of the game script / builtin game maker function to hook, for example `gm.constants.callback_execute` 66 | - `callback` (function): callback that match signature function ( self (CInstance), other (CInstance), result (RValue), args (RValue array) ) 67 | 68 | **Example Usage:** 69 | ```lua 70 | gm.post_script_hook(function_index, callback) 71 | ``` 72 | 73 | ### `variable_global_get(name)` 74 | 75 | - **Parameters:** 76 | - `name` (string): name of the variable 77 | 78 | - **Returns:** 79 | - `value`: The actual value behind the RValue, or RValue if the type is not handled yet. 80 | 81 | **Example Usage:** 82 | ```lua 83 | value = gm.variable_global_get(name) 84 | ``` 85 | 86 | ### `variable_global_set(name, new_value)` 87 | 88 | - **Parameters:** 89 | - `name` (string): name of the variable 90 | - `new_value` (any): new value 91 | 92 | **Example Usage:** 93 | ```lua 94 | gm.variable_global_set(name, new_value) 95 | ``` 96 | 97 | ### `call(name, self, other, args)` 98 | 99 | - **Parameters:** 100 | - `name` (string): name of the function to call 101 | - `self` (CInstance): (optional) 102 | - `other` (CInstance): (optional) 103 | - `args` (any): (optional) 104 | 105 | - **Returns:** 106 | - `value`: The actual value behind the RValue, or RValue if the type is not handled yet. 107 | 108 | **Example Usage:** 109 | ```lua 110 | value = gm.call(name, self, other, args) 111 | ``` 112 | 113 | ### `struct_create()` 114 | 115 | - **Returns:** 116 | - `YYObjectBase*`: The freshly made empty struct 117 | 118 | **Example Usage:** 119 | ```lua 120 | YYObjectBase* = gm.struct_create() 121 | ``` 122 | 123 | ### `find_shader_by_name(shader_name)` 124 | 125 | - **Parameters:** 126 | - `shader_name` (string): the name of shader. 127 | 128 | - **Returns:** 129 | - `value`: The id of the shader. 130 | 131 | **Example Usage:** 132 | ```lua 133 | value = gm.find_shader_by_name(shader_name) 134 | ``` 135 | 136 | ### `shader_replace(file_path, name, id)` 137 | 138 | - **Parameters:** 139 | - `file_path` (string): the path to the shader source code (must be HLSL). 140 | - `name` (string): the shader name. 141 | - `id` (int): the id of the shader to replace. 142 | 143 | **Example Usage:** 144 | ```lua 145 | gm.shader_replace(file_path, name, id) 146 | ``` 147 | 148 | ### `shader_add(file_path, name)` 149 | 150 | **Example Usage** 151 | ```lua 152 | local shd_test = gm.shader_add(path.combine(PATH, "shd_test"), "shd_test") 153 | ``` 154 | 155 | - **Parameters:** 156 | - `file_path` (string): the path to the shader source code (must be HLSL). Check https://github.com/GameMakerDiscord/gists/blob/master/HLSL_passthrough for example. 157 | - `name` (string): the shader name. 158 | 159 | - **Returns:** 160 | - `value`: The id of the shader. 161 | 162 | **Example Usage:** 163 | ```lua 164 | value = gm.shader_add(file_path, name) 165 | ``` 166 | 167 | ### `shader_dump(id)` 168 | 169 | **Example Usage** 170 | ```lua 171 | gm.shader_dump(1) 172 | ``` 173 | 174 | - **Parameters:** 175 | - `id` (int): The id of the shader. 176 | 177 | **Example Usage:** 178 | ```lua 179 | gm.shader_dump(id) 180 | ``` 181 | 182 | ### `get_script_ref(function_index)` 183 | 184 | **Example Usage** 185 | ```lua 186 | callable_ref = nil 187 | gm.pre_script_hook(gm.constants.callable_call, function(self, other, result, args) 188 | if callable_ref then 189 | if args[1].value == callable_ref then 190 | print("GenericCallable ran") 191 | end 192 | end 193 | end) 194 | 195 | gm.post_code_execute("gml_Object_pAttack_Create_0", function(self, other) 196 | gm.instance_callback_set(self.on_hit, gm.get_script_ref(gm.constants.function_dummy)) 197 | callable_ref = self.on_hit.callables[#self.on_hit.callables] 198 | end) 199 | ``` 200 | 201 | - **Parameters:** 202 | - `function_index` (number): index of the game script / builtin game maker function to make a CScriptRef with. 203 | 204 | - **Returns:** 205 | - `CScriptRef*`: The script reference from the passed function index. 206 | 207 | **Example Usage:** 208 | ```lua 209 | CScriptRef* = gm.get_script_ref(function_index) 210 | ``` 211 | 212 | ### `get_script_function_address(function_index)` 213 | 214 | **Example Usage** 215 | ```lua 216 | pointer = gm.get_script_function_address(gm.constants.actor_death) 217 | ``` 218 | 219 | - **Parameters:** 220 | - `function_index` (number): index of the game script / builtin game maker function. 221 | 222 | - **Returns:** 223 | - `pointer`: A pointer to the found address. 224 | 225 | **Example Usage:** 226 | ```lua 227 | pointer = gm.get_script_function_address(function_index) 228 | ``` 229 | 230 | ### `get_object_function_address(function_name)` 231 | 232 | **Example Usage** 233 | ```lua 234 | pointer = gm.get_object_function_address("gml_Object_oStartMenu_Step_2") 235 | ``` 236 | 237 | - **Parameters:** 238 | - `function_name` (string): the name of target function. 239 | 240 | - **Returns:** 241 | - `pointer`: A pointer to the found address. 242 | 243 | **Example Usage:** 244 | ```lua 245 | pointer = gm.get_object_function_address(function_name) 246 | ``` 247 | 248 | 249 | -------------------------------------------------------------------------------- /docs/lua/tables/gui.md: -------------------------------------------------------------------------------- 1 | # Table: gui 2 | 3 | ## Functions (5) 4 | 5 | ### `add_to_menu_bar(imgui_rendering)` 6 | 7 | Registers a function that will be called under your dedicated space in the imgui main menu bar. 8 | **Example Usage:** 9 | ```lua 10 | gui.add_to_menu_bar(function() 11 | if ImGui.BeginMenu("Ayo") then 12 | if ImGui.Button("Label") then 13 | log.info("hi") 14 | end 15 | ImGui.EndMenu() 16 | end 17 | end) 18 | ``` 19 | 20 | - **Parameters:** 21 | - `imgui_rendering` (function): Function that will be called under your dedicated space in the imgui main menu bar. 22 | 23 | **Example Usage:** 24 | ```lua 25 | gui.add_to_menu_bar(imgui_rendering) 26 | ``` 27 | 28 | ### `add_always_draw_imgui(imgui_rendering)` 29 | 30 | Registers a function that will be called every rendering frame, regardless of the gui is in its open state. You can call ImGui functions in it, please check the ImGui.md documentation file for more info. 31 | **Example Usage:** 32 | ```lua 33 | gui.add_always_draw_imgui(function() 34 | if ImGui.Begin("My Custom Window") then 35 | if ImGui.Button("Label") then 36 | log.info("hi") 37 | end 38 | 39 | end 40 | ImGui.End() 41 | end) 42 | ``` 43 | 44 | - **Parameters:** 45 | - `imgui_rendering` (function): Function that will be called every rendering frame, regardless of the gui is in its open state. You can call ImGui functions in it, please check the ImGui.md documentation file for more info. 46 | 47 | **Example Usage:** 48 | ```lua 49 | gui.add_always_draw_imgui(imgui_rendering) 50 | ``` 51 | 52 | ### `add_imgui(imgui_rendering)` 53 | 54 | Registers a function that will be called every rendering frame, only if the gui is in its open state. You can call ImGui functions in it, please check the ImGui.md documentation file for more info. 55 | **Example Usage:** 56 | ```lua 57 | gui.add_imgui(function() 58 | if ImGui.Begin("My Custom Window") then 59 | if ImGui.Button("Label") then 60 | log.info("hi") 61 | end 62 | 63 | end 64 | ImGui.End() 65 | end) 66 | ``` 67 | 68 | - **Parameters:** 69 | - `imgui_rendering` (function): Function that will be called every rendering frame, only if the gui is in its open state. You can call ImGui functions in it, please check the ImGui.md documentation file for more info. 70 | 71 | **Example Usage:** 72 | ```lua 73 | gui.add_imgui(imgui_rendering) 74 | ``` 75 | 76 | ### `is_open()` 77 | 78 | - **Returns:** 79 | - `boolean`: Returns true if the GUI is open. 80 | 81 | **Example Usage:** 82 | ```lua 83 | boolean = gui.is_open() 84 | ``` 85 | 86 | ### `toggle()` 87 | 88 | Opens or closes the GUI. 89 | 90 | **Example Usage:** 91 | ```lua 92 | gui.toggle() 93 | ``` 94 | 95 | 96 | -------------------------------------------------------------------------------- /docs/lua/tables/log.md: -------------------------------------------------------------------------------- 1 | # Table: log 2 | 3 | Table containing functions for printing to console / log file. 4 | 5 | ## Functions (5) 6 | 7 | ### `info(args)` 8 | 9 | Logs an informational message. 10 | 11 | - **Parameters:** 12 | - `args` (any) 13 | 14 | **Example Usage:** 15 | ```lua 16 | log.info(args) 17 | ``` 18 | 19 | ### `warning(args)` 20 | 21 | Logs a warning message. 22 | 23 | - **Parameters:** 24 | - `args` (any) 25 | 26 | **Example Usage:** 27 | ```lua 28 | log.warning(args) 29 | ``` 30 | 31 | ### `debug(args)` 32 | 33 | Logs a debug message. 34 | 35 | - **Parameters:** 36 | - `args` (any) 37 | 38 | **Example Usage:** 39 | ```lua 40 | log.debug(args) 41 | ``` 42 | 43 | ### `error(arg, level)` 44 | 45 | Logs an error message. This is a mirror of lua classic `error` function. 46 | 47 | - **Parameters:** 48 | - `arg` (any) 49 | - `level` (integer) 50 | 51 | **Example Usage:** 52 | ```lua 53 | log.error(arg, level) 54 | ``` 55 | 56 | ### `refresh_filters()` 57 | 58 | Refresh the log filters (Console and File) from the config file. 59 | 60 | **Example Usage:** 61 | ```lua 62 | log.refresh_filters() 63 | ``` 64 | 65 | 66 | -------------------------------------------------------------------------------- /docs/lua/tables/memory.md: -------------------------------------------------------------------------------- 1 | # Table: memory 2 | 3 | Table containing helper functions related to process memory. 4 | 5 | ## Functions (12) 6 | 7 | ### `get_module_base_address(module_name (optional))` 8 | 9 | Returns the base address of a specified module within the current process. Returns a pointer:is_null() == true pointer otherwise. 10 | 11 | - **Parameters:** 12 | - `module_name (optional)` (string): The name of the module for which the base address is to be retrieved. Example: "ntdll.dll". If not provided, the API resolves this to the current targeted main module name automatically. 13 | 14 | - **Returns:** 15 | - `pointer`: A pointer to the found address. 16 | 17 | **Example Usage:** 18 | ```lua 19 | pointer = memory.get_module_base_address(module_name (optional)) 20 | ``` 21 | 22 | ### `scan_pattern_from_module(module_name, pattern)` 23 | 24 | Scans the specified memory pattern within the target main module and returns a pointer to the found address. Returns a pointer:is_null() == true pointer otherwise. 25 | 26 | - **Parameters:** 27 | - `module_name` (string): module name. Example: "ntdll.dll" 28 | - `pattern` (string): byte pattern (IDA format) 29 | 30 | - **Returns:** 31 | - `pointer`: A pointer to the found address. 32 | 33 | **Example Usage:** 34 | ```lua 35 | pointer = memory.scan_pattern_from_module(module_name, pattern) 36 | ``` 37 | 38 | ### `scan_pattern(pattern)` 39 | 40 | Scans the specified memory pattern within the target main module and returns a pointer to the found address. Returns a pointer:is_null() == true pointer otherwise. 41 | 42 | - **Parameters:** 43 | - `pattern` (string): byte pattern (IDA format) 44 | 45 | - **Returns:** 46 | - `pointer`: A pointer to the found address. 47 | 48 | **Example Usage:** 49 | ```lua 50 | pointer = memory.scan_pattern(pattern) 51 | ``` 52 | 53 | ### `allocate(size)` 54 | 55 | - **Parameters:** 56 | - `size` (integer): The number of bytes to allocate on the heap. 57 | 58 | - **Returns:** 59 | - `pointer`: A pointer to the newly allocated memory. 60 | 61 | **Example Usage:** 62 | ```lua 63 | pointer = memory.allocate(size) 64 | ``` 65 | 66 | ### `free(ptr)` 67 | 68 | - **Parameters:** 69 | - `ptr` (pointer): The pointer that must be freed. 70 | 71 | **Example Usage:** 72 | ```lua 73 | memory.free(ptr) 74 | ``` 75 | 76 | ### `dynamic_hook(hook_name, return_type, param_types, target_func_ptr, callbacks)` 77 | 78 | **Example Usage:** 79 | ```lua 80 | local ptr = memory.scan_pattern("some ida sig") 81 | -- Check the implementation of the asmjit::TypeId get_type_id function if you are unsure what to use for return type / parameters types 82 | memory.dynamic_hook("test_hook", "float", {"const char*"}, ptr, 83 | {function(ret_val, str) 84 | 85 | --str:set("replaced str") 86 | ret_val:set(69.69) 87 | log.info("pre callback from lua", ret_val:get(), str:get()) 88 | 89 | -- false for skipping the original function call 90 | return false 91 | end, 92 | function(ret_val, str) 93 | log.info("post callback from lua 1", ret_val:get(), str:get()) 94 | ret_val:set(79.69) 95 | log.info("post callback from lua 2", ret_val:get(), str:get()) 96 | end}) 97 | ``` 98 | 99 | - **Parameters:** 100 | - `hook_name` (string): The name of the hook. 101 | - `return_type` (string): Type of the return value of the detoured function. 102 | - `param_types` (table): Types of the parameters of the detoured function. 103 | - `target_func_ptr` (memory.pointer): The pointer to the function to detour. 104 | - `callbacks` (table): Table first element (can be nil): Pre function callback, lua function that will be called before the original function is about to be called. Pre function callback must match the following signature: ( return_value (value_wrapper), arg1 (value_wrapper), arg2 (value_wrapper), ... ) -> Returns true or false (boolean) depending on whether you want the original function to be called. Table second element (can be nil): function that will be called after the original function. Post function callback must match the following signature: ( return_value (value_wrapper), arg1 (value_wrapper), arg2 (value_wrapper), ... ) -> No return value. 105 | 106 | - **Returns:** 107 | - `number`: Unique identifier for later disabling / enabling the hook on the fly. 108 | 109 | **Example Usage:** 110 | ```lua 111 | number = memory.dynamic_hook(hook_name, return_type, param_types, target_func_ptr, callbacks) 112 | ``` 113 | 114 | ### `dynamic_hook_mid(hook_name, param_captures_targets, param_captures_types, stack_restore_offset, target_func_ptr, mid_callback)` 115 | 116 | **Example Usage:** 117 | ```lua 118 | local ptr = memory.scan_pattern("some ida sig") 119 | gm.dynamic_hook_mid("test_hook", {"rax", "rcx", "[rcx+rdx*4+11]"}, {"int", "RValue*", "int"}, 0, ptr, function(args) 120 | log.info("trigger", args[1]:get(), args[2].value, args[3]:set(1)) 121 | return ptr:add(246) 122 | end) 123 | ``` 124 | But scan_pattern may be affected by the other hooks. 125 | 126 | - **Parameters:** 127 | - `hook_name` (string): The name of the hook. 128 | - `param_captures_targets` (table): Addresses of the parameters which you want to capture. 129 | - `param_captures_types` (table): Types of the parameters which you want to capture. 130 | - `stack_restore_offset` (int): An offset used to restore stack, only need when you want to customize the jump location. 131 | - `target_func_ptr` (memory.pointer): The pointer to the function to detour. 132 | - `mid_callback` (function): The function that will be called when the program reaches the position. The callback must match the following signature: ( args (can be a value_wrapper, or a lua usertype directly, depending if you used `add_type_info_from_string` through some c++ code and exposed it to the lua vm) ) -> Returns memory.pointer if you want to customize the jump location. Be careful when customizing the jump location, you need to restore the registers and the stack before the jump. 133 | 134 | - **Returns:** 135 | - `number`: Unique identifier for later disabling / enabling the hook on the fly. 136 | 137 | **Example Usage:** 138 | ```lua 139 | number = memory.dynamic_hook_mid(hook_name, param_captures_targets, param_captures_types, stack_restore_offset, target_func_ptr, mid_callback) 140 | ``` 141 | 142 | ### `dynamic_hook_enable(identifier)` 143 | 144 | - **Parameters:** 145 | - `identifier` (number): The identifier returned by the `dynamic_hook` family functions. 146 | 147 | **Example Usage:** 148 | ```lua 149 | memory.dynamic_hook_enable(identifier) 150 | ``` 151 | 152 | ### `dynamic_hook_disable(identifier)` 153 | 154 | - **Parameters:** 155 | - `identifier` (number): The identifier returned by the `dynamic_hook` family functions. 156 | 157 | **Example Usage:** 158 | ```lua 159 | memory.dynamic_hook_disable(identifier) 160 | ``` 161 | 162 | ### `dynamic_call(return_type, param_types, target_func_ptr)` 163 | 164 | **Example Usage:** 165 | ```lua 166 | -- the sig in this example leads to an implementation of memcpy_s 167 | local ptr = memory.scan_pattern("48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 49 8B D9 49 8B F0 48 8B FA") 168 | if ptr:is_valid() then 169 | local dest_size = 8 170 | local dest_ptr = memory.allocate(dest_size) 171 | dest_ptr:set_qword(0) 172 | 173 | local src_size = 8 174 | local src_ptr = memory.allocate(src_size) 175 | src_ptr:set_qword(123) 176 | 177 | -- Check the implementation of the asmjit::TypeId get_type_id function if you are unsure what to use for return type / parameters types 178 | local func_to_call_test_global_name = memory.dynamic_call("int", {"void*", "uint64_t", "void*", "uint64_t"}, ptr) 179 | -- print zero. 180 | log.info(dest_ptr:get_qword()) 181 | -- note: don't pass memory.pointer objects directly when you call the function, but use get_address() instead. 182 | local call_res_test = _G[func_to_call_test_global_name](dest_ptr:get_address(), dest_size, src_ptr:get_address(), src_size) 183 | -- print 123. 184 | log.info(dest_ptr:get_qword()) 185 | end 186 | ``` 187 | 188 | - **Parameters:** 189 | - `return_type` (string): Type of the return value of the function to call. 190 | - `param_types` (table): Types of the parameters of the function to call. 191 | - `target_func_ptr` (memory.pointer): The pointer to the function to call. 192 | 193 | - **Returns:** 194 | - `string`: Key name of the function that you can now call from lua. 195 | 196 | **Example Usage:** 197 | ```lua 198 | string = memory.dynamic_call(return_type, param_types, target_func_ptr) 199 | ``` 200 | 201 | ### `resolve_pointer_to_type(target_address, target_type)` 202 | 203 | **Example Usage:** 204 | ```lua 205 | memory.dynamic_hook("test", "RValue*", {"CInstance*","CInstance*","RValue*","int","RValue**"}, 206 | ptr, function (ret_val, skill, player, result, arg_num, args_ptr) 207 | log.info(memory.resolve_pointer_to_type(memory.get_usertype_pointer(skill), "YYObjectBase*").skill_id) 208 | log.info(memory.resolve_pointer_to_type(args_ptr:deref():get_address(), "RValue*").value) 209 | log.info(memory.resolve_pointer_to_type(args_ptr:add(8):deref():get_address(), "RValue*").value) 210 | end) 211 | ``` 212 | 213 | - **Parameters:** 214 | - `target_address` (number): The object target as a lua number. 215 | - `target_type` (string): Target type (must be a pointer type). 216 | 217 | - **Returns:** 218 | - `lua usertype.`: 219 | 220 | **Example Usage:** 221 | ```lua 222 | lua usertype. = memory.resolve_pointer_to_type(target_address, target_type) 223 | ``` 224 | 225 | ### `get_usertype_pointer(usertype_object)` 226 | 227 | - **Parameters:** 228 | - `usertype_object` (any_usertype): A lua usertype instance. 229 | 230 | - **Returns:** 231 | - `number`: The object address as a lua number. 232 | 233 | **Example Usage:** 234 | ```lua 235 | number = memory.get_usertype_pointer(usertype_object) 236 | ``` 237 | 238 | 239 | -------------------------------------------------------------------------------- /docs/lua/tables/mods.md: -------------------------------------------------------------------------------- 1 | # Table: mods 2 | 3 | ## Fields (1) 4 | 5 | ### `[Mod GUID]` 6 | 7 | Each mod once loaded will have a key in this table, the key will be their guid string and the value their `_ENV`. 8 | 9 | - Type: `string` 10 | 11 | ## Functions (2) 12 | 13 | ### `loading_order()` 14 | 15 | - **Returns:** 16 | - `table`: Table containing the order in which mods are loaded by the mod loader. 17 | 18 | **Example Usage:** 19 | ```lua 20 | table = mods.loading_order() 21 | ``` 22 | 23 | ### `on_all_mods_loaded(callback)` 24 | 25 | Registers a callback that will be called once all mods are loaded. Will be called instantly if mods are already loaded and that you are just hot-reloading your mod. 26 | 27 | - **Parameters:** 28 | - `callback` (function): callback that will be called once all mods are loaded. The callback function should match signature func() 29 | 30 | **Example Usage:** 31 | ```lua 32 | mods.on_all_mods_loaded(callback) 33 | ``` 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/lua/tables/path.md: -------------------------------------------------------------------------------- 1 | # Table: path 2 | 3 | Table containing helpers for manipulating file or directory paths 4 | 5 | ## Functions (9) 6 | 7 | ### `combine(path)` 8 | 9 | Combines strings into a path. 10 | 11 | - **Parameters:** 12 | - `path` (string): Any amount of string is accepted. 13 | 14 | - **Returns:** 15 | - `string`: Returns the combined path 16 | 17 | **Example Usage:** 18 | ```lua 19 | string = path.combine(path) 20 | ``` 21 | 22 | ### `get_parent(path)` 23 | 24 | Retrieves the parent directory of the specified path, including both absolute and relative paths. 25 | 26 | - **Parameters:** 27 | - `path` (string): The path for which to retrieve the parent directory. 28 | 29 | - **Returns:** 30 | - `string`: Returns the parent path 31 | 32 | **Example Usage:** 33 | ```lua 34 | string = path.get_parent(path) 35 | ``` 36 | 37 | ### `get_directories(root_path)` 38 | 39 | - **Parameters:** 40 | - `root_path` (string): The path to the directory to search. 41 | 42 | - **Returns:** 43 | - `string table`: Returns the names of subdirectories under the given root_path 44 | 45 | **Example Usage:** 46 | ```lua 47 | string table = path.get_directories(root_path) 48 | ``` 49 | 50 | ### `get_files(root_path)` 51 | 52 | - **Parameters:** 53 | - `root_path` (string): The path to the directory to search. 54 | 55 | - **Returns:** 56 | - `string table`: Returns the names of all the files under the given root_path 57 | 58 | **Example Usage:** 59 | ```lua 60 | string table = path.get_files(root_path) 61 | ``` 62 | 63 | ### `filename(path)` 64 | 65 | - **Parameters:** 66 | - `path` (string): The path for which to retrieve the filename. 67 | 68 | - **Returns:** 69 | - `string`: Returns the filename identified by the path. 70 | 71 | **Example Usage:** 72 | ```lua 73 | string = path.filename(path) 74 | ``` 75 | 76 | ### `stem(path)` 77 | 78 | - **Parameters:** 79 | - `path` (string): The path for which to retrieve the stem. 80 | 81 | - **Returns:** 82 | - `string`: Returns the stem of the filename identified by the path (i.e. the filename without the final extension). 83 | 84 | **Example Usage:** 85 | ```lua 86 | string = path.stem(path) 87 | ``` 88 | 89 | ### `create_directory(path)` 90 | 91 | - **Parameters:** 92 | - `path` (string): The path to the new directory to create. 93 | 94 | - **Returns:** 95 | - `boolean`: true if a directory was newly created for the directory p resolves to, false otherwise. 96 | 97 | **Example Usage:** 98 | ```lua 99 | boolean = path.create_directory(path) 100 | ``` 101 | 102 | ### `exists(path)` 103 | 104 | - **Parameters:** 105 | - `path` (string): The path to check. 106 | 107 | - **Returns:** 108 | - `boolean`: true if the path exists, false otherwise. 109 | 110 | **Example Usage:** 111 | ```lua 112 | boolean = path.exists(path) 113 | ``` 114 | 115 | ### `add_file_watcher(path, callback)` 116 | 117 | Registers a callback that will be called when a file changes. 118 | **Example Usage:** 119 | ```lua 120 | path.add_file_watcher(_ENV["!config_mod_folder_path"], function (file_name, timestamp) 121 | log.info(file_name, timestamp) 122 | end) 123 | ``` 124 | 125 | - **Parameters:** 126 | - `path` (string): The path to add file watcher. 127 | - `callback` (function): callback that match signature function ( file_name, timestamp ). 128 | 129 | **Example Usage:** 130 | ```lua 131 | path.add_file_watcher(path, callback) 132 | ``` 133 | 134 | 135 | -------------------------------------------------------------------------------- /docs/lua/tables/paths.md: -------------------------------------------------------------------------------- 1 | # Table: paths 2 | 3 | Table containing helpers for retrieving project related IO file/folder paths. 4 | 5 | ## Functions (3) 6 | 7 | ### `config()` 8 | 9 | Used for data that must persist between sessions and that can be manipulated by the user. 10 | 11 | - **Returns:** 12 | - `string`: Returns the config folder path 13 | 14 | **Example Usage:** 15 | ```lua 16 | string = paths.config() 17 | ``` 18 | 19 | ### `plugins_data()` 20 | 21 | Used for data that must persist between sessions but not be manipulated by the user. 22 | 23 | - **Returns:** 24 | - `string`: Returns the plugins_data folder path 25 | 26 | **Example Usage:** 27 | ```lua 28 | string = paths.plugins_data() 29 | ``` 30 | 31 | ### `plugins()` 32 | 33 | Location of .lua, README, manifest.json files. 34 | 35 | - **Returns:** 36 | - `string`: Returns the plugins folder path 37 | 38 | **Example Usage:** 39 | ```lua 40 | string = paths.plugins() 41 | ``` 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/lua/tables/toml.md: -------------------------------------------------------------------------------- 1 | ## Usage 2 | 3 | ### Decoding 4 | 5 | ```lua 6 | local tomlStr = [[ 7 | a = 1275892 8 | b = 'Hello, World!' 9 | c = true 10 | d = 124.2548 11 | 12 | [e] 13 | f = [ 1, 2, 3, '4', 5.142 ] 14 | g = 1979-05-27 15 | h = 07:32:00 16 | i = 1979-05-27T07:32:00-07:00 17 | ]] 18 | 19 | -- Decode from string 20 | local succeeded, table = pcall(toml.decode, tomlStr) 21 | 22 | -- Decode from file 23 | succeeded, table = pcall(toml.decodeFromFile, "configuration.toml") 24 | 25 | if succeeded then 26 | -- Use `table`. 27 | else 28 | -- Error details are in `table`. 29 | end 30 | ``` 31 | 32 | #### Decoding Options 33 | 34 | ##### `temporalTypesAsUserData` 35 | 36 | - `temporalTypesAsUserData = true`: The userdata types `toml.Date`, `toml.Time`, and `toml.DateTime` are used to represent TOML date and time types. 37 | 38 | - `temporalTypesAsUserData = false`: Lua tables are used to represent TOML date and time types. 39 | 40 | > The default value is `true` 41 | 42 | ##### `formattedIntsAsUserData` 43 | 44 | - `formattedIntsAsUserData = true`: The userdata type `toml.Int` is used to represent integers in octal, binary, or hexadecimal format. 45 | - `formattedIntsAsUserData = false`: Integers in octal, binary, or hexadecimal format will be represented in decimal. 46 | 47 | > The default value is `false` 48 | 49 | ```lua 50 | local tomlStr = [[ 51 | date = 1979-05-27 52 | time = 07:32:00 53 | datetime = 1979-05-27T07:32:00-07:00 54 | 55 | hexadecimal = 0x16C3 56 | binary = 0b110110011011 57 | octal = 0x169F 58 | ]] 59 | 60 | local table1 = toml.decode(tomlStr, { temporalTypesAsUserData = true, formattedIntsAsUserData = true }) 61 | local table2 = toml.decode(tomlStr, { temporalTypesAsUserData = false, formattedIntsAsUserData = false }) 62 | ``` 63 | 64 | ### Encoding 65 | 66 | ```lua 67 | -- Inline tables: https://toml.io/en/v1.0.0#inline-table 68 | local inlineTable = { 69 | a = 1275892, 70 | b = "Hello, World!", 71 | c = true, 72 | d = 124.2548, 73 | } 74 | 75 | -- Make the table inline. 76 | setmetatable(inlineTable, { inline = true }) 77 | 78 | local table = { 79 | 80 | e = { 81 | f = { 1, 2, 3, "4", 5.142 }, 82 | g = toml.Date.new(1979, 05, 27), 83 | -- year month day 84 | 85 | h = toml.Time.new( 7, 32, 0, 0), 86 | -- hour minute second nanoSecond 87 | 88 | i = toml.DateTime.new( 89 | toml.Date.new(1979, 05, 27), 90 | toml.Time.new(7, 32, 0, 0), 91 | 92 | toml.TimeOffset.new( -7, 0) 93 | -- hour minute 94 | ) 95 | }, 96 | inlineTable = inlineTable 97 | } 98 | 99 | -- Encode to string 100 | local succeeded, documentOrErrorMessage = pcall(toml.encode, table) 101 | 102 | -- Encode to file, this will **append** to the file. 103 | succeeded, documentOrErrorMessage = pcall(toml.encodeToFile, table, "configuration.toml") 104 | 105 | -- Encode to file, this will **overwrite** the file. 106 | succeeded, documentOrErrorMessage = pcall(toml.encodeToFile, table, { file = "configuration.toml", overwrite = true }) 107 | 108 | if succeeded then 109 | -- Successfully encoded to string / wrote to file 110 | print(tomlDocumentOrErrorMessage) 111 | else 112 | -- Error occurred 113 | print(tomlDocumentOrErrorMessage) 114 | end 115 | 116 | --[[ 117 | inlineTable = { a = 1275892, b = "Hello, World!", c = true, d = 124.2548 } 118 | 119 | [e] 120 | f = [ 1, 2, 3, "4", 5.1420000000000003 ] 121 | g = 1979-05-27 122 | h = 07:32:00 123 | i = 1979-05-27T07:32:00-07:00 124 | --]] 125 | ``` 126 | 127 | ### Error Handling 128 | 129 | ```lua 130 | local tomlStr = [[ 131 | a = 1275892 132 | b = 'Hello, World!' 133 | c = true 134 | d = 124. # <-- ERROR: "Expected decimal digit" 135 | 136 | [e] 137 | f = [ 1, 2, 3, '4', 5.142 ] 138 | g = 1979-05-27 139 | h = 07:32:00 140 | i = 1979-05-27T07:32:00-07:00 141 | ]] 142 | 143 | local succeeded, table = pcall(toml.decode, tomlStr) 144 | 145 | if succeeded then 146 | -- Use decoded table. 147 | else 148 | -- Error details are in `table`. 149 | end 150 | ``` 151 | 152 | ### Inline Tables 153 | 154 | Use `setmetatable(myTable, { inline = true })` to create an [inline table](https://toml.io/en/v1.0.0#inline-table). 155 | 156 | ### TOML Conversion 157 | 158 | ```lua 159 | local tomlStr = [[ 160 | a = 1275892 161 | b = 'Hello, World!' 162 | c = true 163 | d = 124.2548 164 | 165 | [e] 166 | f = [ 1, 2, 3, '4', 5.142 ] 167 | g = 1979-05-27 168 | h = 07:32:00 169 | i = 1979-05-27T07:32:00-07:00 170 | ]] 171 | ``` 172 | 173 | #### JSON 174 | 175 | ```lua 176 | -- Convert from a string 177 | local json = toml.toJSON(tomlStr) 178 | 179 | -- or from a table 180 | json = toml.toJSON(toml.decode(tomlStr)) 181 | 182 | print(json) 183 | ``` 184 | 185 | #### YAML 186 | 187 | ```lua 188 | local yaml = toml.toYAML(tomlStr) 189 | yaml = toml.toYAML(toml.decode(tomlStr)) 190 | print(yaml) 191 | ``` 192 | 193 | ### Output Formatting 194 | 195 | #### Formatting Integers 196 | 197 | ```lua 198 | local normalIntegers = { 199 | int1 = 2582 200 | int2 = 3483 201 | int3 = 5971 202 | } 203 | print(toml.encode(normalIntegers)) 204 | --[[ 205 | int1 = 2582 206 | int2 = 3483 207 | int3 = 5791 208 | --]] 209 | 210 | local formattedIntegers = { 211 | int1 = toml.Int.new(2582, toml.formatting.int.octal), 212 | int2 = toml.Int.new(3483, toml.formatting.int.binary), 213 | int3 = toml.Int.new(5791, toml.formatting.int.hexadecimal) 214 | } 215 | 216 | print(toml.encode(formattedIntegers)) 217 | --[[ 218 | int1 = 0o5026 219 | int2 = 0b110110011011 220 | int3 = 0x169F 221 | --]] 222 | 223 | -- Use `int` and `flags` properties to assign and retrieve flags and integers. 224 | local int = formattedIntegers.int1.int 225 | local flags = formattedIntegers.int1.flags 226 | 227 | formattedIntegers.int1.int = 5827 228 | formattedIntegers.int1.flags = toml.formatting.int.hexadecimal 229 | 230 | print(toml.encode(formattedIntegers)) 231 | --[[ 232 | int1 = 0x16C3 233 | int2 = 0b110110011011 234 | int3 = 0x169F 235 | --]] 236 | ``` 237 | 238 | #### Formatting TOML, JSON, or YAML 239 | 240 | `toml.encode`, `toml.encodeToFile`, `toml.toJSON`, and `toml.toYAML` all take an optional second parameter: a table containing keys that disable or enable different formatting options. 241 | Passing an empty table removes all options, while not providing a table will use the default options. 242 | 243 | ```lua 244 | { 245 | --- Dates and times will be emitted as quoted strings. 246 | quoteDatesAndTimes = false, 247 | 248 | --- Infinities and NaNs will be emitted as quoted strings. 249 | quoteInfinitesAndNaNs = false, 250 | 251 | --- Strings will be emitted as single-quoted literal strings where possible. 252 | allowLiteralStrings = false, 253 | 254 | --- Strings containing newlines will be emitted as triple-quoted 'multi-line' strings where possible. 255 | allowMultiLineStrings = false, 256 | 257 | --- Allow real tab characters in string literals (as opposed to the escaped form `\t`). 258 | allowRealTabsInStrings = false, 259 | 260 | --- Allow non-ASCII characters in strings (as opposed to their escaped form, e.g. `\u00DA`). 261 | allow_unicode_strings = true, 262 | 263 | --- Allow integers with `toml.formatting.int.binary` to be emitted as binary. 264 | allowBinaryIntegers = true, 265 | 266 | --- Allow integers with `toml.formatting.int.octal` to be emitted as octal. 267 | allowOctalIntegers = true, 268 | 269 | --- Allow integers with `toml.formatting.int.hexadecimal` to be emitted as hexadecimal. 270 | allowHexadecimalIntegers = true, 271 | 272 | --- Apply indentation to tables nested within other tables/arrays. 273 | indentSubTables = true, 274 | 275 | --- Apply indentation to array elements when the array is forced to wrap over multiple lines. 276 | indentArrayElements = true, 277 | 278 | --- Combination of `indentSubTables` and `indentArrayElements`. 279 | indentation = true, 280 | 281 | --- Emit floating-point values with relaxed (human-friendly) precision. 282 | --- 283 | --- Warning: Setting this flag may cause serialized documents to no longer round- 284 | --- trip correctly since floats might have a less precise value upon being written out 285 | --- than they did when being read in. Use this flag at your own risk. 286 | relaxedFloatPrecision = false, 287 | 288 | --- Avoids the use of whitespace around key-value pairs. 289 | terseKeyValuePairs = false 290 | } 291 | ``` 292 | 293 | ### Date and Time 294 | 295 | (Creating Date, Time, and DateTime is shown in [the encoding section](#encoding)) 296 | 297 | ```lua 298 | record Date 299 | year: number 300 | month: number 301 | day: number 302 | 303 | new: function(year: number, month: number, day: number): Date 304 | end 305 | 306 | record Time 307 | hour: number 308 | minute: number 309 | second: number 310 | nanoSecond: number 311 | 312 | new: function ( 313 | hour: number, 314 | minute: number, 315 | second: number, 316 | nanoSecond: number 317 | ): Time 318 | end 319 | 320 | record TimeOffset 321 | minutes: number 322 | 323 | new: function (hours: number, minutes: number): TimeOffset 324 | end 325 | 326 | record DateTime 327 | date: Date 328 | time: Time 329 | TimeOffset: nil | TimeOffset 330 | 331 | new: function(date: Date, time: Time): DateTime 332 | new: function(date: Date, time: Time, timeOffset: TimeOffset): DateTime 333 | end 334 | ``` 335 | 336 | > The comments for the options are from [the tomlplusplus documentation](https://marzer.github.io/tomlplusplus/namespacetoml.html#a2102aa80bc57783d96180f36e1f64f6a) -------------------------------------------------------------------------------- /examples/plugins/ReturnOfModding-DebugToolkit/lib_debug.lua: -------------------------------------------------------------------------------- 1 | local demo_mod = {} -- The main table 2 | 3 | local hi, there = ... 4 | 5 | log.info(nil, hi, there) 6 | 7 | function demo_mod.hello() 8 | log.info("Hi from some library that you require") 9 | end 10 | 11 | return demo_mod -------------------------------------------------------------------------------- /examples/plugins/ReturnOfModding-DebugToolkit/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DebugToolkit", 3 | "version_number": "1.0.0", 4 | "website_url": "https://github.com/return-of-modding/ReturnOfModding", 5 | "description": "Debug tool for Risk of Rain Returns", 6 | "dependencies": [ 7 | "ReturnOfModding-ReturnOfModding-1.0.0" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /examples/plugins/ReturnOfModding-ShareItem/main.lua: -------------------------------------------------------------------------------- 1 | local share_item_enabled = true 2 | gui.add_to_menu_bar(function() 3 | local new_value, clicked = ImGui.Checkbox("Enable Share Item", share_item_enabled) 4 | if clicked then 5 | share_item_enabled = new_value 6 | end 7 | end) 8 | 9 | local function add_chat_message(text) 10 | gm.chat_add_message(gm["@@NewGMLObject@@"](gm.constants.ChatMessage, text)) 11 | end 12 | 13 | local currently_giving = false 14 | gm.post_script_hook(gm.constants.item_give, function(self, other, result, args) 15 | if share_item_enabled and not currently_giving then 16 | local actor = args[1].value 17 | 18 | if actor.object_index == gm.constants.oP then 19 | for i = 1, #gm.CInstance.instances_active do 20 | local inst = gm.CInstance.instances_active[i] 21 | if inst.object_index == gm.constants.oP and inst.id ~= actor.id then 22 | local item_id = args[2].value 23 | local count = args[3].value 24 | local stack_kind = args[4].value 25 | 26 | currently_giving = true 27 | add_chat_message("Giving item id " .. item_id .. " to " .. inst.user_name .. " (" .. inst.name .. ")") 28 | gm.item_give(inst, item_id, count, stack_kind) 29 | currently_giving = false 30 | end 31 | end 32 | end 33 | end 34 | end) 35 | 36 | gui.add_imgui(function() 37 | if ImGui.Begin("Share Item Debug") then 38 | if ImGui.Button("Give Gold") then 39 | for i = 1, #gm.CInstance.instances_active do 40 | local inst = gm.CInstance.instances_active[i] 41 | if inst.object_index == gm.constants.oP then 42 | gm.drop_gold_and_exp(inst.x, inst.y, 500) 43 | add_chat_message("Giving gold to " .. inst.user_name .. " (" .. inst.name .. ")") 44 | break 45 | end 46 | end 47 | end 48 | 49 | ImGui.End() 50 | end 51 | end) 52 | -------------------------------------------------------------------------------- /examples/plugins/ReturnOfModding-ShareItem/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ShareItem", 3 | "version_number": "1.0.0", 4 | "website_url": "https://github.com/return-of-modding/ReturnOfModding", 5 | "description": "Share Item for Risk of Rain Returns", 6 | "dependencies": [ 7 | "ReturnOfModding-ReturnOfModding-1.0.0" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /examples/plugins/sarn-coolguy/main.lua: -------------------------------------------------------------------------------- 1 | survivor_setup = require("sarn-coolguy_setup/survivor_setup") 2 | 3 | -- messing with these two is pretty fun. 4 | local circle_increment = 15 5 | local explosion_radius = 150 6 | 7 | local angle_increment = 2 * math.pi / circle_increment 8 | local current_explosion_angle_index = 1 9 | local rotation_direction = 1 -- 1 for clockwise, -1 for counterclockwise 10 | local timer_in_seconds = 0 11 | local rotation_interval_in_seconds = 0.05 -- in seconds 12 | 13 | local explosion_sprite = gm.constants.sLoaderExplode 14 | 15 | local function delta_time_in_seconds() 16 | return gm.variable_global_get("delta_time") / 1000000 17 | end 18 | 19 | local function rotating_balls_step_logic(self) 20 | if self.class == survivor_setup.coolguy_id then 21 | -- do coolguy stuff 22 | if self.local_client_is_authority then -- don't call if this isn't our player 23 | timer_in_seconds = timer_in_seconds + delta_time_in_seconds() 24 | 25 | if timer_in_seconds >= rotation_interval_in_seconds then 26 | local angle = angle_increment * current_explosion_angle_index * rotation_direction 27 | local offset_x = explosion_radius * math.cos(angle) 28 | local offset_y = explosion_radius * math.sin(angle) 29 | 30 | gm._mod_attack_fire_explosion( 31 | self.id, -- owner 32 | self.x + offset_x, -- x position adjusted based on angle 33 | self.y + offset_y, -- y position adjusted based on angle 34 | 80, 32, -- width / height 35 | 4, -- damage 36 | explosion_sprite, -- explosion sprite 37 | gm.constants.sSparks14, -- sparks sprite 38 | 1 39 | ) 40 | 41 | -- Increment the explosion index for the next frame 42 | current_explosion_angle_index = (current_explosion_angle_index % circle_increment) + 1 43 | 44 | timer_in_seconds = 0 45 | end 46 | end 47 | end 48 | end 49 | 50 | local function skill_primary_on_activation(self, actor_skill, skill_index) 51 | if self.class == survivor_setup.coolguy_id then 52 | -- do coolguy stuff 53 | if self.local_client_is_authority then -- don't call if this isn't our player 54 | rotation_direction = -rotation_direction 55 | explosion_sprite = explosion_sprite + 1 56 | end 57 | end 58 | end 59 | 60 | local callback_names = gm.variable_global_get("callback_names") 61 | local on_player_init_callback_id = 0 62 | local on_player_step_callback_id = 0 63 | for i = 1, #callback_names do 64 | local callback_name = callback_names[i] 65 | if callback_name:match("onPlayerInit") then 66 | on_player_init_callback_id = i - 1 67 | end 68 | 69 | if callback_name:match("onPlayerStep") then 70 | on_player_step_callback_id = i - 1 71 | end 72 | end 73 | 74 | local pre_hooks = {} 75 | gm.pre_script_hook(gm.constants.callback_execute, function(self, other, result, args) 76 | local callback_id = args[1].value 77 | if pre_hooks[callback_id] then 78 | return pre_hooks[callback_id](self, other, result, args) 79 | end 80 | 81 | return true 82 | end) 83 | 84 | local post_hooks = {} 85 | gm.post_script_hook(gm.constants.callback_execute, function(self, other, result, args) 86 | local callback_id = args[1].value 87 | if post_hooks[callback_id] then 88 | post_hooks[callback_id](self, other, result, args) 89 | end 90 | end) 91 | 92 | post_hooks[on_player_step_callback_id] = function(self_, other, result, args) 93 | local self = args[2].value 94 | rotating_balls_step_logic(self) 95 | end 96 | 97 | local function get_random_sprite(sprite_str) 98 | local matches = {} 99 | local i = 1 100 | for k, v in pairs(gm.constants) do 101 | if k:match(sprite_str) then 102 | matches[i] = v 103 | i = i + 1 104 | end 105 | end 106 | 107 | if #matches > 0 then 108 | local random_sprite = matches[math.random(1, #matches)] 109 | 110 | local subimage_count = gm.sprite_get_number(random_sprite) 111 | local random_sprite_name = gm.sprite_get_name(random_sprite) 112 | if random_sprite_name and random_sprite and subimage_count then 113 | print(random_sprite_name, "", "", random_sprite, "subimage_count", subimage_count) 114 | end 115 | 116 | return random_sprite 117 | end 118 | 119 | return gm.constants.sCommandoWalk 120 | end 121 | 122 | local sprite_walk = -1 123 | local function load_sprite_from_disk(file_name) 124 | local file_path = _ENV["!plugins_data_mod_folder_path"] .. "/" .. file_name 125 | local new_sprite = gm.sprite_add(file_path, 8, false, false, 11, 14) 126 | if new_sprite == -1 then 127 | log.warning("Failed loading sprite", file_name, file_path) 128 | return gm.constants.sCommandoWalk 129 | end 130 | 131 | return new_sprite 132 | end 133 | local function load_sprites_from_disk() 134 | sprite_walk = load_sprite_from_disk("spritesheet_sniper_walk_blue.png") 135 | end 136 | load_sprites_from_disk() 137 | 138 | local function setup_sprites(self) 139 | local survivors = gm.variable_global_get("class_survivor") 140 | if survivors ~= nil then 141 | self.sprite_idle = get_random_sprite("Idle") 142 | self.sprite_walk = sprite_walk 143 | self.sprite_jump = get_random_sprite("Jump") 144 | self.sprite_jump_peak = get_random_sprite("JumpPeak") 145 | self.sprite_fall = get_random_sprite("Fall") 146 | self.sprite_climb = get_random_sprite("Climb") 147 | self.sprite_death = get_random_sprite("Death") 148 | self.sprite_decoy = get_random_sprite("Decoy") 149 | end 150 | end 151 | 152 | local function setup_skills_callbacks() 153 | local primary = survivor_setup.coolguy.skill_family_z[0] 154 | if not pre_hooks[primary.on_activate] then 155 | pre_hooks[primary.on_activate] = function(self, other, result, args) 156 | skill_primary_on_activation(self) 157 | 158 | -- don't call orig 159 | return false 160 | end 161 | end 162 | end 163 | 164 | post_hooks[on_player_init_callback_id] = function(self, other, result, args) 165 | setup_sprites(self) 166 | 167 | setup_skills_callbacks() 168 | end 169 | 170 | local function print_name_of_object(object_id) 171 | for k, v in pairs(gm.constants) do 172 | if v == object_id then 173 | print(k .. ": " .. v) 174 | end 175 | end 176 | end 177 | 178 | -- print_name_of_object(survivor_setup.coolguy.sprite_title) 179 | -- print_name_of_object(survivor_setup.coolguy.sprite_idle) 180 | 181 | gui.add_to_menu_bar(function() 182 | if ImGui.BeginMenu("Debug Info") then 183 | ImGui.Text("explosion_sprite: " .. explosion_sprite) 184 | 185 | ImGui.EndMenu() 186 | end 187 | end) -------------------------------------------------------------------------------- /examples/plugins/sarn-coolguy/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coolguy", 3 | "version_number": "1.0.0", 4 | "website_url": "https://github.com/return-of-modding/ReturnOfModding", 5 | "description": "Test fellow.", 6 | "dependencies": [ 7 | "ReturnOfModding-ReturnOfModding-1.0.0", 8 | "sarn-coolguy_setup-1.0.0" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /examples/plugins/sarn-coolguy_setup/main.lua: -------------------------------------------------------------------------------- 1 | require("./survivor_setup") 2 | 3 | print("main setup", survivor_setup) -------------------------------------------------------------------------------- /examples/plugins/sarn-coolguy_setup/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coolguy_setup", 3 | "version_number": "1.0.0", 4 | "website_url": "https://github.com/return-of-modding/ReturnOfModding", 5 | "description": "Test fellow.", 6 | "dependencies": [ 7 | "ReturnOfModding-ReturnOfModding-1.0.0" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /examples/plugins_data/sarn-coolguy/spritesheet_sniper_walk_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/return-of-modding/ReturnOfModding/64b9d779d29d0f39737005c93779f2d14722d3eb/examples/plugins_data/sarn-coolguy/spritesheet_sniper_walk_blue.png -------------------------------------------------------------------------------- /linux_build.sh: -------------------------------------------------------------------------------- 1 | clear && msvc-x64-cmake --build ./build --config Release --target ReturnOfModding -- && cp ~/code/ReturnOfModding/build/version.dll ~/.local/share/Steam/steamapps/common/Risk\ of\ Rain\ Returns/ && steam steam://rungameid/1337520 -------------------------------------------------------------------------------- /lua_doc_gen.txt: -------------------------------------------------------------------------------- 1 | python ".\out\build\x64-Release-FINAL\_deps\rom-src\docs\lua_docs_generator\doc_gen.py" ".\out\build\x64-Release-FINAL\_deps\rom-src\src" ".\src\" ".\docs\lua" -------------------------------------------------------------------------------- /src/common.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_INC 2 | #define COMMON_INC 3 | 4 | // clang-format off 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | #include 54 | 55 | #include "logger/logger.hpp" 56 | #include "lua/sol_include.hpp" 57 | #include "gui/imgui_include.hpp" 58 | #include "rom/rom.hpp" 59 | 60 | // clang-format on 61 | 62 | namespace big 63 | { 64 | using namespace std::chrono_literals; 65 | 66 | inline HMODULE g_hmodule{}; 67 | 68 | inline HANDLE g_main_thread{}; 69 | inline DWORD g_main_thread_id{}; 70 | 71 | inline std::atomic_bool g_abort{false}; 72 | inline std::atomic_bool g_running{false}; 73 | 74 | inline constexpr auto g_target_window_class_name = "YYGameMakerYY"; 75 | } // namespace big 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/dll_proxy/dll_proxy.cpp: -------------------------------------------------------------------------------- 1 | #include "dll_proxy.hpp" 2 | 3 | namespace big 4 | { 5 | static HMODULE dll_proxies[MODULE_MAX]{}; 6 | static LPCWSTR dll_proxy_names[MODULE_MAX]{ 7 | L"version.dll", 8 | }; 9 | 10 | static FARPROC get_function(dll_proxy index, const char* name) 11 | { 12 | if (dll_proxies[index] == nullptr) 13 | { 14 | BOOL wow64 = FALSE; 15 | WCHAR path[MAX_PATH]; 16 | 17 | if (IsWow64Process(GetCurrentProcess(), &wow64) && wow64) 18 | { 19 | GetSystemWow64DirectoryW(path, MAX_PATH); 20 | } 21 | else 22 | { 23 | GetSystemDirectoryW(path, MAX_PATH); 24 | } 25 | 26 | lstrcatW(path, L"\\"); 27 | lstrcatW(path, dll_proxy_names[index]); 28 | dll_proxies[index] = LoadLibraryW(path); 29 | } 30 | 31 | return GetProcAddress(dll_proxies[index], name); 32 | } 33 | 34 | template 35 | static T forward_version_call_internal(dll_proxy index, const char* funcName, T) 36 | { 37 | static T proc = nullptr; 38 | if (proc != nullptr) 39 | { 40 | return proc; 41 | } 42 | return proc = reinterpret_cast(get_function(index, funcName)); 43 | } 44 | 45 | #define forward_version_call(F) forward_version_call_internal(VERSION_DLL, #F, F) 46 | 47 | EXTERN_C BOOL WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData) 48 | { 49 | return forward_version_call(GetFileVersionInfoA)(lptstrFilename, dwHandle, dwLen, lpData); 50 | } 51 | 52 | EXTERN_C int WINAPI GetFileVersionInfoByHandle(int hMem, LPCWSTR lpFileName, int v2, int v3) 53 | { 54 | return forward_version_call(GetFileVersionInfoByHandle)(hMem, lpFileName, v2, v3); 55 | } 56 | 57 | EXTERN_C BOOL WINAPI GetFileVersionInfoExA(DWORD dwFlags, LPCSTR lpwstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData) 58 | { 59 | return forward_version_call(GetFileVersionInfoExA)(dwFlags, lpwstrFilename, dwHandle, dwLen, lpData); 60 | } 61 | 62 | EXTERN_C BOOL WINAPI GetFileVersionInfoExW(DWORD dwFlags, LPCWSTR lpwstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData) 63 | { 64 | return forward_version_call(GetFileVersionInfoExW)(dwFlags, lpwstrFilename, dwHandle, dwLen, lpData); 65 | } 66 | 67 | EXTERN_C DWORD WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename, LPDWORD lpdwHandle) 68 | { 69 | return forward_version_call(GetFileVersionInfoSizeA)(lptstrFilename, lpdwHandle); 70 | } 71 | 72 | EXTERN_C DWORD WINAPI GetFileVersionInfoSizeExA(DWORD dwFlags, LPCSTR lpwstrFilename, LPDWORD lpdwHandle) 73 | { 74 | return forward_version_call(GetFileVersionInfoSizeExA)(dwFlags, lpwstrFilename, lpdwHandle); 75 | } 76 | 77 | EXTERN_C DWORD WINAPI GetFileVersionInfoSizeExW(DWORD dwFlags, LPCWSTR lpwstrFilename, LPDWORD lpdwHandle) 78 | { 79 | return forward_version_call(GetFileVersionInfoSizeExW)(dwFlags, lpwstrFilename, lpdwHandle); 80 | } 81 | 82 | EXTERN_C DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename, LPDWORD lpdwHandle) 83 | { 84 | return forward_version_call(GetFileVersionInfoSizeW)(lptstrFilename, lpdwHandle); 85 | } 86 | 87 | EXTERN_C BOOL WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData) 88 | { 89 | return forward_version_call(GetFileVersionInfoW)(lptstrFilename, dwHandle, dwLen, lpData); 90 | } 91 | 92 | EXTERN_C DWORD WINAPI VerFindFileA(DWORD uFlags, LPCSTR szFileName, LPCSTR szWinDir, LPCSTR szAppDir, LPSTR szCurDir, PUINT lpuCurDirLen, LPSTR szDestDir, PUINT lpuDestDirLen) 93 | { 94 | return forward_version_call(VerFindFileA)(uFlags, szFileName, szWinDir, szAppDir, szCurDir, lpuCurDirLen, szDestDir, lpuDestDirLen); 95 | } 96 | 97 | EXTERN_C DWORD WINAPI VerFindFileW(DWORD uFlags, LPCWSTR szFileName, LPCWSTR szWinDir, LPCWSTR szAppDir, LPWSTR szCurDir, PUINT lpuCurDirLen, LPWSTR szDestDir, PUINT lpuDestDirLen) 98 | { 99 | return forward_version_call(VerFindFileW)(uFlags, szFileName, szWinDir, szAppDir, szCurDir, lpuCurDirLen, szDestDir, lpuDestDirLen); 100 | } 101 | 102 | EXTERN_C DWORD WINAPI VerInstallFileA(DWORD uFlags, LPCSTR szSrcFileName, LPCSTR szDestFileName, LPCSTR szSrcDir, LPCSTR szDestDir, LPCSTR szCurDir, LPSTR szTmpFile, PUINT lpuTmpFileLen) 103 | { 104 | return forward_version_call(VerInstallFileA)(uFlags, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, szTmpFile, lpuTmpFileLen); 105 | } 106 | 107 | EXTERN_C DWORD WINAPI VerInstallFileW(DWORD uFlags, LPCWSTR szSrcFileName, LPCWSTR szDestFileName, LPCWSTR szSrcDir, LPCWSTR szDestDir, LPCWSTR szCurDir, LPWSTR szTmpFile, PUINT lpuTmpFileLen) 108 | { 109 | return forward_version_call(VerInstallFileW)(uFlags, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, szTmpFile, lpuTmpFileLen); 110 | } 111 | 112 | EXTERN_C DWORD WINAPI VerLanguageNameA(DWORD wLang, LPSTR szLang, DWORD cchLang) 113 | { 114 | return forward_version_call(VerLanguageNameA)(wLang, szLang, cchLang); 115 | } 116 | 117 | EXTERN_C DWORD WINAPI VerLanguageNameW(DWORD wLang, LPWSTR szLang, DWORD cchLang) 118 | { 119 | return forward_version_call(VerLanguageNameW)(wLang, szLang, cchLang); 120 | } 121 | 122 | EXTERN_C BOOL WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen) 123 | { 124 | return forward_version_call(VerQueryValueA)(pBlock, lpSubBlock, lplpBuffer, puLen); 125 | } 126 | 127 | EXTERN_C BOOL WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen) 128 | { 129 | return forward_version_call(VerQueryValueW)(pBlock, lpSubBlock, lplpBuffer, puLen); 130 | } 131 | } // namespace big 132 | -------------------------------------------------------------------------------- /src/dll_proxy/dll_proxy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace big 4 | { 5 | enum dll_proxy 6 | { 7 | VERSION_DLL, 8 | MODULE_MAX 9 | }; 10 | 11 | EXTERN_C BOOL WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); 12 | 13 | EXTERN_C int WINAPI GetFileVersionInfoByHandle(int hMem, LPCWSTR lpFileName, int v2, int v3); 14 | 15 | EXTERN_C BOOL WINAPI GetFileVersionInfoExA(DWORD dwFlags, LPCSTR lpwstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); 16 | 17 | EXTERN_C BOOL WINAPI GetFileVersionInfoExW(DWORD dwFlags, LPCWSTR lpwstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); 18 | 19 | EXTERN_C DWORD WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename, LPDWORD lpdwHandle); 20 | 21 | EXTERN_C DWORD WINAPI GetFileVersionInfoSizeExA(DWORD dwFlags, LPCSTR lpwstrFilename, LPDWORD lpdwHandle); 22 | 23 | EXTERN_C DWORD WINAPI GetFileVersionInfoSizeExW(DWORD dwFlags, LPCWSTR lpwstrFilename, LPDWORD lpdwHandle); 24 | 25 | EXTERN_C DWORD WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename, LPDWORD lpdwHandle); 26 | 27 | EXTERN_C BOOL WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); 28 | 29 | EXTERN_C DWORD WINAPI VerFindFileA(DWORD uFlags, LPCSTR szFileName, LPCSTR szWinDir, LPCSTR szAppDir, LPSTR szCurDir, PUINT lpuCurDirLen, LPSTR szDestDir, PUINT lpuDestDirLen); 30 | 31 | EXTERN_C DWORD WINAPI VerFindFileW(DWORD uFlags, LPCWSTR szFileName, LPCWSTR szWinDir, LPCWSTR szAppDir, LPWSTR szCurDir, PUINT lpuCurDirLen, LPWSTR szDestDir, PUINT lpuDestDirLen); 32 | 33 | EXTERN_C DWORD WINAPI VerInstallFileA(DWORD uFlags, LPCSTR szSrcFileName, LPCSTR szDestFileName, LPCSTR szSrcDir, LPCSTR szDestDir, LPCSTR szCurDir, LPSTR szTmpFile, PUINT lpuTmpFileLen); 34 | 35 | EXTERN_C DWORD WINAPI VerInstallFileW(DWORD uFlags, LPCWSTR szSrcFileName, LPCWSTR szDestFileName, LPCWSTR szSrcDir, LPCWSTR szDestDir, LPCWSTR szCurDir, LPWSTR szTmpFile, PUINT lpuTmpFileLen); 36 | 37 | EXTERN_C DWORD WINAPI VerLanguageNameA(DWORD wLang, LPSTR szLang, DWORD cchLang); 38 | 39 | EXTERN_C DWORD WINAPI VerLanguageNameW(DWORD wLang, LPWSTR szLang, DWORD cchLang); 40 | 41 | EXTERN_C BOOL WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen); 42 | 43 | EXTERN_C BOOL WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen); 44 | } // namespace big 45 | -------------------------------------------------------------------------------- /src/dll_proxy/version.def: -------------------------------------------------------------------------------- 1 | LIBRARY version 2 | 3 | EXPORTS 4 | GetFileVersionInfoA 5 | GetFileVersionInfoByHandle 6 | GetFileVersionInfoExA 7 | GetFileVersionInfoExW 8 | GetFileVersionInfoSizeA 9 | GetFileVersionInfoSizeExA 10 | GetFileVersionInfoSizeExW 11 | GetFileVersionInfoSizeW 12 | GetFileVersionInfoW 13 | VerFindFileA 14 | VerFindFileW 15 | VerInstallFileA 16 | VerInstallFileW 17 | VerLanguageNameA 18 | VerLanguageNameW 19 | VerQueryValueA 20 | VerQueryValueW -------------------------------------------------------------------------------- /src/gui/gui.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "input/hotkey.hpp" 4 | 5 | namespace big 6 | { 7 | static inline hotkey g_gui_toggle("gui_toggle", VK_INSERT); 8 | 9 | class gui 10 | { 11 | public: 12 | ImU32 background_color = 3'696'311'571; 13 | ImU32 text_color = 4'294'967'295; 14 | ImU32 button_color = 2'947'901'213; 15 | ImU32 frame_color = 2'942'518'340; 16 | float scale = 1.0f; 17 | 18 | public: 19 | gui(); 20 | virtual ~gui(); 21 | gui(const gui&) = delete; 22 | gui(gui&&) noexcept = delete; 23 | gui& operator=(const gui&) = delete; 24 | gui& operator=(gui&&) noexcept = delete; 25 | 26 | bool is_open(); 27 | void toggle(bool toggle); 28 | 29 | ImGuiMouseCursor m_mouse_cursor = ImGuiMouseCursor_Arrow; 30 | 31 | void dx_init(); 32 | void dx_on_tick(); 33 | 34 | void save_default_style(); 35 | void restore_default_style(); 36 | 37 | void push_theme_colors(); 38 | void pop_theme_colors(); 39 | 40 | void wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); 41 | 42 | private: 43 | void toggle_mouse(); 44 | 45 | std::filesystem::path m_file_path; 46 | toml::table m_table; 47 | void init_pref(); 48 | void save_pref(); 49 | 50 | private: 51 | bool m_is_open; 52 | toml::node* m_is_open_at_startup; 53 | toml::node* m_onboarded; 54 | 55 | ImGuiStyle m_default_config; 56 | }; 57 | 58 | inline gui* g_gui; 59 | } // namespace big 60 | -------------------------------------------------------------------------------- /src/gui/imgui_config.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Disable asserts 4 | #define IM_ASSERT(_EXPR) ((void)(_EXPR)) 5 | -------------------------------------------------------------------------------- /src/gui/renderer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace big 6 | { 7 | using init_callback = std::function; 8 | 9 | struct dx_callback 10 | { 11 | std::function m_callback; 12 | int64_t m_priority; 13 | }; 14 | 15 | using wndproc_callback = std::function; 16 | 17 | class renderer final 18 | { 19 | private: 20 | std::vector m_init_callbacks; 21 | std::vector m_dx_callbacks; 22 | std::vector m_wndproc_callbacks; 23 | 24 | public: 25 | WNDPROC m_og_wndproc = nullptr; 26 | 27 | ImFont* font_title = nullptr; 28 | ImFont* font_sub_title = nullptr; 29 | ImFont* font_small = nullptr; 30 | ImFont* font_icon = nullptr; 31 | 32 | public: 33 | void init(); 34 | 35 | explicit renderer(); 36 | ~renderer(); 37 | 38 | bool add_init_callback(init_callback callback); 39 | 40 | /** 41 | * @brief Add a callback function to draw your ImGui content in 42 | * 43 | * @param callback function + priority, The higher the priority the value the later it gets drawn on top. 44 | * @return true 45 | * @return false 46 | */ 47 | bool add_dx_callback(dx_callback callback); 48 | 49 | void remove_wndproc_callback(size_t callback_index); 50 | 51 | /** 52 | * @brief Add a callback function on wndproc 53 | * 54 | * @param callback Function 55 | */ 56 | size_t add_wndproc_callback(wndproc_callback callback); 57 | 58 | void wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); 59 | 60 | void render_imgui_d3d11(IDXGISwapChain1* swapchain); 61 | 62 | public: 63 | void init_fonts(); 64 | bool hook(); 65 | 66 | HWND m_window_handle; 67 | }; 68 | 69 | __int64 hook_init_renderer_on_CreateSwapChain(HWND a1, int a2, int a3, int a4); 70 | 71 | inline renderer* g_renderer{}; 72 | } // namespace big 73 | -------------------------------------------------------------------------------- /src/lua/bindings/game_maker.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "lua/lua_module.hpp" 3 | 4 | namespace lua::game_maker 5 | { 6 | void bind(sol::table& state, sol::state_view& L); 7 | } 8 | -------------------------------------------------------------------------------- /src/lua/bindings/gui_ext.cpp: -------------------------------------------------------------------------------- 1 | #include "gui_ext.hpp" 2 | 3 | #include "gui/gui.hpp" 4 | 5 | #include 6 | 7 | namespace lua::gui_ext 8 | { 9 | static bool is_open() 10 | { 11 | return big::g_gui && big::g_gui->is_open(); 12 | } 13 | 14 | static void toggle() 15 | { 16 | if (big::g_gui) 17 | { 18 | big::g_gui->toggle(!big::g_gui->is_open()); 19 | } 20 | } 21 | 22 | void bind(sol::table& state) 23 | { 24 | lua::gui::g_on_is_open = is_open; 25 | lua::gui::g_on_toggle = toggle; 26 | } 27 | } // namespace lua::gui_ext 28 | -------------------------------------------------------------------------------- /src/lua/bindings/gui_ext.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lua::gui_ext 4 | { 5 | void bind(sol::table& state); 6 | } 7 | -------------------------------------------------------------------------------- /src/lua/lua_manager_extension.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "lua_module_ext.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace big::lua_manager_extension 9 | { 10 | void init_lua_base(sol::state_view& state); 11 | void init_lua_api(sol::state_view& state, sol::table& lua_ext); 12 | 13 | bool pre_code_execute(CInstance* self, CInstance* other, CCode* code, RValue* result, int flags); 14 | void post_code_execute(CInstance* self, CInstance* other, CCode* code, RValue* result, int flags); 15 | 16 | bool pre_code_execute_fast(void* original_func_ptr, CInstance* self, CInstance* other); 17 | void post_code_execute_fast(void* original_func_ptr, CInstance* self, CInstance* other); 18 | 19 | bool pre_builtin_execute(void* original_func_ptr, CInstance* self, CInstance* other, RValue* result, int arg_count, RValue* args); 20 | void post_builtin_execute(void* original_func_ptr, CInstance* self, CInstance* other, RValue* result, int arg_count, RValue* args); 21 | 22 | bool pre_script_execute(void* original_func_ptr, CInstance* self, CInstance* other, RValue* result, int arg_count, RValue** args); 23 | void post_script_execute(void* original_func_ptr, CInstance* self, CInstance* other, RValue* result, int arg_count, RValue** args); 24 | } // namespace big::lua_manager_extension 25 | -------------------------------------------------------------------------------- /src/lua/lua_module_ext.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lua/lua_module.hpp" 4 | 5 | namespace big 6 | { 7 | struct lua_module_data_ext 8 | { 9 | std::vector m_pre_code_execute_callbacks; 10 | std::vector m_post_code_execute_callbacks; 11 | 12 | ankerl::unordered_dense::map> m_pre_code_execute_fast_callbacks; 13 | ankerl::unordered_dense::map> m_post_code_execute_fast_callbacks; 14 | 15 | ankerl::unordered_dense::map> m_pre_builtin_execute_callbacks; 16 | ankerl::unordered_dense::map> m_post_builtin_execute_callbacks; 17 | 18 | ankerl::unordered_dense::map> m_pre_script_execute_callbacks; 19 | ankerl::unordered_dense::map> m_post_script_execute_callbacks; 20 | }; 21 | 22 | class lua_module_ext : public lua_module 23 | { 24 | public: 25 | lua_module_data_ext m_data_ext; 26 | 27 | static auto get_PLUGIN_table(sol::environment& env) 28 | { 29 | return env["_PLUGIN"].get_or_create(); 30 | } 31 | 32 | private: 33 | void backcompat_init() 34 | { 35 | auto plugin_ns = get_PLUGIN_table(m_env); 36 | 37 | // Lua API: Field 38 | // Table: _ENV - Plugin Specific Global Table 39 | // Field: !guid: string 40 | // Guid of the mod. 41 | m_env["!guid"] = plugin_ns["guid"]; 42 | 43 | // Lua API: Field 44 | // Table: _ENV - Plugin Specific Global Table 45 | // Field: !config_mod_folder_path: string 46 | // Path to the mod folder inside `config` 47 | m_env["!config_mod_folder_path"] = plugin_ns["config_mod_folder_path"]; 48 | 49 | // Lua API: Field 50 | // Table: _ENV - Plugin Specific Global Table 51 | // Field: !plugins_data_mod_folder_path: string 52 | // Path to the mod folder inside `plugins_data` 53 | m_env["!plugins_data_mod_folder_path"] = plugin_ns["plugins_data_mod_folder_path"]; 54 | 55 | // Lua API: Field 56 | // Table: _ENV - Plugin Specific Global Table 57 | // Field: !plugins_mod_folder_path: string 58 | // Path to the mod folder inside `plugins` 59 | m_env["!plugins_mod_folder_path"] = plugin_ns["plugins_mod_folder_path"]; 60 | 61 | // Lua API: Field 62 | // Table: _ENV - Plugin Specific Global Table 63 | // Field: !this: lua_module* 64 | m_env["!this"] = this; 65 | } 66 | 67 | public: 68 | 69 | lua_module_ext(const module_info& module_info, sol::environment& env) : 70 | lua_module(module_info, env) 71 | { 72 | backcompat_init(); 73 | } 74 | 75 | lua_module_ext(const module_info& module_info, sol::state_view& state) : 76 | lua_module(module_info, state) 77 | { 78 | backcompat_init(); 79 | } 80 | 81 | inline void cleanup() override 82 | { 83 | lua_module::cleanup(); 84 | 85 | m_data_ext = {}; 86 | } 87 | }; 88 | } // namespace big 89 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "config/config.hpp" 2 | #include "gui/gui.hpp" 3 | #include "gui/renderer.hpp" 4 | #include "hooks/hooking.hpp" 5 | #include "logger/exception_handler.hpp" 6 | #include "lua/lua_manager.hpp" 7 | #include "lua/lua_manager_extension.hpp" 8 | #include "memory/byte_patch_manager.hpp" 9 | #include "paths/paths.hpp" 10 | #include "pointers.hpp" 11 | #include "rorr/gm/pin_map.hpp" 12 | #include "rorr/rorr_hooks.hpp" 13 | #include "threads/thread_pool.hpp" 14 | #include "threads/util.hpp" 15 | #include "version.hpp" 16 | 17 | //#include "debug/debug.hpp" 18 | 19 | BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) 20 | { 21 | using namespace big; 22 | 23 | if (reason == DLL_PROCESS_ATTACH) 24 | { 25 | bool use_steam = true; 26 | wchar_t exe_path[1024]; 27 | if (GetModuleFileNameW(nullptr, exe_path, sizeof(exe_path)) > 0) 28 | { 29 | std::filesystem::path steam_appid_file_path(exe_path); 30 | steam_appid_file_path = steam_appid_file_path.parent_path(); 31 | steam_appid_file_path /= "steam_appid.txt"; 32 | use_steam = !std::filesystem::exists(steam_appid_file_path); 33 | } 34 | 35 | if (use_steam) 36 | { 37 | const auto steam_env_env_var = _wgetenv(L"SteamEnv"); 38 | const std::wstring good_steam_env_var = L"1"; 39 | if (!steam_env_env_var || steam_env_env_var != good_steam_env_var) 40 | { 41 | return true; 42 | } 43 | } 44 | 45 | if (!rom::is_rom_enabled()) 46 | { 47 | return true; 48 | } 49 | 50 | rom::init("ReturnOfModding", "Risk of Rain Returns.exe", ""); 51 | 52 | // Purposely leak it, we are not unloading this module in any case. 53 | { 54 | auto exception_handling = new exception_handler(true, gm::triple_exception_handler); 55 | 56 | // SetUnhandledExceptionFilter is not working correctly it seems, 57 | // sometimes it's straight up not called even on unhandled exceptions. 58 | AddVectoredContinueHandler(true, gm::triple_exception_handler); 59 | } 60 | 61 | // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?view=msvc-170#utf-8-support 62 | setlocale(LC_ALL, ".utf8"); 63 | // This also change things like stringstream outputs and add comma to numbers and things like that, we don't want that, so just set locale on the C apis instead. 64 | //std::locale::global(std::locale(".utf8")); 65 | 66 | std::filesystem::path root_folder = paths::get_project_root_folder(); 67 | g_file_manager.init(root_folder); 68 | paths::init_dump_file_path(); 69 | 70 | big::config::init_general(); 71 | 72 | // Purposely leak it, we are not unloading this module in any case. 73 | auto logger_instance = new logger(rom::g_project_name, g_file_manager.get_project_file("./LogOutput.log")); 74 | 75 | static struct logger_cleanup 76 | { 77 | ~logger_cleanup() 78 | { 79 | Logger::Destroy(); 80 | } 81 | } g_logger_cleanup; 82 | 83 | std::srand(std::chrono::system_clock::now().time_since_epoch().count()); 84 | 85 | LOG(INFO) << rom::g_project_name; 86 | LOGF(INFO, "Build (GIT SHA1): {}", version::GIT_SHA1); 87 | 88 | #ifdef FINAL 89 | LOG(INFO) << "This is a final build"; 90 | #endif 91 | 92 | // Purposely leak it, we are not unloading this module in any case. 93 | auto thread_pool_instance = new thread_pool(); 94 | LOG(INFO) << "Thread pool initialized."; 95 | 96 | // Purposely leak it, we are not unloading this module in any case. 97 | auto pointers_instance = new pointers(); 98 | LOG(INFO) << "Pointers initialized."; 99 | 100 | LOG(INFO) << "GameMaker Major Version: " << *g_pointers->m_rorr.m_gamemaker_version_major << " (Found at offset " 101 | << HEX_TO_UPPER_OFFSET(g_pointers->m_rorr.m_gamemaker_version_major) << ")"; 102 | 103 | // Purposely leak it, we are not unloading this module in any case. 104 | auto byte_patch_manager_instance = new byte_patch_manager(); 105 | LOG(INFO) << "Byte Patch Manager initialized."; 106 | 107 | rorr::init_hooks(); 108 | 109 | // Purposely leak it, we are not unloading this module in any case. 110 | auto hooking_instance = new hooking(); 111 | LOG(INFO) << "Hooking initialized."; 112 | 113 | hotkey::init_hotkeys(); 114 | 115 | g_hooking->enable(); 116 | LOG(INFO) << "Hooking enabled."; 117 | 118 | DisableThreadLibraryCalls(hmod); 119 | g_hmodule = hmod; 120 | g_main_thread = CreateThread( 121 | nullptr, 122 | 0, 123 | [](PVOID) -> DWORD 124 | { 125 | while (g_running) 126 | { 127 | std::this_thread::sleep_for(500ms); 128 | } 129 | 130 | CloseHandle(g_main_thread); 131 | FreeLibraryAndExitThread(g_hmodule, 0); 132 | }, 133 | nullptr, 134 | 0, 135 | &g_main_thread_id); 136 | } 137 | 138 | return true; 139 | } 140 | -------------------------------------------------------------------------------- /src/pointers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "file_manager/cache_file.hpp" 3 | #include "memory/batch.hpp" 4 | #include "memory/byte_patch.hpp" 5 | #include "memory/module.hpp" 6 | #include "rorr/rorr_pointers.hpp" 7 | #include "string/compile_time_str.hpp" 8 | 9 | namespace big 10 | { 11 | class pointers 12 | { 13 | private: 14 | template 15 | void write_to_cache_or_read_from_cache(cache_file& cache_file, const memory::module& mem_region) 16 | { 17 | static_assert(batch_hash > 0); 18 | 19 | constexpr size_t field_count = (offset_of_cache_end_field - offset_of_cache_begin_field) / sizeof(void*); 20 | constexpr auto cache_version = batch_hash + field_count; 21 | 22 | cache_file.set_cache_version(cache_version); 23 | 24 | const uintptr_t pointer_to_cacheable_data_start = reinterpret_cast(this) + offset_of_cache_begin_field; 25 | 26 | if (!is_pointers_cache_up_to_date(cache_file, mem_region)) 27 | { 28 | run_batch(batch, mem_region); 29 | 30 | const uintptr_t pointer_to_cacheable_data_end = reinterpret_cast(this) + offset_of_cache_end_field; 31 | write_pointers_to_cache(cache_file, pointer_to_cacheable_data_start, pointer_to_cacheable_data_end, mem_region); 32 | } 33 | else 34 | { 35 | load_pointers_from_cache(cache_file, pointer_to_cacheable_data_start, mem_region); 36 | } 37 | 38 | cache_file.free_data(); 39 | } 40 | 41 | void load_pointers_from_cache(const cache_file& cache_file, const uintptr_t pointer_to_cacheable_data_start, const memory::module& mem_region); 42 | 43 | template 44 | void write_pointers_to_cache(cache_file& cache_file, const uintptr_t pointer_to_cacheable_data_start, const uintptr_t pointer_to_cacheable_data_end, const memory::module& mem_region) 45 | { 46 | constexpr size_t data_size = offset_of_cache_end_field - offset_of_cache_begin_field; 47 | 48 | cache_data cache_data_ptr = std::make_unique(data_size); 49 | 50 | // multiple things here: 51 | // - iterate each cacheable field of the pointers instance 52 | // - substract the base module address so that we only keep the offsets 53 | // - save that to the cache 54 | uintptr_t* cache_data = reinterpret_cast(cache_data_ptr.get()); 55 | 56 | size_t i = 0; 57 | for (uintptr_t field_ptr = pointer_to_cacheable_data_start; field_ptr != pointer_to_cacheable_data_end; field_ptr += sizeof(uintptr_t)) 58 | { 59 | const uintptr_t field_value = *reinterpret_cast(field_ptr); 60 | 61 | if (mem_region.contains(memory::handle(field_value))) 62 | { 63 | const uintptr_t offset = field_value - mem_region.begin().as(); 64 | cache_data[i] = offset; 65 | } 66 | else 67 | { 68 | LOG(ERROR) << "Just tried to save to cache a pointer supposedly within the " << batch_name.str << " module range but isn't! Offset from start of pointers instance: " << (field_ptr - reinterpret_cast(this)); 69 | } 70 | 71 | i++; 72 | } 73 | 74 | LOG(INFO) << "Pointers cache: saved " << (data_size / sizeof(uintptr_t)) << " fields to the cache"; 75 | 76 | cache_file.set_data(std::move(cache_data_ptr), data_size); 77 | 78 | cache_file.set_header_version(mem_region.size()); 79 | cache_file.write(); 80 | } 81 | 82 | template 83 | bool is_pointers_cache_up_to_date(cache_file& cache_file, const memory::module& mem_region) 84 | { 85 | cache_file.load(); 86 | 87 | if (cache_file.up_to_date(mem_region.size())) 88 | { 89 | LOG(INFO) << batch_name.str << " pointers cache is up to date, using it."; 90 | 91 | return true; 92 | } 93 | 94 | return false; 95 | } 96 | 97 | static constexpr auto get_rorr_batch(); 98 | 99 | template 100 | void run_batch(const memory::batch& batch, const memory::module& mem_region) 101 | { 102 | if (!memory::batch_runner::run_sync(batch, mem_region)) 103 | { 104 | LOG(ERROR) << "Failed to find some patterns for " << batch_name.str; 105 | } 106 | } 107 | 108 | public: 109 | explicit pointers(); 110 | ~pointers(); 111 | 112 | private: 113 | cache_file m_rorr_pointers_cache; 114 | 115 | public: 116 | rorr_pointers m_rorr; 117 | }; 118 | 119 | inline pointers* g_pointers{}; 120 | } // namespace big 121 | -------------------------------------------------------------------------------- /src/resources.rc: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | 3 | 1 VERSIONINFO 4 | FILEVERSION 1,0,0 5 | BEGIN 6 | BLOCK "StringFileInfo" 7 | BEGIN 8 | BLOCK "040904b0" 9 | BEGIN 10 | VALUE "CompanyName", "ReturnOfModding\0" 11 | VALUE "FileDescription", "Lua Mod Loader for Risk of Rain Returns\0" 12 | VALUE "InternalName", "version\0" 13 | VALUE "OriginalFilename", "version.dll\0" 14 | VALUE "ProductName", "ReturnOfModding\0" 15 | VALUE "ProductVersion", "1.0.0" "\0" 16 | END 17 | END 18 | 19 | BLOCK "VarFileInfo" 20 | BEGIN 21 | VALUE "Translation", 0x409, 1200 22 | END 23 | END 24 | 25 | // clang-format on 26 | -------------------------------------------------------------------------------- /src/rorr/gm/CCode.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "RToken.hpp" 3 | #include "RValue.hpp" 4 | #include "VMBuffer.hpp" 5 | 6 | struct YYGMLFuncs; 7 | 8 | struct CCode 9 | { 10 | int (**_vptr$CCode)(void); 11 | CCode* m_pNext; 12 | int i_kind; 13 | int i_compiled; 14 | const char* i_str; 15 | RToken i_token; 16 | RValue i_value; 17 | VMBuffer* i_pVM; 18 | VMBuffer* i_pVMDebugInfo; 19 | char* i_pCode; 20 | const char* name; 21 | int index; 22 | YYGMLFuncs* i_pFunc; 23 | bool i_watch; 24 | int i_offset; 25 | int i_locals; 26 | int i_args; 27 | int i_flags; 28 | YYObjectBase* i_pPrototype; 29 | 30 | inline const char* GetText() 31 | { 32 | return this->i_str; 33 | } 34 | 35 | inline YYObjectBase* GetStatic() 36 | { 37 | return this->i_pPrototype; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /src/rorr/gm/CHashMap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MurMurHash.hpp" 4 | 5 | struct YYObjectBase; 6 | 7 | template 8 | struct CHashMap 9 | { 10 | int m_curSize; 11 | int m_numUsed; 12 | int m_curMask; 13 | int m_growThreshold; 14 | 15 | struct CElement 16 | { 17 | Value v; 18 | Key k; 19 | unsigned int Hash; 20 | }* m_pBuckets; 21 | 22 | bool FindElement(int hHash, Value& outValue) 23 | { 24 | int nIdealPos = m_curMask & hHash & 0x7f'ff'ff'ff; 25 | 26 | for (CElement node = m_pBuckets[nIdealPos]; node.Hash != 0; node = m_pBuckets[(++nIdealPos) & m_curMask & 0x7f'ff'ff'ff]) 27 | { 28 | if (node.Hash == hHash) 29 | { 30 | outValue = node.v; 31 | return true; 32 | } 33 | } 34 | return false; 35 | } 36 | 37 | static unsigned int CalculateHash(int val) 38 | { 39 | return 0x9E'37'79'B1U * (unsigned int)val + 1; 40 | } 41 | 42 | static unsigned int CalculateHash(void* val) 43 | { 44 | return ((signed int)val >> 8) + 1; 45 | } 46 | 47 | static unsigned int CalculateHash(YYObjectBase* val) 48 | { 49 | return 7 * ((signed int)val >> 6) + 1; 50 | } 51 | 52 | static unsigned int CalculateHash(const char* val, size_t Len) 53 | { 54 | return Utils::Hash::MurMurHash((const unsigned char*)val, Len, 0); 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /src/rorr/gm/CInstance.cpp: -------------------------------------------------------------------------------- 1 | #include "CInstance.hpp" 2 | 3 | #include "Code_Function_GET_the_function.hpp" 4 | 5 | void CInstance::imgui_dump() 6 | { 7 | ImGui::Text("Instance ID: %d", id); 8 | ImGui::Text("Position: %.2f, %.2f", x, y); 9 | ImGui::Text("Gravity: %.2f (Direction: %.2f)", gravity, gravity_direction); 10 | ImGui::Text("Speed: %.2f", speed); 11 | ImGui::Text("Object Name: %s (Index: %d) ", object_name().c_str(), object_index); 12 | 13 | const auto sprite_name = gm::call("sprite_get_name", sprite_index); 14 | if (sprite_name.type == RValueType::STRING) 15 | { 16 | ImGui::Text("Sprite Name: %s (Index: %d) ", sprite_name.ref_string->m_thing, sprite_index); 17 | } 18 | 19 | const auto layer_name = gm::call("layer_get_name", layer); 20 | if (layer_name.type == RValueType::STRING) 21 | { 22 | ImGui::Text("Layer Name: %s (Index: %d) ", layer_name.ref_string->m_thing, layer); 23 | } 24 | 25 | ImGui::Text("Depth: %.2f | %.2f", depth, i_currentdepth); 26 | } 27 | 28 | void CInstance::imgui_dump_instance_variables() 29 | { 30 | RValue instance_variable_names = gm::call("variable_instance_get_names", id); 31 | ImGui::Text("Var Count: %d", instance_variable_names.ref_array->length); 32 | ImGui::Text("Ref Count: %d", instance_variable_names.ref_array->m_refCount); 33 | ImGui::Text("Flags: %d", instance_variable_names.ref_array->m_flags); 34 | ImGui::Text("Owner: %d", instance_variable_names.ref_array->m_Owner); 35 | ImGui::Text("Visited: %d", instance_variable_names.ref_array->visited); 36 | for (int i = 0; i < instance_variable_names.ref_array->length; i++) 37 | { 38 | if (instance_variable_names.ref_array->m_Array[i].type == RValueType::STRING) 39 | { 40 | const auto& var_name = instance_variable_names.ref_array->m_Array[i].ref_string->m_thing; 41 | ImGui::Text("%d: %s (Ref: %d)", i, var_name, instance_variable_names.ref_array->m_Array[i].ref_string->m_refCount); 42 | ImGui::SameLine(); 43 | static ankerl::unordered_dense::map> var_to_input_texts; 44 | ImGui::InputText(std::format("##{}", var_name).c_str(), var_to_input_texts[var_name].data(), 256); 45 | ImGui::SameLine(); 46 | if (ImGui::Button(std::format("SAVE ##btn{}", var_name).c_str())) 47 | { 48 | gm::call("variable_instance_set", 49 | std::to_array({id, var_name, std::stod(var_to_input_texts[var_name].data())})); 50 | } 51 | } 52 | } 53 | } 54 | 55 | static ankerl::unordered_dense::map object_index_to_name; 56 | static std::string dummy; 57 | 58 | const std::string& CInstance::object_name() const 59 | { 60 | if (!object_index_to_name.contains(object_index)) 61 | { 62 | const auto object_name = gm::call("object_get_name", object_index); 63 | if (object_name.type == RValueType::STRING) 64 | { 65 | object_index_to_name[object_index] = object_name.ref_string->m_thing; 66 | return object_index_to_name[object_index]; 67 | } 68 | } 69 | else 70 | { 71 | return object_index_to_name[object_index]; 72 | } 73 | 74 | return dummy; 75 | } 76 | -------------------------------------------------------------------------------- /src/rorr/gm/CInstance.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "YYObjectBase.hpp" 4 | 5 | struct CInstance : YYObjectBase 6 | { 7 | __int64 m_CreateCounter; 8 | void* m_pObject; 9 | void* m_pPhysicsObject; 10 | void* m_pSkeletonAnimation; 11 | void* m_pControllingSeqInst; 12 | unsigned int m_Instflags; 13 | int id; 14 | int object_index; 15 | int sprite_index; 16 | float i_sequencePos; 17 | float i_lastSequencePos; 18 | float i_sequenceDir; 19 | float image_index; 20 | float image_speed; 21 | float image_xscale; 22 | float image_yscale; 23 | float image_angle; 24 | float image_alpha; 25 | unsigned int image_blend; 26 | float x; 27 | float y; 28 | float xstart; 29 | float ystart; 30 | float xprevious; 31 | float yprevious; 32 | float direction; 33 | float speed; 34 | float friction; 35 | float gravity_direction; 36 | float gravity; 37 | float hspeed; 38 | float vspeed; 39 | int bbox[4]; 40 | int timer[12]; 41 | void* m_pPathAndTimeline; 42 | CCode* i_initcode; 43 | CCode* i_precreatecode; 44 | void* m_pOldObject; 45 | int layer; 46 | int mask_index; 47 | __int16 m_nMouseOver; 48 | CInstance* m_pNext; 49 | CInstance* m_pPrev; 50 | void* m_collisionLink[3]; // SLink 51 | void* m_dirtyLink[3]; // SLink 52 | void* m_withLink[3]; // SLink 53 | float depth; 54 | float i_currentdepth; 55 | float i_lastImageNumber; 56 | unsigned int m_collisionTestNumber; 57 | 58 | void imgui_dump(); 59 | 60 | void imgui_dump_instance_variables(); 61 | 62 | const std::string& object_name() const; 63 | 64 | RValue get(const char* variable_name); 65 | bool get_bool(const char* variable_name); 66 | double get_double(const char* variable_name); 67 | std::string get_string(const char* variable_name); 68 | 69 | void set(const char* variable_name, RValue& new_value); 70 | void set_bool(const char* variable_name, bool new_value); 71 | void set_double(const char* variable_name, double new_value); 72 | void set_string(const char* variable_name, const char* new_value); 73 | }; 74 | -------------------------------------------------------------------------------- /src/rorr/gm/CInstance_hooks.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CInstance.hpp" 4 | #include "hooks/hooking.hpp" 5 | 6 | namespace gm 7 | { 8 | inline std::recursive_mutex CInstance_containers_mutex; 9 | inline std::vector CInstances_all; 10 | inline std::vector CInstances_active; 11 | inline ankerl::unordered_dense::map CInstance_id_to_CInstance; 12 | 13 | using CInstance_ctor = CInstance* (*)(CInstance* this_, float a2, float a3, int a4, int a5, bool a6); 14 | 15 | inline CInstance* hook_CInstance_ctor(CInstance* this_, float a2, float a3, int a4, int a5, bool a6) 16 | { 17 | std::lock_guard lock(CInstance_containers_mutex); 18 | 19 | auto* res = big::g_hooking->get_original()(this_, a2, a3, a4, a5, a6); 20 | 21 | CInstances_all.push_back(res); 22 | 23 | CInstance_id_to_CInstance[res->id] = res; 24 | 25 | return res; 26 | } 27 | 28 | using CInstance_dctor = void* (*)(CInstance* this_); 29 | 30 | inline void* hook_CInstance_dctor(CInstance* this_) 31 | { 32 | std::lock_guard lock(CInstance_containers_mutex); 33 | 34 | std::erase_if(CInstances_all, 35 | [=](CInstance* other) 36 | { 37 | return this_ == other; 38 | }); 39 | 40 | CInstance_id_to_CInstance.erase(this_->id); 41 | 42 | auto* res = big::g_hooking->get_original()(this_); 43 | 44 | return res; 45 | } 46 | 47 | using CObjectGM_AddInstance = void (*)(void* CObjectGM_this, CInstance* real_this); 48 | 49 | inline void hook_CObjectGM_AddInstance(void* CObjectGM_this, CInstance* real_this) 50 | { 51 | big::g_hooking->get_original()(CObjectGM_this, real_this); 52 | 53 | CInstances_active.push_back(real_this); 54 | } 55 | 56 | using CObjectGM_RemoveInstance = void (*)(void* CObjectGM_this, CInstance* real_this); 57 | 58 | inline void hook_CObjectGM_RemoveInstance(void* CObjectGM_this, CInstance* real_this) 59 | { 60 | std::erase_if(CInstances_active, 61 | [=](CInstance* other) 62 | { 63 | return real_this == other; 64 | }); 65 | 66 | big::g_hooking->get_original()(CObjectGM_this, real_this); 67 | } 68 | } // namespace gm 69 | -------------------------------------------------------------------------------- /src/rorr/gm/CRoom.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gm 4 | { 5 | struct CRoom 6 | { 7 | char unk[216]; 8 | CInstance* instances; 9 | }; 10 | 11 | static constexpr auto blaaaaaqsdlksf = offsetof(CRoom, instances); 12 | 13 | //static constexpr auto dflmgdflgklmdfgk = offsetof(CInstance, m_pPrev); 14 | } // namespace gm 15 | -------------------------------------------------------------------------------- /src/rorr/gm/CScript.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct CStream 4 | { 5 | bool m_ReadOnly; 6 | int internal_buffer_size; 7 | int internal_current_position; 8 | void* internal_buffer; 9 | }; 10 | 11 | struct CCode; 12 | struct YYGMLFuncs; 13 | struct CInstance; 14 | 15 | struct CScript 16 | { 17 | int (**_vptr$CScript)(void); 18 | CCode* m_code; 19 | YYGMLFuncs* m_funcs; 20 | CInstance* m_static_object; 21 | 22 | union 23 | { 24 | const char* m_script; 25 | int m_compiled_index; 26 | }; 27 | 28 | const char* m_script_name; // example: gml_Script_init_player 29 | int m_offset; 30 | }; 31 | -------------------------------------------------------------------------------- /src/rorr/gm/CScriptRef.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "YYObjectBase.hpp" 4 | 5 | struct CScript; 6 | 7 | class CScriptRef : public YYObjectBase 8 | { 9 | private: 10 | void* m_unk; 11 | void* m_unk2; 12 | void* m_unk3; 13 | void* m_unk4; 14 | void* m_unk5; 15 | void* m_unk6; 16 | void* m_unk7; 17 | 18 | public: 19 | CScript* m_call_script; 20 | }; 21 | -------------------------------------------------------------------------------- /src/rorr/gm/Code_Execute.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CCode.hpp" 3 | #include "CInstance.hpp" 4 | 5 | namespace gm 6 | { 7 | using Code_Execute = bool (*)(CInstance* self, CInstance* other, CCode* code, RValue* a4, int a5); 8 | } 9 | -------------------------------------------------------------------------------- /src/rorr/gm/Code_Execute_hook.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Code_Execute_trace.hpp" 3 | #include "Code_Function_GET_the_function.hpp" 4 | 5 | #include 6 | #include 7 | 8 | static void* lua_custom_alloc(void* ud, void* ptr, size_t osize, size_t nsize) 9 | { 10 | (void)ud; 11 | (void)osize; 12 | if (nsize == 0) 13 | { 14 | //mi_free(ptr); 15 | free(ptr); 16 | return NULL; 17 | } 18 | else 19 | { 20 | //return mi_realloc_aligned(ptr, nsize, 16); 21 | return realloc(ptr, nsize); 22 | } 23 | } 24 | 25 | namespace gm 26 | { 27 | inline bool g_is_gml_safe_to_init = false; 28 | 29 | inline void init_lua_manager() 30 | { 31 | if (!big::g_abort) 32 | { 33 | YYObjectPinMap::init_pin_map(); 34 | } 35 | 36 | big::g_running = true; 37 | 38 | lua_State* L = lua_newstate(lua_custom_alloc, NULL); 39 | //lua_State* L = luaL_newstate(); 40 | 41 | // Purposely leak it, we are not unloading this module in any case. 42 | auto lua_manager_instance = new big::lua_manager(L, 43 | big::g_file_manager.get_project_folder("config"), 44 | big::g_file_manager.get_project_folder("plugins_data"), 45 | big::g_file_manager.get_project_folder("plugins"), 46 | [](sol::state_view& state, sol::table& lua_ext) 47 | { 48 | big::lua_manager_extension::init_lua_api(state, lua_ext); 49 | }); 50 | sol::state_view sol_state_view(L); 51 | big::lua_manager_extension::init_lua_base(sol_state_view); 52 | lua_manager_instance->init(true); 53 | LOG(INFO) << "Lua manager initialized."; 54 | 55 | if (big::g_abort) 56 | { 57 | LOG(ERROR) << "ReturnOfModding failed to init properly, exiting."; 58 | big::g_running = false; 59 | } 60 | } 61 | 62 | inline bool hook_Code_Execute(CInstance* self, CInstance* other, CCode* code, RValue* result, int flags) 63 | { 64 | g_last_code_execute = code->name; 65 | 66 | bool no_error = true; 67 | if (big::g_lua_manager) 68 | { 69 | const auto call_orig_if_true = big::lua_manager_extension::pre_code_execute(self, other, code, result, flags); 70 | 71 | if (call_orig_if_true) 72 | { 73 | __try 74 | { 75 | no_error = big::g_hooking->get_original()(self, other, code, result, flags); 76 | } 77 | __except (triple_exception_handler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) 78 | { 79 | } 80 | } 81 | 82 | big::lua_manager_extension::post_code_execute(self, other, code, result, flags); 83 | } 84 | else 85 | { 86 | __try 87 | { 88 | no_error = big::g_hooking->get_original()(self, other, code, result, flags); 89 | } 90 | __except (double_exception_handler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) 91 | { 92 | } 93 | } 94 | 95 | if (!g_is_gml_safe_to_init && big::string::starts_with("gml_Object_oInit_Alarm_", code->name)) 96 | { 97 | g_is_gml_safe_to_init = true; 98 | 99 | init_lua_manager(); 100 | } 101 | 102 | g_last_code_execute = nullptr; 103 | return no_error; 104 | } 105 | } // namespace gm 106 | -------------------------------------------------------------------------------- /src/rorr/gm/Code_Execute_trace.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gm 4 | { 5 | inline const char* g_last_code_execute = nullptr; 6 | 7 | inline const char* g_last_call = nullptr; 8 | } // namespace gm 9 | -------------------------------------------------------------------------------- /src/rorr/gm/Code_Function_GET_the_function_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gm 4 | { 5 | using TRoutine = void(__cdecl*)(RValue* _result, CInstance* _self, CInstance* _other, int _argc, RValue* _args); 6 | 7 | using Code_Function_GET_the_function_t = void (*)(int index, const char** out_function_name, TRoutine* out_function_pointer, int* out_function_arg_count); 8 | } // namespace gm 9 | -------------------------------------------------------------------------------- /src/rorr/gm/EJSRetValBool.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class EJSRetValBool 4 | { 5 | EJSRVB_FALSE, 6 | EJSRVB_TRUE, 7 | EJSRVB_TYPE_ERROR 8 | }; 9 | -------------------------------------------------------------------------------- /src/rorr/gm/EVariableType.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum EVariableType : int 4 | { 5 | SELF = -1, 6 | OTHER = -2, 7 | ALL = -3, 8 | NOONE = -4, 9 | GLOBAL = -5, 10 | BUILTIN = -6, 11 | LOCAL = -7, 12 | STACKTOP = -9, 13 | ARGUMENT = -15, 14 | }; 15 | -------------------------------------------------------------------------------- /src/rorr/gm/GetSaveFileName_hook.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GetSaveFileName_t.hpp" 3 | 4 | namespace gm 5 | { 6 | inline bool hook_GetSaveFileName(char* output_path, __int64 size_of_output_path, const char* input_path) 7 | { 8 | try 9 | { 10 | const auto file_path = std::filesystem::path(input_path); 11 | 12 | // Fix ReturnOfModding paths getting fucked by the game sandbox. 13 | if (strstr((char*)file_path.u8string().c_str(), "ReturnOfModding")) 14 | { 15 | strcpy(output_path, input_path); 16 | 17 | return 0; 18 | } 19 | } 20 | catch (const std::exception& e) 21 | { 22 | LOG(ERROR) << e.what(); 23 | } 24 | catch (...) 25 | { 26 | LOG(ERROR) << "Unknown exception"; 27 | } 28 | 29 | const auto res = big::g_hooking->get_original()(output_path, size_of_output_path, input_path); 30 | 31 | return res; 32 | } 33 | } // namespace gm 34 | -------------------------------------------------------------------------------- /src/rorr/gm/GetSaveFileName_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gm 4 | { 5 | using GetSaveFileName_t = __int64 (*)(char *output_path, __int64 size_of_output_path, const char *input_path); 6 | } // namespace gm 7 | -------------------------------------------------------------------------------- /src/rorr/gm/MemoryManager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace gm 6 | { 7 | namespace MemoryManager 8 | { 9 | using ReAlloc = void* (*)(void* Block, std::size_t Size); 10 | using Free = void (*)(void* Block); 11 | using Alloc = void*(*)(size_t Size, const char * a1, int64_t a2, bool zero_fill);// a1 and a2 seem useless 12 | } // namespace MemoryManager 13 | } // namespace gm 14 | -------------------------------------------------------------------------------- /src/rorr/gm/MurMurHash.cpp: -------------------------------------------------------------------------------- 1 | #include "MurMurHash.hpp" 2 | 3 | #include 4 | 5 | using uint32_t = unsigned int; 6 | 7 | uint32_t Utils::Hash::MurMurHash(const unsigned char* key, int len, uint32_t seed) 8 | { 9 | uint32_t c1 = 0xcc'9e'2d'51; 10 | uint32_t c2 = 0x1b'87'35'93; 11 | uint32_t r1 = 15; 12 | uint32_t r2 = 13; 13 | uint32_t m = 5; 14 | uint32_t n = 0xe6'54'6b'64; 15 | uint32_t h = 0; 16 | uint32_t k = 0; 17 | uint8_t* d = (uint8_t*)key; 18 | const uint32_t* chunks = NULL; 19 | const uint8_t* tail = NULL; 20 | int i = 0; 21 | int l = len / 4; 22 | 23 | h = seed; 24 | 25 | chunks = (const uint32_t*)(d + l * 4); 26 | tail = (const uint8_t*)(d + l * 4); 27 | 28 | for (i = -l; i != 0; ++i) 29 | { 30 | k = chunks[i]; 31 | 32 | k *= c1; 33 | k = (k << r1) | (k >> (32 - r1)); 34 | k *= c2; 35 | 36 | h ^= k; 37 | h = (h << r2) | (h >> (32 - r2)); 38 | h = h * m + n; 39 | } 40 | 41 | k = 0; 42 | 43 | switch (len & 3) 44 | { 45 | case 3: k ^= (tail[2] << 16); 46 | case 2: k ^= (tail[1] << 8); 47 | 48 | case 1: 49 | k ^= tail[0]; 50 | k *= c1; 51 | k = (k << r1) | (k >> (32 - r1)); 52 | k *= c2; 53 | h ^= k; 54 | } 55 | 56 | h ^= len; 57 | 58 | h ^= (h >> 16); 59 | h *= 0x85'eb'ca'6b; 60 | h ^= (h >> 13); 61 | h *= 0xc2'b2'ae'35; 62 | h ^= (h >> 16); 63 | 64 | return h; 65 | } 66 | -------------------------------------------------------------------------------- /src/rorr/gm/MurMurHash.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | //https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp 3 | #include 4 | 5 | namespace Utils 6 | { 7 | namespace Hash 8 | { 9 | uint32_t MurMurHash(const unsigned char* key, int len, uint32_t seed); 10 | } 11 | } // namespace Utils 12 | -------------------------------------------------------------------------------- /src/rorr/gm/RToken.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RValue.hpp" 4 | 5 | struct RToken 6 | { 7 | int kind; 8 | unsigned int type; 9 | int ind; 10 | int ind2; 11 | RValue value; 12 | int itemnumb; 13 | RToken* items; 14 | int position; 15 | }; 16 | -------------------------------------------------------------------------------- /src/rorr/gm/RValue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "YYObjectBase.hpp" 4 | 5 | #include 6 | 7 | struct vec3 8 | { 9 | float x, y, z; 10 | }; 11 | 12 | struct vec4 13 | { 14 | float x, y, z, w; 15 | }; 16 | 17 | struct matrix44 18 | { 19 | vec4 m[4]; 20 | }; 21 | 22 | constexpr int MASK_TYPE_RVALUE = 0x0'ff'ff'ff; 23 | 24 | enum RValueType : int 25 | { 26 | REAL = 0, 27 | STRING = 1, 28 | ARRAY = 2, 29 | PTR = 3, 30 | VEC3 = 4, 31 | UNDEFINED = 5, 32 | OBJECT = 6, 33 | _INT32 = 7, 34 | VEC4 = 8, 35 | MATRIX = 9, 36 | _INT64 = 10, 37 | ACCESSOR = 11, 38 | JSNULL = 12, 39 | _BOOL = 13, 40 | ITERATOR = 14, 41 | REF = 15, 42 | UNSET = MASK_TYPE_RVALUE 43 | }; 44 | 45 | typedef YYObjectBase* (*GetCtxStackTop)(void); 46 | typedef void (*DetPotRoot)(YYObjectBase* _pContainer, YYObjectBase* _yy_object_baseect); 47 | //extern GetCtxStackTop GetContextStackTop; 48 | //extern DetPotRoot DeterminePotentialRoot; 49 | 50 | struct RValue; 51 | typedef void (*FREE_RVal_Pre)(RValue* p); 52 | typedef void (*COPY_RValue_do__Post_t)(RValue* dest, RValue* src); 53 | typedef void (*YYSetStr)(RValue* _pVal, const char* _pS); 54 | typedef void (*YYCreStr)(RValue* _pVal, const char* _pS); 55 | typedef char* (*YYDupStr)(const char* _pStr); 56 | typedef RValue* (*ARRAYLVal)(RValue* _pV, int _index); 57 | 58 | #define YYC_DELETE(a) delete a 59 | 60 | class YYObjectBase; 61 | 62 | template 63 | struct _RefFactory 64 | { 65 | static T Alloc(T _thing, int _size) 66 | { 67 | return _thing; 68 | } 69 | 70 | static T Create(T _thing, int& _size) 71 | { 72 | _size = 0; 73 | return _thing; 74 | } 75 | 76 | static T Destroy(T _thing) 77 | { 78 | return _thing; 79 | } 80 | }; 81 | 82 | template 83 | struct _RefThing 84 | { 85 | T m_thing; 86 | int m_refCount; 87 | int m_size; 88 | 89 | _RefThing(T _thing) 90 | { 91 | // this needs to have some sort of factory based on the type to do a duplicate 92 | m_thing = _RefFactory::Create(_thing, m_size); 93 | m_refCount = 0; 94 | inc(); 95 | } 96 | 97 | _RefThing(int _maxSize) 98 | { 99 | // this needs to have some sort of factory based on the type to do a duplicate 100 | m_thing = _RefFactory::Alloc(m_thing, _maxSize); 101 | m_size = _maxSize; 102 | m_refCount = 0; 103 | inc(); 104 | } 105 | 106 | ~_RefThing() 107 | { 108 | dec(); 109 | } 110 | 111 | void inc() 112 | { 113 | ++m_refCount; 114 | } 115 | 116 | void dec() 117 | { 118 | --m_refCount; 119 | if (m_refCount == 0) 120 | { 121 | // use the factory to clean it up and give us a default thing to use 122 | m_thing = _RefFactory::Destroy(m_thing); 123 | m_size = 0; 124 | 125 | YYC_DELETE(this); 126 | } 127 | } 128 | 129 | T get() const 130 | { 131 | return m_thing; 132 | } 133 | 134 | int size() const 135 | { 136 | return m_size; 137 | } 138 | 139 | static _RefThing* assign(_RefThing* _other) 140 | { 141 | if (_other != nullptr) 142 | { 143 | _other->inc(); 144 | } 145 | 146 | return _other; 147 | } 148 | 149 | static _RefThing* remove(_RefThing* _other) 150 | { 151 | if (_other != nullptr) 152 | { 153 | _other->dec(); 154 | } 155 | 156 | return nullptr; 157 | } 158 | }; 159 | 160 | typedef _RefThing RefString; 161 | 162 | struct RefDynamicArrayOfRValue; 163 | 164 | #pragma pack(push, 4) 165 | 166 | struct DValue 167 | { 168 | union 169 | { 170 | int64_t __64; 171 | void* __ptr; 172 | RefDynamicArrayOfRValue* __arr; 173 | YYObjectBase* __obj; 174 | }; 175 | 176 | unsigned int flags; 177 | unsigned int type; 178 | }; 179 | 180 | struct RValue 181 | { 182 | union 183 | { 184 | // values. 185 | int i32; 186 | long long i64; 187 | double value; 188 | 189 | // pointers. 190 | void* ptr; 191 | RefString* ref_string; 192 | RefDynamicArrayOfRValue* ref_array; 193 | YYObjectBase* yy_object_base; 194 | vec4* vec4; 195 | matrix44* matrix44; 196 | }; 197 | 198 | // use for flags (Hijack for Enumerable and Configurable bits in JavaScript) 199 | int flags; 200 | // kind of value 201 | RValueType type; 202 | 203 | void __localFree(void); 204 | void __localCopy(const RValue& v); 205 | 206 | ~RValue(); 207 | 208 | RValue(); 209 | RValue(const RValue& v); 210 | 211 | RValue(double v); 212 | RValue(float v); 213 | RValue(int v); 214 | RValue(long long v); 215 | RValue(bool v); 216 | RValue(std::nullptr_t); 217 | RValue(std::nullptr_t, bool undefined); 218 | RValue(void* v); 219 | RValue(YYObjectBase* obj); 220 | RValue(RefDynamicArrayOfRValue* arr); 221 | RValue(const char* v); 222 | RValue(std::string v); 223 | RValue(std::wstring v); 224 | 225 | RValue operator-(); 226 | RValue operator+(); 227 | 228 | RValue& operator=(const RValue& v); 229 | RValue& operator=(double v); 230 | RValue& operator=(float v); 231 | RValue& operator=(int v); 232 | RValue& operator=(long long v); 233 | RValue& operator=(void* v); 234 | RValue& operator=(bool v); 235 | RValue& operator=(const char* v); 236 | RValue& operator=(std::string v); 237 | RValue& operator=(std::wstring v); 238 | 239 | RValue& operator++(); 240 | RValue operator++(int); 241 | 242 | RValue& operator--(); 243 | RValue operator--(int); 244 | 245 | bool operator==(const RValue& rhs) const; 246 | bool operator!=(const RValue& rhs) const; 247 | 248 | RValue* DoArrayIndex(const int _index); 249 | RValue* operator[](const int _index); 250 | 251 | std::string asString(); 252 | double asReal() const; 253 | int asInt32() const; 254 | bool asBoolean() const; 255 | long long asInt64() const; 256 | void* asPointer() const; 257 | YYObjectBase* asObject() const; 258 | bool isNumber() const; 259 | bool isUnset() const; 260 | bool isArray() const; 261 | 262 | operator double() const; 263 | operator int() const; 264 | operator long long() const; 265 | operator bool() const; 266 | operator std::string(); 267 | operator void*() const; 268 | }; 269 | 270 | #pragma pack(pop) 271 | 272 | struct RefDynamicArrayOfRValue : YYObjectBase 273 | { 274 | int m_refCount; 275 | int m_flags; // flag set = is readonly for example 276 | RValue* m_Array; 277 | void* m_Owner; 278 | int visited; 279 | int length; 280 | 281 | using value_type = RValue; 282 | using iterator = RValue*; 283 | using reference = RValue&; 284 | using size_type = int; 285 | 286 | iterator begin() 287 | { 288 | return iterator(m_Array); 289 | } 290 | 291 | iterator end() 292 | { 293 | return iterator(m_Array + length); 294 | } 295 | 296 | size_type size() const noexcept 297 | { 298 | return length; 299 | } 300 | 301 | size_type max_size() const noexcept 302 | { 303 | return length; 304 | } 305 | 306 | bool empty() const noexcept 307 | { 308 | return length == 0; 309 | } 310 | }; 311 | 312 | // 136 313 | static constexpr auto RefDynamicArrayOfRValue_offset_ref_count = offsetof(RefDynamicArrayOfRValue, m_refCount); 314 | // 144 315 | static constexpr auto RefDynamicArrayOfRValue_offset_array = offsetof(RefDynamicArrayOfRValue, m_Array); 316 | // 152 317 | static constexpr auto RefDynamicArrayOfRValue_offset_owner = offsetof(RefDynamicArrayOfRValue, m_Owner); 318 | // 164 319 | static constexpr auto RefDynamicArrayOfRValue_offset_length = offsetof(RefDynamicArrayOfRValue, length); 320 | -------------------------------------------------------------------------------- /src/rorr/gm/RVariableRoutine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gm 4 | { 5 | using RVariableRoutineGetter = bool (*)(CInstance* self, void* a2, RValue* out); 6 | using RVariableRoutineSetter = bool (*)(CInstance* self, void* a2, RValue* new_value); 7 | 8 | struct RVariableRoutine 9 | { 10 | const char* name; 11 | RVariableRoutineGetter getter; 12 | RVariableRoutineSetter setter; 13 | void* has_setter; 14 | }; 15 | 16 | static_assert(sizeof(RVariableRoutine) == 32); 17 | } // namespace gm 18 | -------------------------------------------------------------------------------- /src/rorr/gm/Script_Data.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct CScript; 5 | 6 | namespace gm 7 | { 8 | inline ankerl::unordered_dense::map> script_asset_cache; 9 | 10 | using Script_Data_t = CScript* (*)(int script_function_index); 11 | } // namespace gm 12 | -------------------------------------------------------------------------------- /src/rorr/gm/StructCreate.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct RValue; 4 | 5 | namespace gm 6 | { 7 | using StructCreate_t = void (*)(RValue* out_result); 8 | } 9 | -------------------------------------------------------------------------------- /src/rorr/gm/VMBuffer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct VMBuffer 4 | { 5 | void** vTable; 6 | int m_size; 7 | int m_numLocalVarsUsed; 8 | int m_numArguments; 9 | char* m_pBuffer; 10 | void** m_pConvertedBuffer; 11 | char* m_pJumpBuffer; 12 | }; 13 | -------------------------------------------------------------------------------- /src/rorr/gm/VMExec.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct VMExec 4 | { 5 | VMExec* pPrev; 6 | VMExec* pNext; 7 | char* pStack; 8 | int localCount; 9 | YYObjectBase* pLocals; 10 | YYObjectBase* pSelf; 11 | YYObjectBase* pOther; 12 | CCode* pCCode; 13 | YYRValue* pArgs; 14 | int argumentCount; 15 | const char* pCode; 16 | char* pBP; 17 | VMBuffer* pBuffer; 18 | int line; 19 | const char* pName; 20 | VMBuffer* pDebugInfo; 21 | const char* pScript; 22 | int stackSize; 23 | int offs; 24 | int boffs; 25 | int retCount; 26 | int bufferSize; 27 | int prevoffs; 28 | void** buff; 29 | int* jt; 30 | }; 31 | -------------------------------------------------------------------------------- /src/rorr/gm/Variable_BuiltIn.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pointers.hpp" 4 | #include "rorr/gm/Code_Function_GET_the_function.hpp" 5 | #include "string/hash.hpp" 6 | 7 | namespace gm 8 | { 9 | static ankerl::unordered_dense::map> builtin_getter_cache; 10 | static ankerl::unordered_dense::map> builtin_setter_cache; 11 | 12 | static ankerl::unordered_dense::set> game_defined_cache; 13 | 14 | inline RValue variable_global_get(std::string_view variable_name) 15 | { 16 | if (const auto it = builtin_getter_cache.find(variable_name.data()); it != builtin_getter_cache.end()) 17 | { 18 | RValue result{}; 19 | it->second(nullptr, nullptr, &result); 20 | return result; 21 | } 22 | 23 | if (const auto it = game_defined_cache.find(variable_name.data()); it != game_defined_cache.end()) 24 | { 25 | return gm::call("variable_global_get", variable_name.data()); 26 | } 27 | 28 | const auto size = *big::g_pointers->m_rorr.m_builtin_variable_count; 29 | for (int i = 0; i < size; i++) 30 | { 31 | const auto& builtin_variable = big::g_pointers->m_rorr.m_builtin_variables[i]; 32 | 33 | const auto same_name = !strcmp(builtin_variable.name, variable_name.data()); 34 | if (same_name && builtin_variable.getter) 35 | { 36 | builtin_getter_cache[variable_name.data()] = builtin_variable.getter; 37 | 38 | RValue result{}; 39 | builtin_variable.getter(nullptr, nullptr, &result); 40 | return result; 41 | } 42 | } 43 | 44 | const auto global_exists = gm::call("variable_global_exists", variable_name.data()).asBoolean(); 45 | if (global_exists) 46 | { 47 | game_defined_cache.insert(variable_name.data()); 48 | 49 | return gm::call("variable_global_get", variable_name.data()); 50 | } 51 | 52 | return {}; 53 | } 54 | 55 | inline bool variable_global_set(std::string_view variable_name, RValue& new_value) 56 | { 57 | if (const auto it = builtin_setter_cache.find(variable_name.data()); it != builtin_setter_cache.end()) 58 | { 59 | RValue result{}; 60 | return it->second(nullptr, nullptr, &result); 61 | } 62 | 63 | if (const auto it = game_defined_cache.find(variable_name.data()); it != game_defined_cache.end()) 64 | { 65 | return gm::call("variable_global_set", std::to_array({variable_name.data(), new_value})); 66 | } 67 | 68 | const auto size = *big::g_pointers->m_rorr.m_builtin_variable_count; 69 | for (int i = 0; i < size; i++) 70 | { 71 | const auto& builtin_variable = big::g_pointers->m_rorr.m_builtin_variables[i]; 72 | 73 | const auto same_name = !strcmp(builtin_variable.name, variable_name.data()); 74 | if (same_name && builtin_variable.setter) 75 | { 76 | builtin_setter_cache[variable_name.data()] = builtin_variable.setter; 77 | 78 | return builtin_variable.setter(nullptr, nullptr, &new_value); 79 | } 80 | } 81 | 82 | game_defined_cache.insert(variable_name.data()); 83 | 84 | return gm::call("variable_global_set", std::to_array({variable_name.data(), new_value})); 85 | } 86 | 87 | inline void print_all_builtin_variables() 88 | { 89 | for (size_t i = 0; i < *big::g_pointers->m_rorr.m_builtin_variable_count; i++) 90 | { 91 | const auto& builtin_variable = big::g_pointers->m_rorr.m_builtin_variables[i]; 92 | 93 | LOG(INFO) << builtin_variable.name; 94 | LOG(INFO) << HEX_TO_UPPER_OFFSET(builtin_variable.getter); 95 | LOG(INFO) << HEX_TO_UPPER_OFFSET(builtin_variable.setter); 96 | } 97 | } 98 | } // namespace gm 99 | -------------------------------------------------------------------------------- /src/rorr/gm/YYGMLException.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "RValue.hpp" 3 | 4 | struct CInstance; 5 | 6 | class YYGMLException 7 | { 8 | public: 9 | char m_object[sizeof(RValue)]; 10 | 11 | inline YYGMLException(CInstance* _pSelf, CInstance* _pOther, const char* _pMessage, const char* _pLongMessage, const char* _filename, int _line, const char** ppStackTrace, int numLines) 12 | { 13 | } 14 | 15 | inline YYGMLException(const RValue& _val) 16 | { 17 | RValue copy{_val}; 18 | std::memcpy(&m_object, ©, sizeof(m_object)); // raw copy... 19 | std::memset(©, 0, sizeof(copy)); // prevent copy from getting destructed... 20 | // initializing an RValue to all bits zero will make it a real number 0.0, which is fine. 21 | } 22 | 23 | inline const RValue& GetExceptionObject() const 24 | { 25 | return *reinterpret_cast(&m_object); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/rorr/gm/YYGMLFuncs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct CInstance; 4 | struct RValue; 5 | struct YYVAR; 6 | 7 | using PFUNC_YYGMLScript = RValue* (*)(CInstance* self, CInstance* other, RValue* result, int arg_count, RValue** args); 8 | using PFUNC_YYGML = void (*)(CInstance* self, CInstance* other); 9 | 10 | struct YYGMLFuncs 11 | { 12 | const char* m_name; 13 | 14 | union 15 | { 16 | PFUNC_YYGMLScript m_script_function; 17 | PFUNC_YYGML m_function; 18 | }; 19 | 20 | YYVAR* m_func_var; 21 | }; 22 | -------------------------------------------------------------------------------- /src/rorr/gm/YYObjectBase.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "EJSRetValBool.hpp" 4 | 5 | struct RValue; 6 | struct CWeakRef; 7 | struct CCode; 8 | 9 | template 10 | struct CHashMap; 11 | 12 | struct CInstanceBase 13 | { 14 | RValue* yyvars; 15 | virtual ~CInstanceBase() = 0; 16 | 17 | virtual RValue& InternalGetYYVarRef(int index) = 0; 18 | virtual RValue& InternalGetYYVarRefL(int index) = 0; 19 | }; 20 | 21 | enum class YYObjectBaseType : int 22 | { 23 | YYOBJECTBASE = 0, 24 | CINSTANCE, 25 | ACCESSOR, 26 | SCRIPTREF, 27 | PROPERTY, 28 | ARRAY, 29 | WEAKREF, 30 | 31 | CONTAINER, 32 | 33 | SEQUENCE, 34 | SEQUENCEINSTANCE, 35 | SEQUENCETRACK, 36 | SEQUENCECURVE, 37 | SEQUENCECURVECHANNEL, 38 | SEQUENCECURVEPOINT, 39 | SEQUENCEKEYFRAMESTORE, 40 | SEQUENCEKEYFRAME, 41 | SEQUENCEKEYFRAMEDATA, 42 | SEQUENCEEVALTREE, 43 | SEQUENCEEVALNODE, 44 | SEQUENCEEVENT, 45 | 46 | NINESLICE, 47 | 48 | MAX 49 | }; 50 | 51 | struct YYObjectBase : CInstanceBase 52 | { 53 | virtual bool Mark4GC(unsigned int* _pM, int _numObjects) = 0; 54 | virtual bool MarkThisOnly4GC(unsigned int* _pM, int _numObjects) = 0; 55 | virtual bool MarkOnlyChildren4GC(unsigned int* _pM, int _numObjects) = 0; 56 | virtual void Free(bool preserve_map) = 0; 57 | virtual void ThreadFree(bool preserve_map, void* _pGCContext) = 0; 58 | virtual void PreFree() = 0; 59 | 60 | YYObjectBase* m_pNextObject; 61 | YYObjectBase* m_pPrevObject; 62 | YYObjectBase* m_prototype; 63 | //void* m_pcre; 64 | //void* m_pcreExtra; 65 | const char* m_class; 66 | void (*m_getOwnProperty)(YYObjectBase* obj, RValue* val, const char* name); 67 | void (*m_deleteProperty)(YYObjectBase* obj, RValue* val, const char* name, bool dothrow); 68 | EJSRetValBool (*m_defineOwnProperty)(YYObjectBase* obj, const char* name, RValue* val, bool dothrow); 69 | CHashMap* m_yyvarsMap; 70 | CWeakRef** m_pWeakRefs; 71 | unsigned int m_numWeakRefs; 72 | unsigned int m_nvars; 73 | unsigned int m_flags; 74 | unsigned int m_capacity; 75 | unsigned int m_visited; 76 | unsigned int m_visitedGC; 77 | int m_GCgen; 78 | int m_GCcreationframe; 79 | int m_slot; // offset 30(int) | 120(byte) 80 | YYObjectBaseType type; // m_kind 81 | int m_rvalueInitType; 82 | int m_curSlot; 83 | }; 84 | 85 | // 120 86 | static constexpr auto YYObjectBase_offset_slot = offsetof(YYObjectBase, m_slot); 87 | // 124 88 | static constexpr auto YYObjectBase_offset_type = offsetof(YYObjectBase, type); 89 | 90 | struct CWeakRef : YYObjectBase 91 | { 92 | YYObjectBase* pWeakRef; 93 | }; 94 | -------------------------------------------------------------------------------- /src/rorr/gm/YYSetScriptRef.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct RValue; 4 | struct YYObjectBase; 5 | 6 | using YYSetScriptRef_t = void* (*)(RValue* result, void* function_pointer, YYObjectBase* context_can_be_null); 7 | -------------------------------------------------------------------------------- /src/rorr/gm/YYShader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // based on https://github.com/YAL-GameMaker/shader_replace_unsafe/blob/main/shader_replace_unsafe/gml_internals.h 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | typedef unsigned int UINT; 9 | 10 | struct YYShaderPair 11 | { 12 | char *vertexShader = nullptr; 13 | char *pixelShader = nullptr; 14 | YYShaderPair() = default; 15 | }; 16 | 17 | enum class YYShaderKind : int 18 | { 19 | Vertex = 0, 20 | Pixel, 21 | }; 22 | 23 | struct YYShaderConstBuf 24 | { 25 | int reg; 26 | int size; // rounded up? 27 | YYShaderKind type = YYShaderKind::Vertex; 28 | uint8_t *data; 29 | ID3D11Buffer *buffer; 30 | bool dirty; 31 | YYShaderConstBuf() = delete; 32 | ~YYShaderConstBuf(); 33 | }; 34 | 35 | struct YYShaderSampler 36 | { 37 | char *name; 38 | int reg; 39 | YYShaderKind type = YYShaderKind::Pixel; 40 | YYShaderSampler() = delete; 41 | ~YYShaderSampler(); 42 | }; 43 | 44 | enum class YYShaderVarType : UINT 45 | { 46 | Void = 0, 47 | Bool, 48 | Int, 49 | Uint, 50 | Byte, 51 | Float, 52 | Double, 53 | }; 54 | 55 | struct YYShaderConstBufVar 56 | { 57 | char *name; 58 | uint8_t *data; // = buffer->data + this->offset 59 | int bufferIndex; 60 | int offset; 61 | int size; 62 | YYShaderVarType type; 63 | int cols; 64 | int rows; 65 | int elementCount; 66 | YYShaderConstBufVar() = delete; 67 | ~YYShaderConstBufVar(); 68 | }; 69 | 70 | enum class YYShaderInputSemantic : UINT 71 | { 72 | None = 0, 73 | Position, 74 | Color, 75 | Normal, 76 | TexCoord, 77 | BlendWeight, 78 | BlendIndex, 79 | PSize, 80 | Tangent, 81 | Binormal, 82 | Unknown1, 83 | Unknown2, 84 | Fog, 85 | Depth, 86 | Sample, 87 | }; 88 | 89 | struct YYShaderInputParam 90 | { 91 | YYShaderInputSemantic semantic; 92 | int semanticIndex; 93 | }; 94 | 95 | struct YYShaderInputLayout 96 | { 97 | int format; 98 | ID3D11InputLayout *layout; 99 | YYShaderInputLayout() = delete; 100 | ~YYShaderInputLayout(); 101 | }; 102 | 103 | struct YYShader; 104 | 105 | static ankerl::unordered_dense::map _YYCustomShaderPool; 106 | 107 | enum class YYShaderLanguage : int 108 | { 109 | NONE = 0, 110 | GLSL_ES, 111 | GLSL, 112 | HLSL_9, 113 | HLSL_11, 114 | }; 115 | 116 | struct YYShader 117 | { 118 | int id = -1; 119 | char *name = nullptr; 120 | 121 | YYShaderLanguage type = YYShaderLanguage::HLSL_11; 122 | YYShaderPair GLSLES, GLSL, HLSL9, HLSL11; 123 | YYShaderPair mysteryPairs[3] = {}; 124 | int mysteryPadding[4] = {}; 125 | 126 | char *error_str = nullptr; 127 | bool is_pixel_error = false; 128 | int attributeCount = 0; 129 | char **attributeNames = nullptr; 130 | 131 | int native_shader_handle = -1; 132 | int a11 = 0; 133 | int gm_BaseTexture = 0; 134 | int gm_Matrices = 0; 135 | int gm_Lights_Direction = 0; 136 | int gm_Lights_PosRange = 0; 137 | int gm_Lights_Colour = 0; 138 | int gm_AmbientColour = 0; 139 | int gm_LightingEnabled = 0; 140 | 141 | YYShader() = default; 142 | YYShader(std::string name, int id, const std::vector &vertexShaderRaw, const std::vector &pixelShaderRaw); 143 | ~YYShader(); 144 | 145 | void *operator new(size_t size); 146 | void *operator new[](size_t size) = delete; 147 | 148 | void operator delete(void *ptr, size_t size); 149 | void operator delete[](void *ptr, size_t size) = delete; 150 | }; 151 | 152 | template 153 | struct YYShaderFakeData 154 | { 155 | char *name = nullptr; 156 | UINT a1[N] = {}; 157 | 158 | YYShaderFakeData() = default; 159 | 160 | YYShaderFakeData(const char *n, std::initializer_list args) : 161 | a1{} 162 | { 163 | size_t len = strlen(n); 164 | name = new char[len + 1]; 165 | strcpy(name, n); 166 | 167 | len = std::min(args.size(), (size_t)N); 168 | auto it = args.begin(); 169 | for (size_t i = 0; i < len; i++) 170 | { 171 | a1[i] = *it; 172 | ++it; 173 | } 174 | } 175 | 176 | ~YYShaderFakeData() 177 | { 178 | if (name != nullptr) 179 | { 180 | delete[] name; 181 | name = nullptr; 182 | } 183 | } 184 | 185 | YYShaderFakeData &operator=(const YYShaderFakeData &other) 186 | { 187 | memcpy(&a1, &other.a1, N * sizeof(UINT)); 188 | if (this != &other) 189 | { 190 | if (name != nullptr) 191 | { 192 | delete[] name; 193 | name = nullptr; 194 | } 195 | if (other.name != nullptr) 196 | { 197 | name = new char[strlen(other.name) + 1]; 198 | strcpy(name, other.name); 199 | } 200 | } 201 | return *this; 202 | } 203 | 204 | YYShaderFakeData(const YYShaderFakeData &other) 205 | { 206 | memcpy(&a1, &other.a1, N * sizeof(UINT)); 207 | if (other.name != nullptr) 208 | { 209 | name = new char[strlen(other.name) + 1]; 210 | strcpy(name, other.name); 211 | } 212 | } 213 | 214 | std::pair, std::string> convertToRaw(UINT n_offset) 215 | { 216 | std::string n(name); 217 | 218 | size_t offset_size = sizeof(UINT); 219 | size_t a1_size = sizeof(UINT) * N; 220 | n_offset = (n.size() == 0) ? 0 : n_offset; 221 | 222 | std::vector raw_data(offset_size + a1_size); 223 | memcpy(raw_data.data(), &n_offset, offset_size); 224 | memcpy(raw_data.data() + offset_size, &a1, a1_size); 225 | return std::make_pair(std::move(raw_data), std::move(n)); 226 | } 227 | }; 228 | 229 | struct YYShaderDataHeader 230 | { 231 | UINT version; 232 | UINT cbuf_count; 233 | UINT cbufvar_count; 234 | UINT sampler_count; 235 | UINT texture_count; // it seems useless. 236 | UINT input_count; 237 | UINT shader_size; 238 | 239 | using ConstBufData = YYShaderFakeData<4>; 240 | ConstBufData *cbuf_data; 241 | 242 | using ConstBufVarData = YYShaderFakeData<7>; 243 | ConstBufVarData *cbufvar_data; 244 | 245 | using SamplerData = YYShaderFakeData<2>; 246 | SamplerData *sampler_data; 247 | 248 | using TexturerData = YYShaderFakeData<2>; 249 | TexturerData *texture_data; // it seems useless. 250 | 251 | using InputData = YYShaderFakeData<4>; 252 | InputData *semantic_data; 253 | 254 | char *shader_data; 255 | 256 | YYShaderVarType D3DtoGMLvarType(_D3D_SHADER_VARIABLE_TYPE t); 257 | std::vector convertToRaw(); 258 | 259 | YYShaderDataHeader(const Microsoft::WRL::ComPtr &blob, const Microsoft::WRL::ComPtr &reflection); 260 | 261 | ~YYShaderDataHeader(); 262 | 263 | YYShaderDataHeader(const YYShaderDataHeader &) = delete; 264 | YYShaderDataHeader &operator=(const YYShaderDataHeader &) = delete; 265 | 266 | void *operator new(size_t size) = delete; 267 | void *operator new[](size_t size) = delete; 268 | 269 | void operator delete(void *ptr) = delete; 270 | void operator delete[](void *ptr) = delete; 271 | }; 272 | 273 | struct YYNativeShader 274 | { 275 | ID3D11VertexShader *vertexShader = nullptr; 276 | ID3D11PixelShader *pixelShader = nullptr; 277 | 278 | YYShaderDataHeader *vertexHeader = nullptr; 279 | YYShaderDataHeader *pixelHeader = nullptr; 280 | 281 | uint8_t mysteryZero = 0; 282 | 283 | int constBufferCount = 0; 284 | YYShaderConstBuf *constBuffers = nullptr; 285 | 286 | int samplerCount = 0; 287 | YYShaderSampler *samplers = nullptr; 288 | 289 | int constBufVarCount = 0; 290 | YYShaderConstBufVar *constBufVars = nullptr; 291 | 292 | int inputCount = 0; 293 | YYShaderInputParam *inputs = nullptr; 294 | 295 | int inputLayoutCount = 0; 296 | YYShaderInputLayout **inputLayouts = nullptr; 297 | int lastUsedInputLayout = -1; 298 | 299 | YYNativeShader(char *vertexShaderRaw, char *pixelShaderRaw, int &result); 300 | 301 | ~YYNativeShader(); 302 | 303 | YYNativeShader(const YYNativeShader &other) = delete; 304 | YYNativeShader &operator=(const YYNativeShader &other) = delete; 305 | 306 | void *operator new(size_t size); 307 | void operator delete(void *ptr, size_t size); 308 | }; 309 | 310 | namespace gm 311 | { 312 | using ShaderCreate_t = bool (*)(YYShader *shader); 313 | using GenShaderDataHeader_t = YYShaderDataHeader *(*)(char *raw_data); 314 | using NativeShaderGenCBuf_t = YYShaderDataHeader *(*)(YYNativeShader *native); 315 | using NativeShaderCreate_t = int (*)(YYNativeShader *native); 316 | using FreeShaderDataHeader_t = void (*)(YYShaderDataHeader **header); 317 | } // namespace gm 318 | -------------------------------------------------------------------------------- /src/rorr/gm/debug_console.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "debug/debug.hpp" 3 | #include "logger/exception_handler.hpp" 4 | #include "string/string.hpp" 5 | 6 | namespace gm 7 | { 8 | using debug_console_output_t = void (*)(void* this_, const char* fmt, ...); 9 | 10 | inline void log_stacktrace_and_abort() 11 | { 12 | __try 13 | { 14 | *(int*)0 = 0; 15 | } 16 | __except (big::big_exception_handler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) 17 | { 18 | Logger::FlushQueue(); 19 | big::debug::wait_until_debugger(); 20 | } 21 | } 22 | 23 | inline void hook_debug_console_output(void* this_, const char* fmt, ...) 24 | { 25 | va_list args; 26 | 27 | // get a stacktrace when this happen, the game triggers a debugbreak on this. 28 | if (!strcmp("Why are we reallocing a block that we didn't alloc?!\n", fmt)) 29 | { 30 | /*va_start(args, fmt); 31 | big::g_hooking->get_original()(this_, fmt, args); 32 | va_end(args);*/ 33 | 34 | log_stacktrace_and_abort(); 35 | 36 | return; 37 | } 38 | 39 | // bandaid fix cause current debug gui code trigger it through getting layer names 40 | if (!strcmp("layer_get_all_elements() - can't find specified layer\n", fmt)) 41 | { 42 | /*va_start(args, fmt); 43 | big::g_hooking->get_original()(this_, fmt, args); 44 | va_end(args);*/ 45 | return; 46 | } 47 | 48 | va_start(args, fmt); 49 | int size = vsnprintf(nullptr, 0, fmt, args); 50 | va_end(args); 51 | 52 | // Allocate a buffer to hold the formatted string 53 | std::string result(size + 1, '\0'); // +1 for the null terminator 54 | 55 | // Format the string into the buffer 56 | va_start(args, fmt); 57 | vsnprintf(&result[0], size + 1, fmt, args); 58 | va_end(args); 59 | result.pop_back(); 60 | result.pop_back(); 61 | 62 | if (big::string::starts_with("ERROR!!!", result.c_str())) 63 | { 64 | LOG(ERROR) << result; 65 | Logger::FlushQueue(); 66 | } 67 | else 68 | { 69 | LOG(INFO) << result; 70 | } 71 | 72 | /*va_start(args, fmt); 73 | big::g_hooking->get_original()(this_, fmt, args); 74 | va_end(args);*/ 75 | } 76 | } // namespace gm 77 | -------------------------------------------------------------------------------- /src/rorr/gm/inputs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gui/gui.hpp" 4 | 5 | namespace gm 6 | { 7 | using IO_UpdateM_t = void (*)(); 8 | 9 | inline void hook_IO_UpdateM() 10 | { 11 | if (!big::g_gui || !big::g_gui->is_open()) 12 | { 13 | big::g_hooking->get_original()(); 14 | } 15 | } 16 | } // namespace gm 17 | -------------------------------------------------------------------------------- /src/rorr/gm/pin_map.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Code_Function_GET_the_function.hpp" 3 | 4 | struct YYObjectPinMap 5 | { 6 | inline static ankerl::unordered_dense::map m_refcounts; 7 | 8 | // a ds map for pinnable objects. 9 | inline static RValue m_pin_map{}; 10 | 11 | inline static void init_pin_map() 12 | { 13 | YYObjectPinMap::m_pin_map = gm::call("ds_map_create"); 14 | gm::call("variable_global_set", std::to_array({"__returnofmodding_gc_pin_ds_map_index", YYObjectPinMap::m_pin_map})); 15 | } 16 | 17 | inline static void pin(YYObjectBase* obj) 18 | { 19 | if (!m_refcounts.contains(obj) || m_refcounts[obj] <= 0) 20 | { 21 | gm::call("ds_map_replace", std::to_array({YYObjectPinMap::m_pin_map, (void*)obj, obj})); 22 | 23 | //LOG(ERROR) << "pin(): first " << HEX_TO_UPPER(obj); 24 | 25 | // TODO: Can't figure a nice way to do it cleanly. 26 | m_refcounts[obj]++; 27 | } 28 | 29 | m_refcounts[obj]++; 30 | 31 | //LOG(ERROR) << "pin() refcount " << m_refcounts[obj]; 32 | 33 | //LOG(ERROR) << "pin() map size: " << gm::call("ds_map_size", YYObjectPinMap::m_pin_map).value << " | " << m_refcounts.size(); 34 | } 35 | 36 | inline static void unpin(YYObjectBase* obj) 37 | { 38 | if (m_refcounts.contains(obj)) 39 | { 40 | auto& refcount = m_refcounts[obj]; 41 | 42 | refcount--; 43 | 44 | //LOG(ERROR) << "unpin() refcount " << refcount; 45 | 46 | if (refcount <= 0) 47 | { 48 | gm::call("ds_map_delete", std::to_array({YYObjectPinMap::m_pin_map, (void*)obj})); 49 | 50 | //LOG(ERROR) << "unpin(): delete " << HEX_TO_UPPER(obj); 51 | 52 | m_refcounts.erase(obj); 53 | } 54 | } 55 | 56 | //LOG(ERROR) << "unpin() map size: " << gm::call("ds_map_size", YYObjectPinMap::m_pin_map).value << " | " << m_refcounts.size(); 57 | } 58 | 59 | inline static void cleanup_pin_map() 60 | { 61 | if (YYObjectPinMap::m_pin_map.type != RValueType::UNDEFINED) 62 | { 63 | gm::call("ds_map_destroy", YYObjectPinMap::m_pin_map); 64 | 65 | m_refcounts.clear(); 66 | } 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /src/rorr/gm/save_file_serialize_hook.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GetSaveFileName_t.hpp" 3 | 4 | namespace gm 5 | { 6 | inline void fix_save(RValue* res) 7 | { 8 | if (!res->asString().contains("lobby_votes")) 9 | { 10 | return; 11 | } 12 | 13 | try 14 | { 15 | nlohmann::json save_file = nlohmann::json::parse(res->asString()); 16 | 17 | // Game will hard crash on char select screen if it's a non vanilla difficulty that get saved to user save file. 18 | auto lobby_vote_fix = [](nlohmann::json& save_file, const char* lobby_vote_id) 19 | { 20 | constexpr auto difficulty_key = "d"; 21 | 22 | if (save_file.contains(lobby_vote_id) && save_file[lobby_vote_id].contains(difficulty_key)) 23 | { 24 | if (save_file[lobby_vote_id][difficulty_key].is_number()) 25 | { 26 | const auto selected_difficulty = save_file[lobby_vote_id][difficulty_key].get(); 27 | if (selected_difficulty < 0 || selected_difficulty > 2) 28 | { 29 | save_file[lobby_vote_id][difficulty_key] = 1; 30 | } 31 | } 32 | else 33 | { 34 | save_file[lobby_vote_id][difficulty_key] = 1; 35 | } 36 | } 37 | }; 38 | 39 | lobby_vote_fix(save_file, "lobby_votes"); 40 | lobby_vote_fix(save_file, "lobby_votes_multi"); 41 | 42 | // Game will hard crash on char select screen if it's a non vanilla character that was last selected get saved to user save file. 43 | constexpr auto last_selected_survivor_key = "survivor_choice"; 44 | if (save_file.contains(last_selected_survivor_key)) 45 | { 46 | if (save_file[last_selected_survivor_key].is_string()) 47 | { 48 | const auto selected_survivor = save_file[last_selected_survivor_key].get(); 49 | 50 | // TODO: This is bad check, assumes that modders will never use the ror namespace for their custom survivors. 51 | if (!selected_survivor.starts_with("ror-")) 52 | { 53 | save_file[last_selected_survivor_key] = "ror-commando"; 54 | } 55 | } 56 | else 57 | { 58 | save_file[last_selected_survivor_key] = "ror-commando"; 59 | } 60 | } 61 | 62 | // TODO: loadout_choice bound checking 63 | 64 | *res = save_file.dump(); 65 | } 66 | catch (const std::exception& e) 67 | { 68 | LOG(WARNING) << "Failed save file serialize check: " << e.what(); 69 | } 70 | catch (...) 71 | { 72 | LOG(WARNING) << "Unknown exception while trying to check user save file"; 73 | } 74 | } 75 | 76 | inline RValue* hook_save_file_serialize(CInstance* a1, CInstance* a2, RValue* a3, int a4, RValue** a5) 77 | { 78 | auto res = big::g_hooking->get_original()(a1, a2, a3, a4, a5); 79 | 80 | fix_save(res); 81 | 82 | return res; 83 | } 84 | 85 | inline RValue* hook_save_file_deserialize(CInstance* a1, CInstance* a2, RValue* a3, int a4) 86 | { 87 | const auto res = big::g_hooking->get_original()(a1, a2, a3, a4); 88 | 89 | return res; 90 | } 91 | 92 | inline void hook_json_parse(RValue* res, CInstance* a2, CInstance* a3, __int64 a4, RValue* arg) 93 | { 94 | fix_save(arg); 95 | 96 | big::g_hooking->get_original()(res, a2, a3, a4, arg); 97 | } 98 | } // namespace gm 99 | -------------------------------------------------------------------------------- /src/rorr/gm/save_file_serialize_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gm 4 | { 5 | using save_file_serialize_t = RValue* (*)(CInstance* a1, CInstance* a2, RValue* a3, int a4, RValue** a5); 6 | using save_file_deserialize_t = RValue* (*)(CInstance* a1, CInstance* a2, RValue* a3, int a4); 7 | using json_parse_t = void (*)(RValue* res, CInstance* a2, CInstance* a3, __int64 a4, RValue* arg); 8 | } // namespace gm 9 | -------------------------------------------------------------------------------- /src/rorr/rorr_hooks.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "rorr/gm/CInstance_hooks.hpp" 3 | #include "rorr/gm/Code_Execute_hook.hpp" 4 | #include "rorr/gm/debug_console.hpp" 5 | #include "rorr/gm/GetSaveFileName_hook.hpp" 6 | #include "rorr/gm/inputs.hpp" 7 | #include "rorr/gm/save_file_serialize_hook.hpp" 8 | 9 | namespace big::rorr 10 | { 11 | inline void init_hooks() 12 | { 13 | hooking::detour_hook_helper::add("CSC2", g_pointers->m_rorr.m_CreateSwapChain); 14 | 15 | hooking::detour_hook_helper::add("DCO", g_pointers->m_rorr.m_debug_console_output); 16 | 17 | hooking::detour_hook_helper::add("CE", g_pointers->m_rorr.m_code_execute); 18 | 19 | hooking::detour_hook_helper::add("CIC", g_pointers->m_rorr.m_cinstance_ctor); 20 | hooking::detour_hook_helper::add("CID", g_pointers->m_rorr.m_cinstance_dctor); 21 | 22 | hooking::detour_hook_helper::add("COGMAI", g_pointers->m_rorr.m_cobjectgm_add_instance); 23 | hooking::detour_hook_helper::add("COGMRI", g_pointers->m_rorr.m_cobjectgm_remove_instance); 24 | 25 | hooking::detour_hook_helper::add("IOUM", g_pointers->m_rorr.m_io_update_m); 26 | 27 | hooking::detour_hook_helper::add("GSFN", g_pointers->m_rorr.m_get_save_file_name); 28 | 29 | hooking::detour_hook_helper::add("SFS", g_pointers->m_rorr.m_save_file_serialize); 30 | hooking::detour_hook_helper::add("SFD", g_pointers->m_rorr.m_save_file_deserialize); 31 | hooking::detour_hook_helper::add("JP", g_pointers->m_rorr.m_json_parse); 32 | } 33 | } // namespace big::rorr 34 | -------------------------------------------------------------------------------- /src/rorr/rorr_pointers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gm/CInstance_hooks.hpp" 3 | #include "gm/Code_Execute.hpp" 4 | #include "gm/Code_Function_GET_the_function_t.hpp" 5 | #include "gm/CRoom.hpp" 6 | #include "gm/debug_console.hpp" 7 | #include "gm/GetSaveFileName_t.hpp" 8 | #include "gm/inputs.hpp" 9 | #include "gm/RVariableRoutine.hpp" 10 | #include "gm/save_file_serialize_t.hpp" 11 | #include "gm/Script_Data.hpp" 12 | #include "gm/StructCreate.hpp" 13 | #include "gm/YYShader.hpp" 14 | #include "gm/MemoryManager.hpp" 15 | #include "gm/YYSetScriptRef.hpp" 16 | 17 | #include 18 | 19 | namespace big 20 | { 21 | // needed for serialization of the pointers cache 22 | #pragma pack(push, 1) 23 | 24 | struct rorr_pointers 25 | { 26 | int* m_gamemaker_version_major; 27 | 28 | gm::Code_Function_GET_the_function_t m_code_function_GET_the_function; 29 | int* m_code_function_GET_the_function_function_count; 30 | 31 | gm::Code_Execute m_code_execute; 32 | 33 | gm::RVariableRoutine* m_builtin_variables; 34 | int* m_builtin_variable_count; 35 | 36 | gm::CRoom** m_croom; 37 | 38 | gm::CInstance_ctor m_cinstance_ctor; 39 | gm::CInstance_dctor m_cinstance_dctor; 40 | 41 | gm::CObjectGM_AddInstance m_cobjectgm_add_instance; 42 | gm::CObjectGM_RemoveInstance m_cobjectgm_remove_instance; 43 | 44 | YYSetStr m_yysetstring; 45 | 46 | FREE_RVal_Pre m_free_rvalue_pre; 47 | COPY_RValue_do__Post_t m_copy_rvalue_do_post; 48 | 49 | gm::debug_console_output_t m_debug_console_output; 50 | 51 | gm::IO_UpdateM_t m_io_update_m; 52 | 53 | gm::Script_Data_t m_script_data; 54 | 55 | gm::StructCreate_t m_struct_create; 56 | 57 | YYShader*** m_shader_pool; 58 | int *m_shader_amount; 59 | YYNativeShader*** m_native_shader_pool; 60 | int *m_native_shader_amount; 61 | 62 | gm::ShaderCreate_t m_shader_create; 63 | gm::NativeShaderCreate_t m_native_shader_create; 64 | gm::GenShaderDataHeader_t m_gen_shader_data_header; 65 | gm::NativeShaderGenCBuf_t m_native_shader_gen_cbuf; 66 | gm::FreeShaderDataHeader_t m_free_shader_data_header; 67 | 68 | gm::MemoryManager::ReAlloc m_memorymanager_realloc; 69 | gm::MemoryManager::Free m_memorymanager_free; 70 | gm::MemoryManager::Alloc m_memorymanager_alloc; 71 | 72 | gm::GetSaveFileName_t m_get_save_file_name; 73 | 74 | gm::save_file_serialize_t m_save_file_serialize; 75 | gm::save_file_deserialize_t m_save_file_deserialize; 76 | gm::json_parse_t m_json_parse; 77 | 78 | YYGMLFuncs* m_GMLFuncs; 79 | 80 | YYSetScriptRef_t m_YYSetScriptRef; 81 | 82 | void* m_CreateSwapChain; 83 | }; 84 | 85 | #pragma pack(pop) 86 | static_assert(sizeof(rorr_pointers) % 8 == 0, "Pointers are not properly aligned"); 87 | } // namespace big 88 | -------------------------------------------------------------------------------- /src/rorr/rorr_pointers_layout_info.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pointers.hpp" 3 | 4 | namespace big 5 | { 6 | struct rorr_pointers_layout_info 7 | { 8 | // get the beginning and the end of what we need to save / load 9 | inline static constexpr size_t offset_of_cache_begin_field = offsetof(big::pointers, m_rorr); 10 | inline static constexpr size_t offset_of_cache_end_field = offsetof(big::pointers, m_rorr) + sizeof(rorr_pointers); 11 | inline static constexpr size_t field_count = (offset_of_cache_end_field - offset_of_cache_begin_field) / sizeof(void*); 12 | }; 13 | } // namespace big 14 | -------------------------------------------------------------------------------- /src/version.cpp.in: -------------------------------------------------------------------------------- 1 | #include "version.hpp" 2 | 3 | namespace big 4 | { 5 | const char* version::GIT_SHA1 = "@GIT_SHA1@"; 6 | const char* version::GIT_BRANCH = "@GIT_BRANCH@"; 7 | const char* version::GIT_DATE = "@GIT_DATE@"; 8 | const char* version::GIT_COMMIT_SUBJECT = "@GIT_COMMIT_SUBJECT@"; 9 | }; -------------------------------------------------------------------------------- /src/version.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace big 4 | { 5 | struct version 6 | { 7 | static const char* GIT_SHA1; 8 | static const char* GIT_DATE; 9 | static const char* GIT_COMMIT_SUBJECT; 10 | static const char* GIT_BRANCH; 11 | }; 12 | } -------------------------------------------------------------------------------- /thunderstore/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/return-of-modding/ReturnOfModding/64b9d779d29d0f39737005c93779f2d14722d3eb/thunderstore/icon.png -------------------------------------------------------------------------------- /thunderstore/thunderstore.toml: -------------------------------------------------------------------------------- 1 | 2 | [config] 3 | schemaVersion = "0.0.1" 4 | 5 | [package] 6 | namespace = "ReturnOfModding" 7 | name = "ReturnOfModding" 8 | versionNumber = "1.0.0" 9 | description = "Lua Mod Loader for Risk of Rain Returns" 10 | websiteUrl = "https://github.com/return-of-modding/ReturnOfModding/" 11 | containsNsfwContent = false 12 | 13 | [package.dependencies] 14 | 15 | [build] 16 | icon = "./icon.png" 17 | readme = "../README.md" 18 | outdir = "./build" 19 | 20 | [[build.copy]] 21 | source = "../version.dll" 22 | target = "./ReturnOfModdingPack/version.dll" 23 | 24 | [publish] 25 | repository = "https://thunderstore.io" 26 | communities = ["risk-of-rain-returns"] 27 | categories = ["libraries"] 28 | --------------------------------------------------------------------------------