diff --git a/.gitignore b/.gitignore index 4e35c33..2d7fc12 100644 --- a/.gitignore +++ b/.gitignore @@ -58,4 +58,6 @@ Android.mk.backup /log_timestamp TestBuild.ps1 -TestQMOD.ps1 \ No newline at end of file +TestQMOD.ps1 +/build +*.cmake diff --git a/Android.mk b/Android.mk deleted file mode 100644 index 4e9db66..0000000 --- a/Android.mk +++ /dev/null @@ -1,43 +0,0 @@ -HOST_NAME ?= master.beattogether.systems -PORT ?= 2328 -STATUS_URL ?= http://master.beattogether.systems/status -LOCAL_PATH := $(call my-dir) - -TARGET_ARCH_ABI := arm64-v8a - -include $(CLEAR_VARS) -LOCAL_MODULE := hook -rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) -# Creating prebuilt for dependency: beatsaber-hook - version: 2.3.0 -include $(CLEAR_VARS) -LOCAL_MODULE := beatsaber-hook_2_3_0 -LOCAL_EXPORT_C_INCLUDES := extern/beatsaber-hook -LOCAL_SRC_FILES := extern/libbeatsaber-hook_2_3_0.so -LOCAL_CPP_FEATURES += exceptions -include $(PREBUILT_SHARED_LIBRARY) -# Creating prebuilt for dependency: modloader - version: 1.2.3 -include $(CLEAR_VARS) -LOCAL_MODULE := modloader -LOCAL_EXPORT_C_INCLUDES := extern/modloader -LOCAL_SRC_FILES := extern/libmodloader.so -include $(PREBUILT_SHARED_LIBRARY) -# Creating prebuilt for dependency: codegen - version: 0.17.0 -include $(CLEAR_VARS) -LOCAL_MODULE := codegen -LOCAL_EXPORT_C_INCLUDES := extern/codegen -LOCAL_SRC_FILES := extern/libcodegen.so -include $(PREBUILT_SHARED_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_MODULE := beattogether -LOCAL_SRC_FILES += $(call rwildcard,src/,*.cpp) -LOCAL_SRC_FILES += $(call rwildcard,extern/beatsaber-hook/src/inline-hook,*.cpp) -LOCAL_SRC_FILES += $(call rwildcard,extern/beatsaber-hook/src/inline-hook,*.c) -LOCAL_SHARED_LIBRARIES += modloader -LOCAL_SHARED_LIBRARIES += beatsaber-hook_2_3_0 -LOCAL_SHARED_LIBRARIES += codegen -LOCAL_LDLIBS += -llog -LOCAL_CFLAGS += -I'extern/libil2cpp/il2cpp/libil2cpp' -DID='"BeatTogether"' -DVERSION='"$(VERSION)"' -DHOST_NAME='"$(HOST_NAME)"' -DPORT='$(PORT)' -DSTATUS_URL='"$(STATUS_URL)"' -I'./shared' -I'./extern' -isystem'./extern/codegen/include' -LOCAL_CPPFLAGS += -std=c++2a -LOCAL_C_INCLUDES += ./include ./src -include $(BUILD_SHARED_LIBRARY) diff --git a/Application.mk b/Application.mk deleted file mode 100644 index 77c0ec6..0000000 --- a/Application.mk +++ /dev/null @@ -1,6 +0,0 @@ -APP_ABI := arm64-v8a -APP_PLATFORM := 25 -APP_PIE:= true -APP_STL := c++_static -APP_CFLAGS := -std=gnu17 -APP_CPPFLAGS := -std=gnu++2a diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..88a3865 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,100 @@ +# include some defines automatically made by qpm +include(qpm_defines.cmake) + +# override mod id +# set(MOD_ID "QuestSounds") + +# 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}) + +# c++ standard +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED 20) + +# 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(-Ofast) +# compile definitions used +add_compile_definitions(VERSION=\"${MOD_VERSION}\") +add_compile_definitions(ID=\"${MOD_ID}\") +add_compile_definitions(MOD_ID=\"${MOD_ID}\") +add_compile_definitions(USE_CODEGEN_FIELDS) + +# BeatTogether compile definitions +if (NOT DEFINED HOST_NAME OR NOT DEFINED STATUS_URL) + add_compile_definitions(HOST_NAME=\"master.beattogether.systems\") + add_compile_definitions(PORT=2328) + add_compile_definitions(STATUS_URL=\"http://master.beattogether.systems/status\") + message(STATUS "Using Server master.beattogether.systems:2328 with StatusUrl \"http://master.beattogether.systems/status\"") +elseif (NOT DEFINED ${PORT}) + add_compile_definitions(HOST_NAME=\"${HOST_NAME}\") + add_compile_definitions(STATUS_URL=\"${STATUS_URL}\") + add_compile_definitions(PORT=2328) + message(AUTHOR_WARNING "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverriding default Server to ${HOST_NAME}:2328 with StatusUrl ${STATUS_URL}\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n") +else() + add_compile_definitions(HOST_NAME=\"${HOST_NAME}\") + add_compile_definitions(STATUS_URL=\"${STATUS_URL}\") + add_compile_definitions(PORT=${PORT}) + message(AUTHOR_WARNING "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOverriding default Server to ${HOST_NAME}:${PORT} with StatusUrl ${STATUS_URL}\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n") +endif() + + +# recursively get all src files +RECURSE_FILES(cpp_file_list ${SOURCE_DIR}/*.cpp) +RECURSE_FILES(c_file_list ${SOURCE_DIR}/*.c) + +# add all src files to compile +add_library( + ${COMPILE_ID} + SHARED + ${cpp_file_list} + ${c_file_list} +) + +target_include_directories(${COMPILE_ID} PRIVATE .) + +target_include_directories(${COMPILE_ID} PRIVATE extern/includes/questui_components) + +# 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" + ) + +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" + ) \ No newline at end of file diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 0000000..ac999ae --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,35 @@ +{ + "configurations": [ + { + "name": "arm64-v8a-Debug", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "inheritEnvironments": [ "linux_arm" ], + "buildRoot": "${projectDir}\\build", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeExecutable": "C:\\Program Files\\CMake\\bin\\cmake.exe", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "cmakeToolchain": "F:/BS-Modding/android-ndk-r24-beta1/build/cmake/android.toolchain.cmake", + "variables": [ + { + "name": "CMAKE_MAKE_PROGRAM", + "value": "C:\\Program Files\\Meson\\ninja.EXE", + "type": "FILEPATH" + }, + { + "name": "CMAKE_C_COMPILER", + "value": "F:\\BS-Modding\\android-ndk-r24-beta1\\toolchains\\llvm\\prebuilt\\windows-x86_64\\bin\\clang.exe", + "type": "FILEPATH" + }, + { + "name": "CMAKE_CXX_COMPILER", + "value": "F:\\BS-Modding\\android-ndk-r24-beta1\\toolchains\\llvm\\prebuilt\\windows-x86_64\\bin\\clang++.exe", + "type": "FILEPATH" + } + ], + "intelliSenseMode": "android-clang-arm64" + } + ] +} \ No newline at end of file diff --git a/ExampleBuild.ps1 b/ExampleBuild.ps1 new file mode 100644 index 0000000..583ffe8 --- /dev/null +++ b/ExampleBuild.ps1 @@ -0,0 +1,59 @@ +Param ( +[Parameter(Mandatory=$false, HelpMessage="The version the mod should be compiled with")][Alias("ver")][string]$Version, +[Parameter(Mandatory=$false, HelpMessage="Switch to create a clean compilation")][Alias("rebuild")][Switch]$clean, +[Parameter(Mandatory=$false, HelpMessage="To create a release build")][Alias("publish")][Switch]$release, +[Parameter(Mandatory=$false, HelpMessage="To create a github actions build, assumes specific Environment variables are set")][Alias("github-build")][Switch]$actions +) + +# The following is an example build file that overwrites the default hostname and status url + +$NDKPath = Get-Content $PSScriptRoot/ndkpath.txt +$QPMpackage = "./qpm.json" +$qpmjson = Get-Content $QPMpackage -Raw | ConvertFrom-Json +$ModID = $qpmjson.info.id +$VERSION = $qpmjson.info.version +if (-not $VERSION.Contains("-Test")) { + $VERSION += "-Test" +} +& qpm-rust package edit --version $VERSION + + +if ((Test-Path "./extern/includes/beatsaber-hook/src/inline-hook/And64InlineHook.cpp", "./extern/includes/beatsaber-hook/src/inline-hook/inlineHook.c", "./extern/includes/beatsaber-hook/src/inline-hook/relocate.c") -contains $false) { + Write-Host "Critical: Missing inline-hook" + if (!(Test-Path "./extern/includes/beatsaber-hook/src/inline-hook/And64InlineHook.cpp")) { + Write-Host "./extern/includes/beatsaber-hook/src/inline-hook/And64InlineHook.cpp" + } + if (!(Test-Path "./extern/includes/beatsaber-hook/src/inline-hook/inlineHook.c")) { + Write-Host "./extern/includes/beatsaber-hook/src/inline-hook/inlineHook.c" + } + if (!(Test-Path "./extern/includes/beatsaber-hook/inline-hook/src/relocate.c")) { + Write-Host "./extern/includes/beatsaber-hook/src/inline-hook/relocate.c" + } + Write-Host "Task Failed, see output above" + exit 1; +} +echo "Building mod $ModID version $VERSION" + +if ($clean.IsPresent) +{ + if (Test-Path -Path "build") + { + remove-item build -R + } +} + +if (($clean.IsPresent) -or (-not (Test-Path -Path "build"))) +{ + $out = new-item -Path build -ItemType Directory +} + +cd build +# For overwriting the hostname and status url +& cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DHOST_NAME="YOUR_SERVER_HOSTNAME" -DSTATUS_URL="http://YOUR_STATUS_URL" ../ +# If you also need to overwrite the port use the following line instead +# & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DHOST_NAME="YOUR_SERVER_HOSTNAME" -DSTATUS_URL="http://YOUR_STATUS_URL" -DPORT=2328 ../ +& cmake --build . -j 6 +$ExitCode = $LastExitCode +cd .. +exit $ExitCode +echo Done \ No newline at end of file diff --git a/ExampleQMOD.ps1 b/ExampleQMOD.ps1 new file mode 100644 index 0000000..709457e --- /dev/null +++ b/ExampleQMOD.ps1 @@ -0,0 +1,98 @@ +Param( + [Parameter(Mandatory=$false, HelpMessage="The name the output qmod file should have")][String] $qmodname="", + + [Parameter(Mandatory=$false, HelpMessage="Switch to create a clean compilation")] + [Alias("rebuild")] + [Switch] $clean, + + [Parameter(Mandatory=$false, HelpMessage="Prints the help instructions")] + [Switch] $help, + + [Parameter(Mandatory=$false, HelpMessage="Tells the script to not compile and only package the existing files")] + [Alias("actions", "pack")] + [Switch] $package +) + +# Builds a .qmod file for loading with QP or BMBF + +# This is an example qmod script that will build a qmod using our ExampleBuild.ps1 script +# Replace line 37 with the name of the script you want to use + +if ($help -eq $true) { + echo "`"BuildQmod `" - Copiles your mod into a `".so`" or a `".a`" library" + echo "`n-- Parameters --`n" + echo "qmodName `t The file name of your qmod" + + echo "`n-- Arguments --`n" + + echo "-clean `t`t Performs a clean build on both your library and the qmod" + echo "-help `t`t Prints this" + echo "-package `t Only packages existing files, without recompiling`n" + + exit +} + +echo "Creating QMod" +# Replace ExampleBuild.ps1 with the name of your build script +& $PSScriptRoot/ExampleBuild.ps1 -clean:$clean + +if ($LASTEXITCODE -ne 0) { + echo "Failed to build, exiting..." + exit $LASTEXITCODE +} + +qpm-rust qmod build + +echo "Creating qmod from mod.json" + +$mod = "./mod.json" +$modJson = Get-Content $mod -Raw | ConvertFrom-Json + +if ($qmodName -eq "") +{ + $qmodName = "$($modJson.name)_$($modJson.version)" +} + +$filelist = @($mod) + +$cover = "./" + $modJson.coverImage +if ((-not ($cover -eq "./")) -and (Test-Path $cover)) +{ + $filelist += ,$cover +} else { + echo "No cover Image found" +} + +foreach ($mod in $modJson.modFiles) +{ + $path = "./build/" + $mod + if (-not (Test-Path $path)) + { + $path = "./extern/libs/" + $mod + } + $filelist += $path +} + +foreach ($lib in $modJson.libraryFiles) +{ + $path = "./extern/libs/" + $lib + if (-not (Test-Path $path)) + { + $path = "./build/" + $lib + } + $filelist += $path +} + +$zip = $qmodName + ".zip" +$qmod = $qmodName + ".qmod" + +if ((-not ($clean.IsPresent)) -and (Test-Path $qmod)) +{ + echo "Making Clean Qmod" + Move-Item $qmod $zip -Force +} + +Compress-Archive -Path $filelist -DestinationPath $zip -Update +Move-Item $zip $qmod -Force + +echo "Task Completed" \ No newline at end of file diff --git a/README.md b/README.md index 2e55006..7647427 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,6 @@ Want to support development and server costs? [Click Here](https://www.patreon.c **Recommended Install:** -**PLEASE USE MANUAL INSTALL FOR NOW. THE MOD IS IN BETA AND ISN'T LISTED TILL IT IS STABLE. THIS WILL BE REMOVED WHEN ITS AVAILABLE.** - - - Here is how to install the mod in headset: - Go to the Browser section of the BMBF app. - Click the small globe icon in the top right-hand corner and click QuestBoard @@ -26,7 +22,7 @@ Here is how to install the mod in headset: - Scroll down till you find "BeatTogether" and hit the blue download button on the right hand side. - It will say its downloaded. Make sure to hit "Sync to Beat Saber" to apply changes -~~You are now ready to play!~~ +You are now ready to play! **Manual Install:** @@ -39,7 +35,7 @@ On your PC, type in that web address that is shown. You will be greeted with a u Upload the .qmod you got from the download above. To be sure it downloaded correctly, check the "mods" tab and see if its enabled and active. ## Custom Song Support -Customs in multiplayer requires [MultiQuestensions](https://github.com/Goobwabber/MultiQuestensions) +Customs in multiplayer require [MultiplayerCore](https://github.com/EnderdracheLP/MultiplayerCore.Quest) ## Special Thanks Special thanks to [Sc2ad](https://github.com/Sc2ad) for helping me debug this. diff --git a/VERSION b/VERSION deleted file mode 100644 index f0bb29e..0000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.3.0 diff --git a/build.ps1 b/build.ps1 index 77a12ef..feebd60 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,9 +1,98 @@ -$NDKPath = Get-Content $PSScriptRoot/ndkpath.txt -First 1 -$VERSION = Get-Content $PSScriptRoot/VERSION -First 1 +Param ( +[Parameter(Mandatory=$false, HelpMessage="The version the mod should be compiled with")][Alias("ver")][string]$Version, +[Parameter(Mandatory=$false, HelpMessage="Switch to create a clean compilation")][Alias("rebuild")][Switch]$clean, +[Parameter(Mandatory=$false, HelpMessage="To create a release build")][Alias("publish")][Switch]$release, +[Parameter(Mandatory=$false, HelpMessage="To create a github actions build, assumes specific Environment variables are set")][Alias("github-build")][Switch]$actions, +[Parameter(Mandatory=$false, HelpMessage="Overwrite default HOST_NAME")][Alias("host")][string]$HOST_NAME, +[Parameter(Mandatory=$false, HelpMessage="Overwrite default PORT")][string]$PORT, +[Parameter(Mandatory=$false, HelpMessage="Overwrite default STATUS_URL")][string]$STATUS_URL +) +# $NDKPath = Get-Content $PSScriptRoot/ndkpath.txt +$QPMpackage = "./qpm.json" +$qpmjson = Get-Content $QPMpackage -Raw | ConvertFrom-Json +$ModID = $qpmjson.info.id +if (-not $Version) { + $VERSION = $qpmjson.info.version +} else { + $VERSION = $Version +} +if ($release -ne $true -and -not $VERSION.Contains('-Dev')) { + $VERSION += "-Dev" +} + +if ($env:version -eq "") { + & qpm-rust package edit --version $VERSION +} + +if ((Test-Path "./extern/includes/beatsaber-hook/src/inline-hook/And64InlineHook.cpp", "./extern/includes/beatsaber-hook/src/inline-hook/inlineHook.c", "./extern/includes/beatsaber-hook/src/inline-hook/relocate.c") -contains $false) { + Write-Host "Critical: Missing inline-hook" + if (!(Test-Path "./extern/includes/beatsaber-hook/src/inline-hook/And64InlineHook.cpp")) { + Write-Host "./extern/includes/beatsaber-hook/src/inline-hook/And64InlineHook.cpp" + } + if (!(Test-Path "./extern/includes/beatsaber-hook/src/inline-hook/inlineHook.c")) { + Write-Host "./extern/includes/beatsaber-hook/src/inline-hook/inlineHook.c" + } + if (!(Test-Path "./extern/includes/beatsaber-hook/inline-hook/src/relocate.c")) { + Write-Host "./extern/includes/beatsaber-hook/src/inline-hook/relocate.c" + } + Write-Host "Task Failed, see output above" + exit 1; +} +Write-Output "Building mod $ModID version $VERSION" + +if ($clean.IsPresent) +{ + if (Test-Path -Path "build") + { + remove-item build -R + } +} -$buildScript = "$NDKPath/build/ndk-build" -if (-not ($PSVersionTable.PSEdition -eq "Core")) { - $buildScript += ".cmd" +if (($clean.IsPresent) -or (-not (Test-Path -Path "build"))) +{ + new-item -Path build -ItemType Directory } -& $buildScript NDK_PROJECT_PATH=$PSScriptRoot APP_BUILD_SCRIPT=$PSScriptRoot/Android.mk NDK_APPLICATION_MK=$PSScriptRoot/Application.mk VERSION=$VERSION +Set-Location build +if ($null -ne $HOST_NAME -and $null -eq $STATUS_URL) { + $STATUS_URL = "status.$HOST_NAME" + Write-Output $STATUS_URL +} +$argumentList = @() +if ($PORT.Length -gt 0) { + $argumentList += "-DPORT=$PORT" +} +if ($STATUS_URL.Length -gt 0) { + $argumentList += "-DSTATUS_URL=$STATUS_URL" +} +if ($HOST_NAME.Length -gt 0) { + if ($STATUS_URL.Length -eq 0) { + $argumentList += "-DSTATUS_URL=http://$HOST_NAME/status" + } + $argumentList += "-DHOST_NAME=$HOST_NAME" +} + +# if ($null -ne $HOST_NAME -and $null -ne $PORT) { +# & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DHOST_NAME=$HOST_NAME -DPORT=$PORT -DSTATUS_URL=$STATUS_URL ../ +# } elseif ($null -ne $HOST_NAME) { +# & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DHOST_NAME=$HOST_NAME -DSTATUS_URL=$STATUS_URL ../ +# } elseif ($null -ne $PORT) { +# & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DPORT=$PORT ../ +# } elseif ($null -ne $PORT -and $null -ne $STATUS_URL) { +# & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DPORT=$PORT -DSTATUS_URL=$STATUS_URL ../ +# } elseif ($null -ne $STATUS_URL) { +# & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DSTATUS_URL=$STATUS_URL ../ +# } else { +# & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" ../ +# } +Write-Host "Building with arguments: $argumentList" +if ($argumentList.Count -gt 0) { + & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" $argumentList ../ +} else { + & cmake -G "Ninja" -DCMAKE_BUILD_TYPE="RelWithDebInfo" ../ +} +& cmake --build . -j 6 +$ExitCode = $LastExitCode +Set-Location .. +exit $ExitCode +Write-Output Done \ No newline at end of file diff --git a/buildQMOD.ps1 b/buildQMOD.ps1 index 0d54f55..2f44247 100644 --- a/buildQMOD.ps1 +++ b/buildQMOD.ps1 @@ -1,31 +1,114 @@ -# Builds a .qmod file for loading with QuestPatcher -$NDKPath = Get-Content $PSScriptRoot/ndkpath.txt -$VERSION = Get-Content $PSScriptRoot/VERSION -First 1 +Param( + [Parameter(Mandatory=$false, HelpMessage="The name the output qmod file should have")][String] $qmodname="BeatTogether", -$buildScript = "$NDKPath/build/ndk-build" -if (-not ($PSVersionTable.PSEdition -eq "Core")) { - $buildScript += ".cmd" + [Parameter(Mandatory=$false, HelpMessage="Switch to create a clean compilation")] + [Alias("rebuild")] + [Switch] $clean, + + [Parameter(Mandatory=$false, HelpMessage="Prints the help instructions")] + [Switch] $help, + + [Parameter(Mandatory=$false, HelpMessage="Tells the script to not compile and only package the existing files")] + [Alias("actions", "pack")] + [Switch] $package, + + [Parameter(Mandatory=$false, HelpMessage="Overwrite default HOST_NAME")][Alias("host")][string]$HOST_NAME, + [Parameter(Mandatory=$false, HelpMessage="Overwrite default PORT")][string]$PORT, + [Parameter(Mandatory=$false, HelpMessage="Overwrite default STATUS_URL")][string]$STATUS_URL + +) + +# Builds a .qmod file for loading with QP or BMBF + + +if ($help -eq $true) { + echo "`"BuildQmod `" - Copiles your mod into a `".so`" or a `".a`" library" + echo "`n-- Parameters --`n" + echo "qmodName `t The file name of your qmod" + + echo "`n-- Arguments --`n" + + echo "-clean `t`t Performs a clean build on both your library and the qmod" + echo "-help `t`t Prints this" + echo "-package `t Only packages existing files, without recompiling`n" + + exit +} + +if ($qmodName -eq "") +{ + echo "Give a proper qmod name and try again" + exit } -$ArchiveName = "BeatTogether_v$VERSION.qmod" -$TempArchiveName = "beattogether_v$VERSION.qmod.zip" -$BS_HOOK_VERSION = "2_3_0" +if ($package -eq $true) { + $qmodName = "$($env:module_id)_$($env:version)" + echo "Actions: Packaging QMod $qmodName" +} +if (($args.Count -eq 0) -And $package -eq $false) { +echo "Creating QMod $qmodName" +echo "Server ${$HOST_NAME}:$PORT with statusUrl $STATUS_URL" + & $PSScriptRoot/build.ps1 -clean:$clean -HOST_NAME:$HOST_NAME -STATUS_URL:$STATUS_URL -PORT:$PORT -release:$true + + if ($LASTEXITCODE -ne 0) { + echo "Failed to build, exiting..." + exit $LASTEXITCODE + } + + qpm-rust qmod build +} + +echo "Creating qmod from mod.json" + +$mod = "./mod.json" +$modJson = Get-Content $mod -Raw | ConvertFrom-Json -echo "Compiling BeatTogether version: $VERSION, BS-Hook: $BS_HOOK_VERSION" +$filelist = @($mod) -& $buildScript -B NDK_PROJECT_PATH=$PSScriptRoot APP_BUILD_SCRIPT=$PSScriptRoot/Android.mk NDK_APPLICATION_MK=$PSScriptRoot/Application.mk VERSION=$VERSION +$cover = "./" + $modJson.coverImage +if ((-not ($cover -eq "./")) -and (Test-Path $cover)) +{ + $filelist += ,$cover +} else { + echo "No cover Image found" +} + +foreach ($mod in $modJson.modFiles) +{ + $path = "./build/" + $mod + if (-not (Test-Path $path)) + { + $path = "./extern/libs/" + $mod + } + $filelist += $path +} -echo "Compile Finished" +foreach ($lib in $modJson.libraryFiles) +{ + $path = "./extern/libs/" + $lib + if (-not (Test-Path $path)) + { + $path = "./build/" + $lib + } + $filelist += $path +} -$json = Get-Content $PSScriptRoot/mod.json -raw | ConvertFrom-Json -$json.version="$VERSION" -$json.libraryFiles=@("libbeatsaber-hook_$BS_HOOK_VERSION.so") +if ([string]::IsNullOrEmpty($env:version)) { + $qmodVersion = $modJson.version + $qmodName += "_v$qmodVersion" + echo "qmodName set to $qmodName" +} -$json | ConvertTo-Json -depth 32| Set-Content $PSScriptRoot/mod.json +$zip = $qmodName + ".zip" +$qmod = $qmodName + ".qmod" -echo "mod.json updated" +if ((-not ($clean.IsPresent)) -and (Test-Path $qmod)) +{ + echo "Making Clean Qmod" + Move-Item $qmod $zip -Force +} -Compress-Archive -Path "./libs/arm64-v8a/libbeattogether.so", "./libs/arm64-v8a/libbeatsaber-hook_$BS_HOOK_VERSION.so", "./mod.json", "./Cover.png" -DestinationPath $TempArchiveName -Force -Move-Item $TempArchiveName $ArchiveName -Force +Compress-Archive -Path $filelist -DestinationPath $zip -Update +Move-Item $zip $qmod -Force -echo "qmod generated, Done" \ No newline at end of file +echo "Task Completed" \ No newline at end of file diff --git a/copy.ps1 b/copy.ps1 index 084a1b9..53e8201 100644 --- a/copy.ps1 +++ b/copy.ps1 @@ -1,11 +1,37 @@ -$NDKPath = Get-Content $PSScriptRoot/ndkpath.txt -First 1 -$VERSION = Get-Content $PSScriptRoot/VERSION -First 1 +& $PSScriptRoot/TestBuild.ps1 -clean +if ($?) { + qpm-rust qmod build + $modJson = Get-Content "./mod.json" -Raw | ConvertFrom-Json + foreach ($mod in $modJson.modFiles) + { + $path = "./build/" + $mod + if (-not (Test-Path $path)) + { + $path = "./extern/libs/" + $mod + } + adb push $path /sdcard/Android/data/com.beatgames.beatsaber/files/mods/$mod + } -$buildScript = "$NDKPath/build/ndk-build" -if (-not ($PSVersionTable.PSEdition -eq "Core")) { - $buildScript += ".cmd" -} + foreach ($lib in $modJson.libraryFiles) + { + $path = "./extern/libs/" + $lib + if (-not (Test-Path $path)) + { + $path = "./build/" + $lib + } + adb push $path /sdcard/Android/data/com.beatgames.beatsaber/files/libs/$lib + } -& $buildScript NDK_PROJECT_PATH=$PSScriptRoot APP_BUILD_SCRIPT=$PSScriptRoot/Android.mk NDK_APPLICATION_MK=$PSScriptRoot/Application.mk VERSION=$VERSION -& adb push libs/arm64-v8a/libbeattogether.so /sdcard/Android/data/com.beatgames.beatsaber/files/mods/libbeattogether.so -& adb shell am force-stop com.beatgames.beatsaber + if ($?) { + adb shell am force-stop com.beatgames.beatsaber + adb shell am start com.beatgames.beatsaber/com.unity3d.player.UnityPlayerActivity + if ($args[0] -eq "--log") { + & Start-Process PowerShell -ArgumentList "./logging.ps1 --file" + } + if ($args[0] -eq "--debug") { + $timestamp = Get-Date -Format "MM-dd HH:mm:ss.fff" + adb logcat -T "$timestamp" main-modloader:W QuestHook[QuestSounds`|v0.3.0]:* AndroidRuntime:E *:S QuestHook[UtilsLogger`|v1.2.3]:* + } + } +} +echo "Exiting Copy.ps1" \ No newline at end of file diff --git a/mod.json b/mod.json index 015e68d..fae2e7b 100644 --- a/mod.json +++ b/mod.json @@ -1,17 +1,26 @@ { - "_QPVersion": "0.1.1", - "name": "Beat Together", - "id": "BeatTogether", - "author": "BeatTogether Team", - "version": "1.3.0", - "packageId": "com.beatgames.beatsaber", - "packageVersion": "1.17.1", - "description": "A multiplayer private server for the modding community. Supports crossplay between PC and Quest.", - "coverImage": "Cover.png", - "modFiles": [ - "libbeattogether.so" - ], - "libraryFiles": [ - "libbeatsaber-hook_2_3_0.so" - ] -} + "_QPVersion": "0.1.1", + "name": "BeatTogether", + "id": "BeatTogether", + "author": "BeatTogether Team", + "version": "1.4.0", + "packageId": "com.beatgames.beatsaber", + "packageVersion": "1.21.0", + "description": "A multiplayer private server for the modding community. Supports crossplay between PC and Quest.", + "coverImage": "Cover.png", + "dependencies": [ + { + "version": "=0.22.0", + "id": "codegen", + "downloadIfMissing": "https://github.com/sc2ad/BeatSaber-Quest-Codegen/releases/download/v0.22.0/Codegen.qmod" + } + ], + "modFiles": [ + "libBeatTogether.so" + ], + "libraryFiles": [ + "libbeatsaber-hook_3_8_5.so" + ], + "fileCopies": [], + "copyExtensions": [] +} \ No newline at end of file diff --git a/mod.template.json b/mod.template.json new file mode 100644 index 0000000..d755a0a --- /dev/null +++ b/mod.template.json @@ -0,0 +1,16 @@ +{ + "_QPVersion": "0.1.1", + "name": "${mod_name}", + "id": "${mod_id}", + "author": "BeatTogether Team", + "version": "${version}", + "packageId": "com.beatgames.beatsaber", + "packageVersion": "1.21.0", + "description": "A multiplayer private server for the modding community. Supports crossplay between PC and Quest.", + "coverImage": "Cover.png", + "dependencies": [], + "modFiles": [], + "libraryFiles": [], + "fileCopies": [], + "copyExtensions": [] +} \ No newline at end of file diff --git a/qpm.json b/qpm.json index 2108e89..595faa4 100644 --- a/qpm.json +++ b/qpm.json @@ -4,9 +4,11 @@ "info": { "name": "BeatTogether", "id": "BeatTogether", - "version": "1.3.0", - "url": null, - "additionalData": {} + "version": "1.4.0", + "url": "https://github.com/pythonology/BeatTogether.Quest", + "additionalData": { + "overrideSoName": "libBeatTogether.so" + } }, "dependencies": [ { @@ -20,12 +22,12 @@ }, { "id": "codegen", - "versionRange": "*", + "versionRange": "=0.22.0", "additionalData": {} }, { - "id": "libil2cpp", - "versionRange": "*", + "id": "modloader", + "versionRange": "^1.2.3", "additionalData": {} } ], diff --git a/src/main.cpp b/src/main.cpp index a468445..57284a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,12 +16,12 @@ #include "GlobalNamespace/PlatformAuthenticationTokenProvider.hpp" #include "GlobalNamespace/AuthenticationToken.hpp" -#include "GlobalNamespace/MasterServerEndPoint.hpp" +#include "GlobalNamespace/DnsEndPoint.hpp" #include "GlobalNamespace/MultiplayerModeSelectionViewController.hpp" #include "GlobalNamespace/MainMenuViewController.hpp" #include "GlobalNamespace/MainSystemInit.hpp" #include "GlobalNamespace/NetworkConfigSO.hpp" -#include "GlobalNamespace/UserCertificateValidator.hpp" +#include "GlobalNamespace/ClientCertificateValidator.hpp" #include "GlobalNamespace/QuickPlaySongPacksDropdown.hpp" using namespace GlobalNamespace; @@ -138,26 +138,30 @@ MAKE_HOOK_MATCH(PlatformAuthenticationTokenProvider_GetAuthenticationToken, &Pla getLogger().debug("Returning custom authentication token!"); return System::Threading::Tasks::Task_1::New_ctor(AuthenticationToken( AuthenticationToken::Platform::OculusQuest, - self->dyn__userId(), // Important for server and client to keep track of things, should not be modified - self->dyn__userName(), + self->userId, // Important for server and client to keep track of things, should not be modified + self->userName, Array::NewLength(0) )); } MAKE_HOOK_MATCH(MainSystemInit_Init, &MainSystemInit::Init, void, MainSystemInit* self) { MainSystemInit_Init(self); - auto* networkConfig = self->dyn__networkConfig(); + auto* networkConfig = self->networkConfig; getLogger().info("Overriding master server end point . . ."); - getLogger().info("Original status URL: %s", to_utf8(csstrtostr(networkConfig->dyn__masterServerStatusUrl())).c_str()); + getLogger().info("Original status URL: %s", static_cast(networkConfig->get_multiplayerStatusUrl()).c_str()); + getLogger().info("Original QuickPlay Setup URL: %s", static_cast(networkConfig->get_quickPlaySetupUrl()).c_str()); + getLogger().info("ServiceEnvironment: %d", networkConfig->get_serviceEnvironment().value); // If we fail to make the strings, we should fail silently // This could also be replaced with a CRASH_UNLESS call, if you want to fail verbosely. - networkConfig->dyn__masterServerHostName() = CRASH_UNLESS(/* getLogger(), */config.get_hostname()); - networkConfig->dyn__masterServerPort() = CRASH_UNLESS(/* getLogger(), */config.get_port()); - networkConfig->dyn__masterServerStatusUrl() = CRASH_UNLESS(/* getLogger(), */config.get_statusUrl()); + networkConfig->masterServerHostName = CRASH_UNLESS(/* getLogger(), */config.get_hostname()); + networkConfig->masterServerPort = CRASH_UNLESS(/* getLogger(), */config.get_port()); + networkConfig->multiplayerStatusUrl = CRASH_UNLESS(/* getLogger(), */config.get_statusUrl()); + networkConfig->quickPlaySetupUrl = CRASH_UNLESS(StringW(config.get_statusUrl()) + "/mp_override.json"); + networkConfig->forceGameLift = false; } -MAKE_HOOK_MATCH(UserCertificateValidator_ValidateCertificateChainInternal, &UserCertificateValidator::ValidateCertificateChainInternal, void, UserCertificateValidator* self, GlobalNamespace::MasterServerEndPoint* endPoint, System::Security::Cryptography::X509Certificates::X509Certificate2* certificate, Array<::Array*>* certificateChain) +MAKE_HOOK_MATCH(ClientCertificateValidator_ValidateCertificateChainInternal, &ClientCertificateValidator::ValidateCertificateChainInternal, void, ClientCertificateValidator* self, GlobalNamespace::DnsEndPoint* endPoint, System::Security::Cryptography::X509Certificates::X509Certificate2* certificate, ::ArrayW<::ArrayW> certificateChain) { // TODO: Support disabling the mod if official multiplayer is ever fixed // It'd be best if we do certificate validation here... @@ -166,34 +170,22 @@ MAKE_HOOK_MATCH(UserCertificateValidator_ValidateCertificateChainInternal, &User // Change the "Online" menu text to "Modded Online" MAKE_HOOK_MATCH(MainMenuViewController_DidActivate, &MainMenuViewController::DidActivate, void, MainMenuViewController* self, bool firstActivation, bool addedToHierarchy, bool systemScreenEnabling) -{ - // Find the GameObject for the online button's text - //static auto* searchPath = il2cpp_utils::newcsstr("MainContent/OnlineButton"); - //static auto* textName = il2cpp_utils::newcsstr("Text"); - - //UnityEngine::Transform* transform = self->get_gameObject()->get_transform(); - //UnityEngine::GameObject* onlineButton = transform->Find(searchPath)->get_gameObject(); - //UnityEngine::GameObject* onlineButtonTextObj = onlineButton->get_transform()->Find(textName)->get_gameObject(); - +{ // Find the GameObject and get the component for the online button's text - static auto* searchPath = il2cpp_utils::newcsstr("MainContent/OnlineButton/Text"); + static ConstString searchPath = "MainContent/OnlineButton/Text"; TMPro::TextMeshProUGUI* onlineButtonText = self->get_gameObject()->get_transform()->Find(searchPath)->get_gameObject()->GetComponent(); - //// Set the "Modded Online" text every time so that it doesn't change back - //TMPro::TextMeshProUGUI* onlineButtonText = onlineButtonTextObj->GetComponent(); + // Set the "Modded Online" text every time so that it doesn't change back // If we fail to get any valid button text, crash verbosely. // TODO: This could be replaced with a non-intense crash, if we can ensure that DidActivate also works as intended. onlineButtonText->set_text(CRASH_UNLESS(config.get_button())); - - //// Align the Text in the Center - //onlineButtonText->set_alignment(TMPro::TextAlignmentOptions::Center); MainMenuViewController_DidActivate(self, firstActivation, addedToHierarchy, systemScreenEnabling); } // Disable QuickplaySongPacksOverrides if MQE is missing MAKE_HOOK_MATCH(QuickPlaySongPacksDropdown_LazyInit, &QuickPlaySongPacksDropdown::LazyInit, void, QuickPlaySongPacksDropdown* self) { - self->dyn__quickPlaySongPacksOverride() = nullptr; + self->quickPlaySongPacksOverride = nullptr; QuickPlaySongPacksDropdown_LazyInit(self); } @@ -222,16 +214,20 @@ extern "C" void load() INSTALL_HOOK(getLogger(), PlatformAuthenticationTokenProvider_GetAuthenticationToken); INSTALL_HOOK(getLogger(), MainSystemInit_Init); - INSTALL_HOOK(getLogger(), UserCertificateValidator_ValidateCertificateChainInternal); + INSTALL_HOOK(getLogger(), ClientCertificateValidator_ValidateCertificateChainInternal); INSTALL_HOOK(getLogger(), MainMenuViewController_DidActivate); // Checks if MQE is installed - auto ModList = Modloader::getMods(); - if (ModList.find("multiquestensions") != ModList.end()) { - getLogger().info("Hello MQE!"); - getLogger().debug("MQE detected!"); + const std::unordered_map& ModList = Modloader::getMods(); + if (ModList.find("MultiplayerCore") != ModList.end()) { + getLogger().info("Hello MultiplayerCore!"); + getLogger().debug("MultiplayerCore detected!"); + if (ModList.find("MultiQuestensions") != ModList.end()) { + getLogger().info("Hello MQE!"); + getLogger().debug("MQE detected!"); + } } else { - getLogger().warning("MQE not found, CustomSongs will not work!"); + getLogger().warning("MultiplayerCore not found, CustomSongs will not work!"); INSTALL_HOOK(getLogger(), QuickPlaySongPacksDropdown_LazyInit); } }