diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3f1a10c..77fdf15 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -15,5 +15,5 @@ "remoteUser": "codespace", "containerUser": "codespace", "onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}", - "postCreateCommand": "qpm restore" + "postCreateCommand": "qpm ndk resolve -d && qpm restore" } diff --git a/.github/actions/canary-ndk/action.yml b/.github/actions/canary-ndk/action.yml deleted file mode 100644 index 81f9b3a..0000000 --- a/.github/actions/canary-ndk/action.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: "Setup canary ndk" -description: "Sets up canary ndk" -outputs: - ndk-path: - value: ${{ steps.path.outputs.path }} - description: "Output path of the ndk" - cache-hit: - value: ${{ steps.cache.outputs.cache-hit }} - description: "Whether a cache hit occurred for the ndk" -runs: - using: "composite" - steps: - - name: NDK cache - id: cache - uses: actions/cache@v3 - with: - path: ${HOME}/android-ndk-r27-canary/ - key: ${{ runner.os }}-ndk-r27-canary - - - name: Download canary ndk - if: ${{ !steps.cache.outputs.cache-hit }} - env: - CANARY_URL: https://github.com/QuestPackageManager/ndk-canary-archive/releases/download/27.0.1/android-ndk-10883340-linux-x86_64.zip - run: wget ${CANARY_URL} -O ${HOME}/ndk.zip - shell: bash - - - name: Unzip ndk - if: ${{ !steps.cache.outputs.cache-hit }} - run: 7z x "${HOME}/ndk.zip" -o"${HOME}/" - shell: bash - - - name: Set output - id: path - shell: bash - run: echo "path=${HOME}/android-ndk-r27-canary" >> ${GITHUB_OUTPUT} diff --git a/.github/workflows/build-ndk.yml b/.github/workflows/build-ndk.yml index af93955..f2d90bd 100644 --- a/.github/workflows/build-ndk.yml +++ b/.github/workflows/build-ndk.yml @@ -1,42 +1,75 @@ -name: NDK build +name: QPM build on: workflow_dispatch: + inputs: + version: + description: 'Version' + required: false + push: tags: - "v*" branches: - 'master' + - 'main' - 'dev/*' - 'feat/*' - 'fix/*' - paths-ignore: - - '**.yml' - - '!.github/workflows/build-ndk.yml' - - '**.json' - - '!qpm.json' - - '!qpm.shared.json' - - '!mod.template.json' - - '**.txt' - - '!CMakeLists.txt' - - '**.ps1' - - '!build.ps1' - - '!createqmod.ps1' - - '**.md' - - '.gitignore' pull_request: - branches: master + branches: + - 'master' + - 'main' + - 'dev/*' + - 'feat/*' + - 'fix/*' -env: - module_id: NoPromo - qmod_name: NoPromo +jobs: + qpm_info: + runs-on: ubuntu-latest -permissions: - contents: write + outputs: + name: ${{ steps.read_qpm_info.outputs.name }} + id: ${{ steps.read_qpm_info.outputs.id }} + override_so_name: ${{ steps.read_qpm_info.outputs.override_so_name }} + qmod_output_path: ${{ steps.read_qpm_info.outputs.qmod_output_path }} + ndk: ${{ steps.read_qpm_info.outputs.ndk }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install jq + run: | + sudo apt-get update + sudo apt-get install -y jq + + - name: Read info from qpm.json + id: read_qpm_info + run: | + if [ -f "qpm.shared.json" ]; then + NAME="$(jq -r '.config.info.name' qpm.shared.json)" + ID="$(jq -r '.config.info.id' qpm.shared.json)" + OVERRIDE_SO_NAME="$(jq -r '.config.info.additionalData.overrideSoName' qpm.shared.json)" + QMOD_OUTPUT_PATH="$(jq -r '.config.workspace.qmodOutput' qpm.shared.json)" + NDK="$(jq -r '.config.workspace.ndk' qpm.shared.json)" + else + NAME="$(jq -r '.info.name' qpm.json)" + ID="$(jq -r '.info.id' qpm.json)" + OVERRIDE_SO_NAME="$(jq -r '.info.additionalData.overrideSoName' qpm.json)" + QMOD_OUTPUT_PATH="$(jq -r '.workspace.qmodOutput' qpm.json)" + NDK="$(jq -r '.workspace.ndk' qpm.json)" + fi + + echo "name=${NAME}" | tee -a "$GITHUB_OUTPUT" + echo "id=${ID}" | tee -a "$GITHUB_OUTPUT" + echo "override_so_name=${OVERRIDE_SO_NAME}" | tee -a "$GITHUB_OUTPUT" + echo "qmod_output_path=${QMOD_OUTPUT_PATH}" | tee -a "$GITHUB_OUTPUT" + echo "ndk=${NDK}" | tee -a "$GITHUB_OUTPUT" -jobs: build: runs-on: ubuntu-latest + needs: qpm_info steps: - uses: actions/checkout@v4 @@ -47,72 +80,93 @@ jobs: - uses: seanmiddleditch/gha-setup-ninja@v3 - # Use canary NDK to avoid lesser known compile bugs - - name: Setup canary NDK - id: setup-ndk - uses: ./.github/actions/canary-ndk - - - name: Create ndkpath.txt + - name: Get home path run: | - echo ${{ steps.setup-ndk.outputs.ndk-path }} > ${GITHUB_WORKSPACE}/ndkpath.txt - cat ${GITHUB_WORKSPACE}/ndkpath.txt + echo "HOME=$HOME" | tee -a "$GITHUB_ENV" - # get version from pushed tag - name: Extract version - if: startsWith(github.ref, 'refs/tags/v') + if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.version != '' id: version run: | - echo "TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_OUTPUT} - echo "VERSION=${GITHUB_REF#refs/tags/v}" >> ${GITHUB_OUTPUT} + if [ "${{ github.event.inputs.version }}" != "" ]; then + FULL_VERSION="${{ github.event.inputs.version }}" + VERSION="${FULL_VERSION%%[-+]*}" + else + TAG="${GITHUB_REF#refs/tags/}" + FULL_VERSION="${GITHUB_REF#refs/tags/v}" + VERSION="${FULL_VERSION%%[-+]*}" + fi + + echo "TAG=$TAG" | tee -a "$GITHUB_OUTPUT" + echo "VERSION=$VERSION" | tee -a "$GITHUB_OUTPUT" + echo "FULL_VERSION=$FULL_VERSION" | tee -a "$GITHUB_OUTPUT" + + - name: Update version in qpm.json, qpm.shared.json, and mod.template.json + if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.version != '' + run: | + # Update qpm.json + if [ -f qpm.json ]; then + MODIFIED_JSON="$(jq --arg version "$VERSION" '.info.version = $version' qpm.json)" + echo "$MODIFIED_JSON" > qpm.json + fi + + # Update qpm.shared.json if it exists + if [ -f qpm.shared.json ]; then + MODIFIED_JSON="$(jq --arg version "$VERSION" '.config.info.version = $version' qpm.shared.json)" + echo "$MODIFIED_JSON" > qpm.shared.json + fi + + # Update mod.template.json if it exists + if [ -f mod.template.json ]; then + MODIFIED_JSON="$(jq --arg version "$FULL_VERSION" '.version = $version' mod.template.json)" + echo "$MODIFIED_JSON" > mod.template.json + fi + env: + VERSION: ${{ steps.version.outputs.VERSION }} + FULL_VERSION: ${{ steps.version.outputs.FULL_VERSION }} - name: Setup qpm - uses: Fernthedev/qpm-action@v1 + uses: fernthedev/qpm-action@v1 with: workflow_token: ${{ secrets.GITHUB_TOKEN }} restore: true + resolve_ndk: true cache: true - publish: false - name: Build & Create Qmod run: | - cd ${GITHUB_WORKSPACE} qpm s qmod - - name: Get Library Name - id: libname + - name: Rename build artifacts run: | - cd ./build/ - pattern="lib${module_id}*.so" - files=( $pattern ) - echo "NAME=${files[0]}" >> ${GITHUB_OUTPUT} - - - name: Rename debug artifact - run: mv "./build/debug/${{ steps.libname.outputs.NAME }}" "./build/debug_${{ steps.libname.outputs.NAME }}" + mv "./build/debug/${{ needs.qpm_info.outputs.override_so_name }}" "./debug_${{ needs.qpm_info.outputs.override_so_name }}" + mv "./build/${{ needs.qpm_info.outputs.override_so_name }}" "./${{ needs.qpm_info.outputs.override_so_name }}" - - name: Upload non-debug artifact + - name: Upload build artifacts uses: actions/upload-artifact@v4 with: - name: ${{ steps.libname.outputs.NAME }} - path: ./build/${{ steps.libname.outputs.NAME }} + name: build-artifacts if-no-files-found: error + path: | + ./${{ needs.qpm_info.outputs.override_so_name }} + ./debug_${{ needs.qpm_info.outputs.override_so_name }} + ${{ needs.qpm_info.outputs.qmod_output_path }} - - name: Upload debug artifact - uses: actions/upload-artifact@v4 - with: - name: debug_${{ steps.libname.outputs.NAME }} - path: ./build/debug_${{ steps.libname.outputs.NAME }} - if-no-files-found: error + release: + runs-on: ubuntu-latest + needs: build + if: startsWith(github.ref, 'refs/tags/v') + permissions: + contents: write - - name: Upload qmod artifact - uses: actions/upload-artifact@v4 + steps: + - name: Download build artifacts + uses: actions/download-artifact@v4 with: - name: ${{env.qmod_name}}.qmod - path: ./${{ env.qmod_name }}.qmod - if-no-files-found: error + name: build-artifacts + path: output/ - # if we had a tag, we should make a release - - name: Upload release .qmod - if: startsWith(github.ref, 'refs/tags/v') + - name: Upload .qmod id: upload_file_qmod uses: softprops/action-gh-release@v2 with: @@ -120,27 +174,33 @@ jobs: draft: false generate_release_notes: true files: | - ./${{ env.qmod_name }}.qmod + ./output/*.qmod env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload release .so artifacts - if: startsWith(github.ref, 'refs/tags/v') + - name: Upload .so artifacts id: upload_file_so uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.event.inputs.version }} files: | - ./build/${{ steps.libname.outputs.NAME }} - ./build/debug_${{ steps.libname.outputs.NAME }} + ./output/*.so env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Make PR to mod repo - if: startsWith(github.ref, 'refs/tags/v') - continue-on-error: true + - name: Check if BSQMODS_TOKEN is set + id: check-token + run: | + if [ -z "${{ secrets.BSQMODS_TOKEN }}" ]; then + echo "TOKEN_SET=false" | tee -a "$GITHUB_OUTPUT" + else + echo "TOKEN_SET=true" | tee -a "$GITHUB_OUTPUT" + fi + + - name: Make PR to mod repository + if: steps.check-token.outputs.TOKEN_SET == 'true' id: qmod-release - uses: QuestPackageManager/qmod-repo-publish-action@main + uses: DanTheMan827/qmod-repo-publish-action@main with: token: ${{ secrets.BSQMODS_TOKEN }} qmod_url: diff --git a/.github/workflows/tag-and-push.yml b/.github/workflows/tag-and-push.yml new file mode 100644 index 0000000..abd301c --- /dev/null +++ b/.github/workflows/tag-and-push.yml @@ -0,0 +1,53 @@ +name: Tag and Push + +on: + workflow_dispatch: + inputs: + ref: + description: "The ref to check out (branch, tag, or commit SHA). Leave blank for default branch." + required: false + default: '' + tag_name: + description: "The name of the tag to create." + required: true + +permissions: + contents: write # Grant write permissions to push tags + actions: write # Grant write permissions to trigger workflows + +jobs: + tag_and_push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 # Ensure full history is fetched for tagging + + - name: Checkout specific ref (if provided) + run: | + if [ "${{ github.event.inputs.ref }}" != "" ]; then + git fetch origin "${{ github.event.inputs.ref }}" + git checkout "${{ github.event.inputs.ref }}" + fi + + - name: Create or replace the tag + run: | + git tag -f "${{ github.event.inputs.tag_name }}" + + - name: Push the tag to origin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git push origin "${{ github.event.inputs.tag_name }}" --force + + - name: Trigger build-ndk.yml workflow + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + curl -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-ndk.yml/dispatches \ + -d '{"ref": "${{ github.event.inputs.tag_name }}"}' diff --git a/.gitignore b/.gitignore index 9269277..30c9421 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -# Ignore clangd cache .cache/ # Prerequisites @@ -67,4 +66,5 @@ cmake-build-*/ extern.cmake # QMOD Schema -mod.json.schema \ No newline at end of file +mod.json.schema +include/Hooking.hpp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a1b2c2a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "common-stuff"] + path = common-stuff + url = https://github.com/DanTheMan827-BeatSaber/common-stuff.git diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..631e519 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "llvm-vs-code-extensions.vscode-clangd" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index f521685..5b36ff3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -112,10 +112,6 @@ "xstddef": "cpp", "xtr1common": "cpp", "xtree": "cpp", - "xutility": "cpp", - "format": "cpp", - "ranges": "cpp", - "stop_token": "cpp", - "__verbose_abort": "cpp" + "xutility": "cpp" } } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b38a8a4..321936d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -40,7 +40,7 @@ "label": "Build", "detail": "Builds the library", "type": "shell", - "command": "./scripts/build.ps1", + "command": "qpm s build", "group": "build", "options": { "env": {} @@ -51,7 +51,18 @@ "label": "Build (Clean)", "detail": "Builds the library from a clean state", "type": "shell", - "command": "./scripts/build.ps1 -clean", + "command": "qpm s clean", + "group": "build", + "options": { + "env": {} + }, + "problemMatcher": [] + }, + { + "label": "Rebuild", + "detail": "Builds the library from a clean state with cleared dependencies", + "type": "shell", + "command": "qpm s rebuild", "group": "build", "options": { "env": {} @@ -62,7 +73,7 @@ "label": "Copy", "detail": "Builds and copies the library to the Quest using ADB and force-quits Beat Saber", "type": "shell", - "command": "./scripts/copy.ps1", + "command": "qpm s copy", "group": "build", "options": { "env": {} @@ -72,19 +83,19 @@ "label": "Start Logging", "detail": "Begin logging from the Quest to the console", "type": "shell", - "command": "./scripts/start-logging.ps1", + "command": "qpm s logcat", }, { "label": "Start logging to file", "detail": "Begin logging from the Quest to the console and saving output to a file 'logcat.log'", "type": "shell", - "command": "./scripts/start-logging.ps1 --file", + "command": "qpm s logcat -- --file", }, { "label": "Build QMOD", "detail": "Builds a .qmod to be installed into BMBF or QuestPatcher", "type": "shell", - "command": "./scripts/build.ps1 && ./scripts/createqmod.ps1", + "command": "qpm s qmod", "args": [], "group": { "kind": "build", @@ -95,25 +106,56 @@ }, "problemMatcher": [] }, + { + "label": "Build QMOD (Clean)", + "detail": "Builds a .qmod from a clean state to be installed into BMBF or QuestPatcher", + "type": "shell", + "command": "qpm s clean-qmod", + "args": [], + "group": "build", + "options": { + "env": {} + }, + "problemMatcher": [] + }, + { + "label": "Rebuild QMOD", + "detail": "Builds a .qmod from a cleaned state with cleared dependencies to be installed into BMBF or QuestPatcher", + "type": "shell", + "command": "qpm s rebuild-qmod", + "args": [], + "group": "build", + "options": { + "env": {} + }, + "problemMatcher": [] + }, { "label": "Restart Beat Saber", "detail": "Force-quits and restarts Beat Saber on the Quest", "type": "shell", - "command": "./scripts/restart-game.ps1", + "command": "qpm s restart", "problemMatcher": [] }, { "label": "Process Stack", "detail": "Processes a tombstone using the debug .so to find file locations", "type": "shell", - "command": "./scripts/ndk-stack.ps1", + "command": "qpm s stack", "problemMatcher": [] }, { "label": "Pull Tombstone", "detail": "Finds and pulls the most recent tombstone from your quest", "type": "shell", - "command": "./scripts/pull-tombstone.ps1", + "command": "qpm s tomb", + "problemMatcher": [] + }, + { + "label": "Deep Clean", + "detail": "Clears dependencies and cleans the build path", + "type": "shell", + "command": "qpm s deepclean", "problemMatcher": [] } ] diff --git a/CMakeLists.txt b/CMakeLists.txt index 0014cc9..46b6808 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,106 +1,76 @@ -# include some defines automatically made by qpm -include(qpm_defines.cmake) +cmake_minimum_required(VERSION 3.22) -# override mod id -set(MOD_ID "NoPromo") +option(QUEST "Build for quest" ON) -# Enable link time optimization -# In my experience, this can be highly unstable but it nets a huge size optimization and likely performance -# However, the instability was seen using Android.mk/ndk-build builds. With Ninja + CMake, this problem seems to have been solved. -# As always, test thoroughly -# - Fern -# set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) - -cmake_minimum_required(VERSION 3.21) -project(${COMPILE_ID}) - -# export compile commands for significantly better intellisense -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -# c++ standard +# Globals set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED 20) +set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) -# define that stores the actual source directory set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) -# compile options used -add_compile_options(-frtti -fexceptions) -add_compile_options(-O3) -# compile definitions used -add_compile_definitions(VERSION=\"${MOD_VERSION}\") -add_compile_definitions(MOD_ID=\"${MOD_ID}\") +add_compile_options(-frtti -fexceptions -fvisibility=hidden -fPIE -fPIC -Wno-invalid-offsetof) + +# Include. Include order matters! +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/utils.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/qpm.cmake) + +if(${CMAKE_BUILD_TYPE} STREQUAL "RELEASE" OR ${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo" OR ${CMAKE_BUILD_TYPE} STREQUAL "MinSizeRel") + # Better optimizations + add_compile_options(-O3) + + # LTO + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + add_compile_options(-flto) +endif() + +if(${CMAKE_BUILD_TYPE} STREQUAL "DEBUG" OR ${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo") + add_compile_options(-g) +endif() + +# Targets +if(QUEST) + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/targets/quest.cmake) +endif() + +# Post build +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/strip.cmake) + +# stop symbols leaking +# TODO: Fix +# add_link_options(-Wl, --exclude-libs, ALL) +project( NoPromo + VERSION ${PACKAGE_VERSION}) + +add_compile_definitions(MOD_ID="${CMAKE_PROJECT_NAME}") +add_compile_definitions(VERSION="${CMAKE_PROJECT_VERSION}") + +# Set COMPILE_ID for qpm purposes +set(COMPILE_ID ${CMAKE_PROJECT_NAME}) # recursively get all src files RECURSE_FILES(cpp_file_list ${SOURCE_DIR}/*.cpp) RECURSE_FILES(c_file_list ${SOURCE_DIR}/*.c) -RECURSE_FILES(inline_hook_c ${EXTERN_DIR}/includes/beatsaber-hook/shared/inline-hook/*.c) -RECURSE_FILES(inline_hook_cpp ${EXTERN_DIR}/includes/beatsaber-hook/shared/inline-hook/*.cpp) - -# add all src files to compile add_library( - ${COMPILE_ID} + ${CMAKE_PROJECT_NAME} SHARED ${cpp_file_list} ${c_file_list} - ${inline_hook_c} - ${inline_hook_cpp} ) -target_include_directories(${COMPILE_ID} PRIVATE .) - -# add src dir as include dir -target_include_directories(${COMPILE_ID} PRIVATE ${SOURCE_DIR}) -# add include dir as include dir -target_include_directories(${COMPILE_ID} PRIVATE ${INCLUDE_DIR}) -# add shared dir as include dir -target_include_directories(${COMPILE_ID} PUBLIC ${SHARED_DIR}) -# codegen includes -target_include_directories(${COMPILE_ID} PRIVATE ${EXTERN_DIR}/includes/${CODEGEN_ID}/include) - -target_link_libraries(${COMPILE_ID} PRIVATE -llog) -# add extern stuff like libs and other includes -include(extern.cmake) - -add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_STRIP} -d --strip-all - "lib${COMPILE_ID}.so" -o "stripped_lib${COMPILE_ID}.so" - COMMENT "Strip debug symbols done on final binary.") - -add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory debug - COMMENT "Make directory for debug symbols" - ) - -add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename lib${COMPILE_ID}.so debug/lib${COMPILE_ID}.so - COMMENT "Rename the lib to debug_ since it has debug symbols" - ) - -# strip debug symbols from the .so and all dependencies -add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename stripped_lib${COMPILE_ID}.so lib${COMPILE_ID}.so - COMMENT "Rename the stripped lib to regular" - ) - foreach(so_file ${so_list}) - cmake_path(GET so_file FILENAME file) - - add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${so_file} debug/${file} - COMMENT "Copy so files for ndk stack" - ) - - add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_STRIP} -g -S -d --strip-all ${so_file} -o ${file} - COMMENT "Strip debug symbols from the dependencies") - endforeach() - - foreach(a_file ${a_list}) - cmake_path(GET a_file FILENAME file) - - add_custom_command(TARGET ${COMPILE_ID} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${a_file} debug/${file} - COMMENT "Copy a files for ndk stack") - endforeach() +# for inline hook +target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE -llog) + +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${INCLUDE_DIR}) +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${SHARED_DIR}) + +# beatsaber hook inline hook + +RECURSE_FILES(src_inline_hook_beatsaber_hook_local_extra_c ${EXTERN_DIR}/includes/beatsaber-hook/shared/inline-hook/*.c) +RECURSE_FILES(src_inline_hook_beatsaber_hook_local_extra_cpp ${EXTERN_DIR}/includes/beatsaber-hook/shared/inline-hook/*.cpp) + +target_sources(${COMPILE_ID} PRIVATE ${src_inline_hook_beatsaber_hook_local_extra_c}) +target_sources(${COMPILE_ID} PRIVATE ${src_inline_hook_beatsaber_hook_local_extra_cpp}) +include("${CMAKE_CURRENT_SOURCE_DIR}/common-stuff/cmake/include-all.cmake") diff --git a/Customs Banner.psd b/Customs Banner.psd new file mode 100644 index 0000000..fab0c65 Binary files /dev/null and b/Customs Banner.psd differ diff --git a/README.md b/README.md index 46c25da..dbb67bb 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # NoPromo + Hides the promo banner on the main screen. -Use `qpm-rust s build` to build -Same goes for `qpm-rust s copy` and `qpm-rust s qmod` +Use `qpm s build` to build +Same goes for `qpm s copy` and `qpm s qmod` ## Credits diff --git a/cmake/git.cmake b/cmake/git.cmake new file mode 100644 index 0000000..b23401f --- /dev/null +++ b/cmake/git.cmake @@ -0,0 +1,26 @@ +include_guard() + +# TODO: Make this a header file instead of global defines +# to avoid recompile when git changes + +# get git info +execute_process(COMMAND git config user.name OUTPUT_VARIABLE GIT_USER) +execute_process(COMMAND git branch --show-current OUTPUT_VARIABLE GIT_BRANCH) +execute_process(COMMAND git rev-parse --short HEAD OUTPUT_VARIABLE GIT_COMMIT) +execute_process(COMMAND git diff-index --quiet HEAD RESULT_VARIABLE GIT_MODIFIED) + +string(STRIP "${GIT_USER}" GIT_USER) +string(STRIP "${GIT_BRANCH}" GIT_BRANCH) +string(STRIP "${GIT_COMMIT}" GIT_COMMIT) +string(STRIP "${GIT_MODIFIED}" GIT_MODIFIED) + +message(STATUS "GIT_USER: ${GIT_USER}") +message(STATUS "GIT_BRANCH: ${GIT_BRANCH}") +message(STATUS "GIT_COMMIT: 0x${GIT_COMMIT}") +message(STATUS "GIT_MODIFIED: ${GIT_MODIFIED}") + +# set git defines +add_compile_definitions(GIT_USER=\"${GIT_USER}\") +add_compile_definitions(GIT_BRANCH=\"${GIT_BRANCH}\") +add_compile_definitions(GIT_COMMIT=0x00${GIT_COMMIT}) +add_compile_definitions(GIT_MODIFIED=${GIT_MODIFIED}) diff --git a/cmake/gtest.cmake b/cmake/gtest.cmake new file mode 100644 index 0000000..098ceb1 --- /dev/null +++ b/cmake/gtest.cmake @@ -0,0 +1,43 @@ +include_guard() + +message("Compiling with GTest") + +# GTest +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +enable_testing() + +# Run at end to link with project +cmake_language(DEFER DIRECTORY ${CMAKE_SOURCE_DIR} CALL _setup_gtest_project()) + +function(_setup_gtest_project) + # recursively get all src files + RECURSE_FILES(cpp_test_file_list ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp) + RECURSE_FILES(c_test_file_list ${CMAKE_CURRENT_SOURCE_DIR}/test/*.c) + + add_executable( + ${PROJECT_NAME}_test + ${cpp_test_file_list} + ${c_test_file_list} + ) + target_link_libraries( + ${PROJECT_NAME}_test + PRIVATE ${PROJECT_NAME} + GTest::gtest_main + ) + + target_include_directories(${PROJECT_NAME}_test PRIVATE ${INCLUDE_DIR}) + target_include_directories(${PROJECT_NAME}_test PRIVATE ${SHARED_DIR}) + target_include_directories(${PROJECT_NAME}_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test) + + include(GoogleTest) + gtest_discover_tests(${PROJECT_NAME}_test) +endfunction(_setup_gtest_project) diff --git a/cmake/qpm.cmake b/cmake/qpm.cmake new file mode 100644 index 0000000..942568b --- /dev/null +++ b/cmake/qpm.cmake @@ -0,0 +1,33 @@ +include_guard() + +# Necessary for extern.cmake +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/utils.cmake) + + +# read in information about the mod from qpm.json +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/qpm.json PACKAGE_JSON) + +string(JSON PACKAGE_INFO GET ${PACKAGE_JSON} info) + +string(JSON PACKAGE_NAME GET ${PACKAGE_INFO} name) +string(JSON PACKAGE_ID GET ${PACKAGE_INFO} id) +string(JSON PACKAGE_VERSION GET ${PACKAGE_INFO} version) + +message(STATUS "PACKAGE NAME: ${PACKAGE_NAME}") +message(STATUS "PACKAGE VERSION: ${PACKAGE_VERSION}") + +string(JSON EXTERN_DIR_NAME GET ${PACKAGE_JSON} dependenciesDir) +string(JSON SHARED_DIR_NAME GET ${PACKAGE_JSON} sharedDir) + +set(EXTERN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${EXTERN_DIR_NAME}) +set(SHARED_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${SHARED_DIR_NAME}) + +# TODO: This is empty by the time this is called +set(COMPILE_ID ${CMAKE_PROJECT_NAME}) + +# Setup QPM Extern +# TODO: Setup qpm extern from toolchain +cmake_language(DEFER DIRECTORY ${CMAKE_SOURCE_DIR} CALL _setup_qpm_project()) +function(_setup_qpm_project) + include(${CMAKE_CURRENT_SOURCE_DIR}/extern.cmake) +endfunction(_setup_qpm_project) diff --git a/cmake/strip.cmake b/cmake/strip.cmake new file mode 100644 index 0000000..37d3dde --- /dev/null +++ b/cmake/strip.cmake @@ -0,0 +1,29 @@ +# Run at end to link with project +cmake_language(DEFER DIRECTORY ${CMAKE_SOURCE_DIR} CALL _setup_linux_strip_project()) + +function(_setup_linux_strip_project) + if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android") + message("Enabling Stripping") + + # Strip debug symbols + add_custom_command(TARGET ${COMPILE_ID} POST_BUILD + COMMAND ${CMAKE_STRIP} -d --strip-all + "lib${COMPILE_ID}.so" -o "stripped_lib${COMPILE_ID}.so" + COMMENT "Strip debug symbols done on final binary.") + + add_custom_command(TARGET ${COMPILE_ID} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory debug + COMMENT "Make directory for debug symbols" + ) + add_custom_command(TARGET ${COMPILE_ID} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E rename lib${COMPILE_ID}.so debug/lib${COMPILE_ID}.so + COMMENT "Rename the lib to debug_ since it has debug symbols" + ) + + # strip debug symbols from the .so and all dependencies + add_custom_command(TARGET ${COMPILE_ID} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E rename stripped_lib${COMPILE_ID}.so lib${COMPILE_ID}.so + COMMENT "Rename the stripped lib to regular" + ) + endif() +endfunction(_setup_linux_strip_project) diff --git a/cmake/targets/android-ndk.cmake b/cmake/targets/android-ndk.cmake new file mode 100644 index 0000000..a278ea5 --- /dev/null +++ b/cmake/targets/android-ndk.cmake @@ -0,0 +1,45 @@ +include_guard() + +if(NOT DEFINED CMAKE_ANDROID_NDK) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ndkpath.txt") + file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/ndkpath.txt" CMAKE_ANDROID_NDK) + else() + if(EXISTS $ENV{ANDROID_NDK_HOME}) + set(CMAKE_ANDROID_NDK $ENV{ANDROID_NDK_HOME}) + elseif(EXISTS $ENV{ANDROID_NDK_LATEST_HOME}) + set(CMAKE_ANDROID_NDK $ENV{ANDROID_NDK_LATEST_HOME}) + endif() + endif() +endif() + +if(NOT DEFINED CMAKE_ANDROID_NDK) + message(Big time error buddy, no NDK) +endif() + +string(REPLACE "\\" "/" CMAKE_ANDROID_NDK ${CMAKE_ANDROID_NDK}) + +message(STATUS "Using NDK ${CMAKE_ANDROID_NDK}") + +# check if contains space +if(CMAKE_ANDROID_NDK MATCHES " ") + message(FATAL_ERROR "CMAKE_ANDROID_NDK contains a space! Please remove it!") +endif() + + +# Quest is armv8-64 +# Uses Android 12-14 now + +set(ANDROID_PLATFORM 24) +set(ANDROID_ABI arm64-v8a) +set(ANDROID_STL c++_static) +set(ANDROID_USE_LEGACY_TOOLCHAIN_FILE OFF) + +#TODO: Fix this warning +if(CMAKE_TOOLCHAIN_FILE MATCHES ".+") + message(WARNING "CMAKE_TOOLCHAIN_FILE already defined, overwriting! ${CMAKE_TOOLCHAIN_FILE}") +endif() + +set(CMAKE_TOOLCHAIN_FILE ${CMAKE_ANDROID_NDK}/build/cmake/android.toolchain.cmake) + +# Set triplet for vcpkg +set(VCPKG_TARGET_TRIPLET arm64-android) diff --git a/cmake/targets/quest.cmake b/cmake/targets/quest.cmake new file mode 100644 index 0000000..57f3fa8 --- /dev/null +++ b/cmake/targets/quest.cmake @@ -0,0 +1,8 @@ +include_guard() + +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/targets/android-ndk.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/qpm.cmake) + +add_compile_definitions(QUEST) +add_compile_definitions(UNITY_2021) +add_compile_definitions(NEED_UNSAFE_CSHARP) diff --git a/cmake/utils.cmake b/cmake/utils.cmake new file mode 100644 index 0000000..059906c --- /dev/null +++ b/cmake/utils.cmake @@ -0,0 +1,14 @@ +include_guard() + +# get files by filter recursively +MACRO(RECURSE_FILES return_list filter) + FILE(GLOB_RECURSE new_list ${filter}) + SET(file_list "") + + FOREACH(file_path ${new_list}) + SET(file_list ${file_list} ${file_path}) + ENDFOREACH() + + LIST(REMOVE_DUPLICATES file_list) + SET(${return_list} ${file_list}) +ENDMACRO() diff --git a/cmake/vcpkg.cmake b/cmake/vcpkg.cmake new file mode 100644 index 0000000..59ca891 --- /dev/null +++ b/cmake/vcpkg.cmake @@ -0,0 +1,12 @@ +include_guard() + +# vcpkg config +message("VCPKG $ENV{VCPKG_ROOT}") + +# chain the toolchain file for vcpkg +if(CMAKE_TOOLCHAIN_FILE NOT MATCHES ".+") + set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE ${CMAKE_TOOLCHAIN_FILE}) +endif() + +string(REPLACE "\\" "/" VCPKG_ROOT_WINDOWS_FIX $ENV{VCPKG_ROOT}) +set(CMAKE_TOOLCHAIN_FILE ${VCPKG_ROOT_WINDOWS_FIX}/scripts/buildsystems/vcpkg.cmake) diff --git a/common-stuff b/common-stuff new file mode 160000 index 0000000..83ec60b --- /dev/null +++ b/common-stuff @@ -0,0 +1 @@ +Subproject commit 83ec60bca4b15001fbc048843909fbb2eb2bbf01 diff --git a/include/AutoHooks.hpp b/include/AutoHooks.hpp deleted file mode 100644 index 3b75dd2..0000000 --- a/include/AutoHooks.hpp +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include "beatsaber-hook/shared/utils/hooking.hpp" -#include - -namespace AutoHooks { - inline std::vector installFuncs; - - inline void AddInstallFunc(void (*installFunc)()) { - installFuncs.push_back(installFunc); - } - - inline void InstallHooks() { - for (auto& func : installFuncs) func(); - } - - template - concept has_metadata = requires() { - { ::il2cpp_utils::il2cpp_type_check::MetadataGetter::methodInfo() } -> std::same_as; - }; - - template - requires(has_metadata) - using Metadata = ::il2cpp_utils::il2cpp_type_check::MetadataGetter; - - /// @brief checks whether the function is match hookable, which requires the function to be at least 5 (5 * 4 = 20 bytes) instructions and not have an address of 0 (abstract/virtual funcs) - template - concept match_hookable = has_metadata && Metadata::size >= (0x5 * sizeof(int32_t)) && Metadata::addrs != 0xffffffff; -} - -#define HOOK_AUTO_INSTALL_ORIG(name_) \ - struct Auto_Hook_##name_ { \ - static void Auto_Hook_##name_##_Install() { \ - static constexpr auto logger = Paper::ConstLoggerContext(MOD_ID "_Install_" #name_); \ - ::Hooking::InstallOrigHook(logger); \ - } \ - Auto_Hook_##name_() { ::AutoHooks::AddInstallFunc(Auto_Hook_##name_##_Install); } \ - }; \ - static Auto_Hook_##name_ Auto_Hook_Instance_##name_ - -#define HOOK_AUTO_INSTALL(name_) \ - struct Auto_Hook_##name_ { \ - static void Auto_Hook_##name_##_Install() { \ - static constexpr auto logger = Paper::ConstLoggerContext(MOD_ID "_Install_" #name_); \ - ::Hooking::InstallHook(logger); \ - } \ - Auto_Hook_##name_() { ::AutoHooks::AddInstallFunc(Auto_Hook_##name_##_Install); } \ - }; \ - static Auto_Hook_##name_ Auto_Hook_Instance_##name_ - -#define MAKE_AUTO_HOOK_MATCH(name_, mPtr, retval, ...) \ - struct Hook_##name_ { \ - using funcType = retval (*)(__VA_ARGS__); \ - static_assert(AutoHooks::match_hookable); \ - static_assert(std::is_same_v::funcType>, "Hook method signature does not match!"); \ - constexpr static const char* name() { return #name_; } \ - static const MethodInfo* getInfo() { return ::il2cpp_utils::il2cpp_type_check::MetadataGetter::methodInfo(); } \ - static funcType* trampoline() { return &name_; } \ - static inline retval (*name_)(__VA_ARGS__) = nullptr; \ - static funcType hook() { return &::Hooking::HookCatchWrapper<&hook_##name_, funcType>::wrapper; } \ - static retval hook_##name_(__VA_ARGS__); \ - }; \ - HOOK_AUTO_INSTALL(name_); \ - retval Hook_##name_::hook_##name_(__VA_ARGS__) - -#define MAKE_AUTO_HOOK_ORIG_MATCH(name_, mPtr, retval, ...) \ - struct Hook_##name_ { \ - using funcType = retval (*)(__VA_ARGS__); \ - static_assert(AutoHooks::match_hookable); \ - static_assert(std::is_same_v::funcType>, "Hook method signature does not match!"); \ - constexpr static const char* name() { return #name_; } \ - static const MethodInfo* getInfo() { return ::il2cpp_utils::il2cpp_type_check::MetadataGetter::methodInfo(); } \ - static funcType* trampoline() { return &name_; } \ - static inline retval (*name_)(__VA_ARGS__) = nullptr; \ - static funcType hook() { return &::Hooking::HookCatchWrapper<&hook_##name_, funcType>::wrapper; } \ - static retval hook_##name_(__VA_ARGS__); \ - }; \ - HOOK_AUTO_INSTALL_ORIG(name_); \ - retval Hook_##name_::hook_##name_(__VA_ARGS__) diff --git a/include/Logger.hpp b/include/Logger.hpp deleted file mode 100644 index b7048d6..0000000 --- a/include/Logger.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "beatsaber-hook/shared/utils/logging.hpp" - -/// @brief A logger, useful for printing debug messages -/// @return -inline constexpr auto Logger = Paper::ConstLoggerContext(MOD_ID "_" VERSION); diff --git a/include/main.hpp b/include/main.hpp index 22500db..bad5594 100644 --- a/include/main.hpp +++ b/include/main.hpp @@ -1,16 +1,5 @@ #pragma once -// Include the modloader header, which allows us to tell the modloader which mod this is, and the version etc. -#include "scotland2/shared/modloader.h" - -// beatsaber-hook is a modding framework that lets us call functions and fetch field values from in the game -// It also allows creating objects, configuration, and importantly, hooking methods to modify their values -#include "beatsaber-hook/shared/utils/hooking.hpp" -#include "beatsaber-hook/shared/utils/il2cpp-functions.hpp" -#include "beatsaber-hook/shared/utils/il2cpp-utils.hpp" -#include "beatsaber-hook/shared/utils/logging.hpp" -#include "beatsaber-hook/shared/utils/typedefs.h" - #define MOD_EXPORT __attribute__((visibility("default"))) #ifdef __cplusplus #define MOD_EXPORT_FUNC extern "C" MOD_EXPORT diff --git a/include/modInfo.hpp b/include/modInfo.hpp deleted file mode 100644 index 3f2b4f7..0000000 --- a/include/modInfo.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "scotland2/shared/loader.hpp" - -/// @brief Stores the ID and version of our mod, and is sent to the modloader upon startup -inline const modloader::ModInfo modInfo{MOD_ID, VERSION, 0}; diff --git a/mod.template.json b/mod.template.json index 653c34d..cfa5f15 100644 --- a/mod.template.json +++ b/mod.template.json @@ -3,15 +3,15 @@ "_QPVersion": "0.1.1", "name": "${mod_name}", "id": "${mod_id}", - "coverImage:": "", - "modloader": "Scotland2", "author": "DanTheMan827", - "version": "0.1.5", + "version": "${version}", "packageId": "com.beatgames.beatsaber", "packageVersion": "1.40.0_2229", "description": "Hides the promo banner on the main screen.", "dependencies": [], - "modFiles": ["${binary}"], + "modFiles": [ + "${binary}" + ], "libraryFiles": [], "fileCopies": [] } diff --git a/qpm.json b/qpm.json index 8f86481..f1561e3 100644 --- a/qpm.json +++ b/qpm.json @@ -1,11 +1,12 @@ { - "version": "0.2.0", + "$schema": "https://github.com/QuestPackageManager/QPM.Package/raw/refs/heads/main/qpm.schema.json", "sharedDir": "shared", "dependenciesDir": "extern", + "version": "0.4.0", "info": { "name": "NoPromo", "id": "NoPromo", - "version": "0.1.1", + "version": "0.1.5", "url": null, "additionalData": { "overrideSoName": "libNoPromo.so", @@ -17,15 +18,34 @@ "build": [ "pwsh ./scripts/build.ps1" ], + "clean": [ + "pwsh ./scripts/build.ps1 -clean" + ], + "clean-qmod": [ + "qpm s clean", + "qpm s qmod" + ], + "deepclean": [ + "pwsh ./scripts/build.ps1 -clean -skipBuild", + "qpm clear" + ], + "rebuild": [ + "qpm s deepclean", + "qpm s build" + ], + "rebuild-qmod": [ + "qpm s deepclean", + "qpm s qmod" + ], "copy": [ - "pwsh ./scripts/copy.ps1" + "pwsh ./scripts/copy.ps1 $0:?" ], "logcat": [ "pwsh ./scripts/start-logging.ps1" ], "qmod": [ - "pwsh ./scripts/build.ps1", - "pwsh ./scripts/createqmod.ps1" + "qpm s build", + "qpm qmod zip" ], "restart": [ "pwsh ./scripts/restart-game.ps1" @@ -35,18 +55,22 @@ ], "tomb": [ "pwsh ./scripts/pull-tombstone.ps1" + ], + "make-hooking": [ + "pwsh ./common-stuff/scripts/make-hooking.ps1" ] - } + }, + "ndk": "^27.0.0", + "qmodIncludeDirs": [ + "./build", + "./extern/libs" + ], + "qmodOutput": "./NoPromo.qmod" }, "dependencies": [ - { - "id": "beatsaber-hook", - "versionRange": "^6.3.0", - "additionalData": {} - }, { "id": "paper2_scotland2", - "versionRange": "^4.3.2", + "versionRange": "^4.5.0", "additionalData": {} }, { @@ -54,12 +78,16 @@ "versionRange": "4000.*", "additionalData": {} }, + { + "id": "beatsaber-hook", + "versionRange": "^6.3.0", + "additionalData": {} + }, { "id": "scotland2", "versionRange": "^0.1.6", "additionalData": { - "includeQmod": false, - "private": true + "includeQmod": false } } ] diff --git a/qpm.shared.json b/qpm.shared.json index 92fdefc..abb467c 100644 --- a/qpm.shared.json +++ b/qpm.shared.json @@ -1,12 +1,13 @@ { + "$schema": "https://raw.githubusercontent.com/QuestPackageManager/QPM.Package/refs/heads/main/qpm.shared.schema.json", "config": { - "version": "0.2.0", + "version": "0.4.0", "sharedDir": "shared", "dependenciesDir": "extern", "info": { "name": "NoPromo", "id": "NoPromo", - "version": "0.1.1", + "version": "0.1.5", "url": null, "additionalData": { "overrideSoName": "libNoPromo.so", @@ -18,15 +19,37 @@ "build": [ "pwsh ./scripts/build.ps1" ], + "clean": [ + "pwsh ./scripts/build.ps1 -clean" + ], + "clean-qmod": [ + "qpm s clean", + "qpm s qmod" + ], "copy": [ - "pwsh ./scripts/copy.ps1" + "pwsh ./scripts/copy.ps1 $0:?" + ], + "deepclean": [ + "pwsh ./scripts/build.ps1 -clean -skipBuild", + "qpm clear" ], "logcat": [ "pwsh ./scripts/start-logging.ps1" ], + "make-hooking": [ + "pwsh ./common-stuff/scripts/make-hooking.ps1" + ], "qmod": [ - "pwsh ./scripts/build.ps1", - "pwsh ./scripts/createqmod.ps1" + "qpm s build", + "qpm qmod zip" + ], + "rebuild": [ + "qpm s deepclean", + "qpm s build" + ], + "rebuild-qmod": [ + "qpm s deepclean", + "qpm s qmod" ], "restart": [ "pwsh ./scripts/restart-game.ps1" @@ -38,19 +61,18 @@ "pwsh ./scripts/pull-tombstone.ps1" ] }, - "qmodIncludeDirs": [], + "ndk": "^27.0.0", + "qmodIncludeDirs": [ + "./build", + "./extern/libs" + ], "qmodIncludeFiles": [], - "qmodOutput": null + "qmodOutput": "./NoPromo.qmod" }, "dependencies": [ - { - "id": "beatsaber-hook", - "versionRange": "^6.3.0", - "additionalData": {} - }, { "id": "paper2_scotland2", - "versionRange": "^4.3.2", + "versionRange": "^4.5.0", "additionalData": {} }, { @@ -58,12 +80,16 @@ "versionRange": "4000.*", "additionalData": {} }, + { + "id": "beatsaber-hook", + "versionRange": "^6.3.0", + "additionalData": {} + }, { "id": "scotland2", "versionRange": "^0.1.6", "additionalData": { - "includeQmod": false, - "private": true + "includeQmod": false } } ] @@ -72,10 +98,10 @@ { "dependency": { "id": "bs-cordl", - "versionRange": "=4000.1.1", + "versionRange": "=4000.2.0", "additionalData": { "headersOnly": true, - "branchName": "version/v4000_1_1", + "branchName": "version/v4000_2_0", "compileOptions": { "includePaths": [ "include" @@ -91,17 +117,17 @@ } } }, - "version": "4000.1.1" + "version": "4000.2.0" }, { "dependency": { "id": "paper2_scotland2", - "versionRange": "=4.3.2", + "versionRange": "=4.5.0", "additionalData": { - "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.3.2/libpaper2_scotland2.so", + "soLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.5.0/libpaper2_scotland2.so", "overrideSoName": "libpaper2_scotland2.so", - "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.3.2/paper2_scotland2.qmod", - "branchName": "version/v4_3_2", + "modLink": "https://github.com/Fernthedev/paperlog/releases/download/v4.5.0/paper2_scotland2.qmod", + "branchName": "version/v4_5_0", "compileOptions": { "systemIncludes": [ "shared/utfcpp/source" @@ -110,7 +136,7 @@ "cmake": false } }, - "version": "4.3.2" + "version": "4.5.0" }, { "dependency": { @@ -131,17 +157,17 @@ { "dependency": { "id": "beatsaber-hook", - "versionRange": "=6.3.0", + "versionRange": "=6.4.0", "additionalData": { - "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.3.0/libbeatsaber-hook.so", - "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.3.0/debug_libbeatsaber-hook.so", + "soLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.0/libbeatsaber-hook.so", + "debugSoLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.0/debug_libbeatsaber-hook.so", "overrideSoName": "libbeatsaber-hook.so", - "modLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.3.0/beatsaber-hook.qmod", - "branchName": "version/v6_3_0", + "modLink": "https://github.com/QuestPackageManager/beatsaber-hook/releases/download/v6.4.0/beatsaber-hook.qmod", + "branchName": "version/v6_4_0", "cmake": true } }, - "version": "6.3.0" + "version": "6.4.0" }, { "dependency": { diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 06dec9a..d80301e 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -2,6 +2,9 @@ Param( [Parameter(Mandatory=$false)] [Switch] $clean, + [Parameter(Mandatory=$false)] + [Switch] $skipBuild, + [Parameter(Mandatory=$false)] [Switch] $help ) @@ -11,21 +14,48 @@ if ($help -eq $true) { Write-Output "`n-- Arguments --`n" Write-Output "-Clean `t`t Deletes the `"build`" folder, so that the entire library is rebuilt" + Write-Output "-SkipBuild `t`t Skips build, combine this with -Clean" exit } +$sharedQpmFilePath = "qpm.shared.json" +$defaultQpmFilePath = "qpm.json" + +# Check if qpm.shared.json exists, otherwise fallback to qpm.json +if (Test-Path $sharedQpmFilePath) { + $qpmJson = (Get-Content $sharedQpmFilePath | ConvertFrom-Json).config +} elseif (Test-Path $defaultQpmFilePath) { + $qpmJson = Get-Content $defaultQpmFilePath | ConvertFrom-Json +} else { + Write-Error "Neither qpm.shared.json nor qpm.json exists." + exit 1 +} + +# Restore if the dependencies directory isn't present +if (-not $skipBuild.IsPresent -and (-not (Test-Path -Path $qpmJson.dependenciesDir))) { + & qpm restore +} + # if user specified clean, remove all build files if ($clean.IsPresent) { if (Test-Path -Path "build") { remove-item build -R -Force } + + if (Test-Path $qpmJson.workspace.qmodOutput) { + Remove-Item $qpmJson.workspace.qmodOutput -Force + } } +if ($skipBuild.IsPresent) { + exit 0 +} -if (($clean.IsPresent) -or (-not (Test-Path -Path "build"))) { +if (-not (Test-Path -Path "build")) { new-item -Path build -ItemType Directory } & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -B build & cmake --build ./build +exit $LASTEXITCODE diff --git a/scripts/createqmod.ps1 b/scripts/createqmod.ps1 deleted file mode 100644 index 89c9300..0000000 --- a/scripts/createqmod.ps1 +++ /dev/null @@ -1,78 +0,0 @@ -Param( - [Parameter(Mandatory=$false)] - [String] $qmodName="", - - [Parameter(Mandatory=$false)] - [Switch] $help -) - -if ($help -eq $true) { - Write-Output "`"createqmod`" - Creates a .qmod file with your compiled libraries and mod.json." - Write-Output "`n-- Arguments --`n" - - Write-Output "-QmodName `t The file name of your qmod" - - exit -} - -$mod = "./mod.json" - -& $PSScriptRoot/validate-modjson.ps1 -if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE -} -$modJson = Get-Content $mod -Raw | ConvertFrom-Json - -if ($qmodName -eq "") { - $qmodName = $modJson.name -} - -$filelist = @($mod) - -$cover = "./" + $modJson.coverImage -if ((-not ($cover -eq "./")) -and (Test-Path $cover)) { - $filelist += ,$cover -} - -foreach ($mod in $modJson.modFiles) { - $path = "./build/" + $mod - if (-not (Test-Path $path)) { - $path = "./extern/libs/" + $mod - } - if (-not (Test-Path $path)) { - Write-Output "Error: could not find dependency: $path" - exit 1 - } - $filelist += $path -} - -foreach ($mod in $modJson.lateModFiles) { - $path = "./build/" + $mod - if (-not (Test-Path $path)) { - $path = "./extern/libs/" + $mod - } - if (-not (Test-Path $path)) { - Write-Output "Error: could not find dependency: $path" - exit 1 - } - $filelist += $path -} - - -foreach ($lib in $modJson.libraryFiles) { - $path = "./build/" + $lib - if (-not (Test-Path $path)) { - $path = "./extern/libs/" + $lib - } - if (-not (Test-Path $path)) { - Write-Output "Error: could not find dependency: $path" - exit 1 - } - $filelist += $path -} - -$zip = $qmodName + ".zip" -$qmod = $qmodName + ".qmod" - -Compress-Archive -Path $filelist -DestinationPath $zip -Update -Move-Item $zip $qmod -Force diff --git a/src/Hooks/MainViewController.cpp b/src/Hooks/MainViewController.cpp index 4b609f8..e679b66 100644 --- a/src/Hooks/MainViewController.cpp +++ b/src/Hooks/MainViewController.cpp @@ -1,4 +1,4 @@ -#include "AutoHooks.hpp" +#include "Hooking.hpp" #include "Logger.hpp" // GlobalNamespace @@ -12,7 +12,7 @@ namespace Hooks { using namespace GlobalNamespace; // Hooks the MainMenuViewController to hide the musicPackPromoBanner object. - MAKE_AUTO_HOOK_MATCH(MainMenuViewController_DidActivate, &MainMenuViewController::DidActivate, void, MainMenuViewController* self, bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling) { + MAKE_LATE_HOOK_MATCH(MainMenuViewController_DidActivate, &MainMenuViewController::DidActivate, void, MainMenuViewController* self, bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling) { Logger.debug("MainMenuViewController_DidActivate"); self->____musicPackPromoBanner->get_gameObject()->SetActive(false); MainMenuViewController_DidActivate(self, firstActivation, addedToHierarchy, screenSystemEnabling); diff --git a/src/main.cpp b/src/main.cpp index 8ec3da4..4832da5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,23 +1,37 @@ -#include "main.hpp" -#include "AutoHooks.hpp" +#include "Hooking.hpp" #include "Logger.hpp" +#include "beatsaber-hook/shared/utils/il2cpp-functions.hpp" +#include "main.hpp" #include "modInfo.hpp" +#include "scotland2/shared/modloader.h" /// @brief Called at the early stages of game loading -/// @param info +/// @param info The mod info. Update this with your mod's info. /// @return MOD_EXPORT_FUNC void setup(CModInfo& info) { + // Convert the mod info to a C struct and set that as the modloader info. info = modInfo.to_c(); Logger.info("Completed setup!"); } -/// @brief Called later on in the game loading - a good time to install function hooks +/// @brief Called early on in the game loading /// @return -MOD_EXPORT_FUNC void late_load() { +MOD_EXPORT_FUNC void load() { + // Initialize il2cpp functions il2cpp_functions::Init(); - Logger.info("Installing hooks..."); - AutoHooks::InstallHooks(); - Logger.info("Installed all hooks!"); + // install early hooks + Logger.info("Installing early hooks"); + INSTALL_EARLY_HOOKS(); + Logger.info("Finished installing early hooks"); +} + +/// @brief Called later on in the game loading - a good time to install function hooks +/// @return +MOD_EXPORT_FUNC void late_load() { + // Install late hooks + Logger.info("Installing late hooks"); + INSTALL_LATE_HOOKS(); + Logger.info("Finished installing late hooks"); }