diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d09a514 --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# VSCode config stuff +!.vscode/c_cpp_properties.json +!.vscode/tasks.json + +# NDK stuff +out/ +[Ll]ib/ +[Ll]ibs/ +[Oo]bj/ +[Oo]bjs/ +ndkpath.txt +*.zip +*.txt +extern/ +Android.mk.backup +qpm.shared.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..e68e932 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,24 @@ +{ + "configurations": [ + { + "defines": [ + "VERSION=\"0.1.0\"", + "__GNUC__", + "__aarch64__" + ], + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/shared", + "${workspaceFolder}/include", + "${workspaceFolder}/extern/**", + "${workspaceFolder}/extern/libil2cpp/il2cpp/libil2cpp", + "C:/androidndk/android-ndk-r21d-windows-x86_64/android-ndk-r21d/**" + ], + "name": "Quest", + "cStandard": "c11", + "cppStandard": "c++20", + "intelliSenseMode": "clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..8862622 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,118 @@ +{ + "files.associations": { + "iosfwd": "cpp", + "__config": "cpp", + "__nullptr": "cpp", + "thread": "cpp", + "any": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "optional": "cpp", + "queue": "cpp", + "set": "cpp", + "stack": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "variant": "cpp", + "vector": "cpp", + "__bit_reference": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "cfenv": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "complex": "cpp", + "condition_variable": "cpp", + "csetjmp": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "exception": "cpp", + "coroutine": "cpp", + "propagate_const": "cpp", + "forward_list": "cpp", + "fstream": "cpp", + "functional": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "locale": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "numeric": "cpp", + "ostream": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "scoped_allocator": "cpp", + "span": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "strstream": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "utility": "cpp", + "valarray": "cpp", + "xstring": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "concepts": "cpp", + "filesystem": "cpp", + "shared_mutex": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstddef": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp" + }, + "C_Cpp.errorSquiggles": "Enabled" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..d2bde51 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,68 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "NDK Build", + "detail": "Builds the library using ndk-build.cmd", + "type": "shell", + "command": "ndk-build", + "windows": { + "command": "ndk-build.cmd" + }, + "args": ["NDK_PROJECT_PATH=.", "APP_BUILD_SCRIPT=./Android.mk", "NDK_APPLICATION_MK=./Application.mk"], + "group": "build", + "options": { + "env": {} + } + }, + { + "label": "Powershell Build", + "detail": "Builds the library using Powershell (recommended)", + "type": "shell", + "command": "./build.ps1", + "windows": { + "command": "./build.ps1" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "options": { + "env": {} + } + }, + { + "label": "Powershell Build and Copy", + "detail": "Builds and copies the library to the Quest using adb and force-quits Beat Saber", + "type": "shell", + "command": "./copy.ps1", + "windows": { + "command": "./copy.ps1" + }, + "group": "build", + "options": { + "env": {} + } + }, + { + "label": "BMBF Build", + "detail": "Builds a .zip to be uploaded into BMBF", + "type": "shell", + "command": "./buildBMBF.ps1", + "windows": { + "command": "./buildBMBF.ps1" + }, + "args": [], + "group": "build", + "options": { + "env": {} + } + }, + { + "label": "Start logging", + "detail": "Records a log to log.txt using adb logcat", + "type": "shell", + "command": "./startlogging.bat" + } + ] +} diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..679d7a6 --- /dev/null +++ b/Android.mk @@ -0,0 +1,69 @@ +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +LOCAL_PATH := $(call my-dir) +TARGET_ARCH_ABI := $(APP_ABI) + +rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) + +# Build the modloader shared library +include $(CLEAR_VARS) +# Creating prebuilt for dependency: modloader - version: 1.0.4 +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: beatsaber-hook - version: 0.8.4 +include $(CLEAR_VARS) +LOCAL_MODULE := beatsaber-hook_0_8_4 +LOCAL_EXPORT_C_INCLUDES := extern/beatsaber-hook +LOCAL_SRC_FILES := extern/libbeatsaber-hook_0_8_4.so +LOCAL_CPP_FEATURES += exceptions +include $(PREBUILT_SHARED_LIBRARY) +# Creating prebuilt for dependency: codegen - version: 0.4.0 +include $(CLEAR_VARS) +LOCAL_MODULE := codegen_0_4_0 +LOCAL_EXPORT_C_INCLUDES := extern/codegen +LOCAL_SRC_FILES := extern/libcodegen_0_4_0.so +include $(PREBUILT_SHARED_LIBRARY) +# Creating prebuilt for dependency: questui - version: 0.2.8 +include $(CLEAR_VARS) +LOCAL_MODULE := questui +LOCAL_EXPORT_C_INCLUDES := extern/questui +LOCAL_SRC_FILES := extern/libquestui.so +include $(PREBUILT_SHARED_LIBRARY) +# Creating prebuilt for dependency: custom-types - version: 0.2.14 +include $(CLEAR_VARS) +LOCAL_MODULE := custom-types +LOCAL_EXPORT_C_INCLUDES := extern/custom-types +LOCAL_SRC_FILES := extern/libcustom-types.so +include $(PREBUILT_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := clockmod +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_0_8_4 +LOCAL_SHARED_LIBRARIES += codegen_0_4_0 +LOCAL_SHARED_LIBRARIES += questui +LOCAL_SHARED_LIBRARIES += custom-types +LOCAL_LDLIBS += -llog +LOCAL_CFLAGS += -I'extern/libil2cpp/il2cpp/libil2cpp' -DID='"clockmod"' -DVERSION='"0.1.0"' -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 new file mode 100644 index 0000000..e7e447f --- /dev/null +++ b/Application.mk @@ -0,0 +1,5 @@ +APP_ABI := arm64-v8a +APP_PLATFORM := 25 +APP_PIE:= true +APP_STL := c++_static +APP_CPPFLAGS := -std=gnu++2a diff --git a/bmbfmod.json b/bmbfmod.json new file mode 100644 index 0000000..7e83c56 --- /dev/null +++ b/bmbfmod.json @@ -0,0 +1,29 @@ +{ + "id": "clockmod", + "name": "Clock Mod", + "version": "0.1.0", + "author": "BoopetyDoopety", + "description": [ + "Displays the time in game. \n\nDoes not currently work with Hitscore Visualiser" + ], + "category": "Gameplay", + "gameVersion": "1.13.0", + "platform": "Quest", + "components": [ + { + "type": "HookMod", + "installAction": { + "installLibraryFile": "libclockmod.so" + }, + "uninstallAction": { + "removeLibraryFile": "libclockmod.so" + } + }, + { + "type": "HookModLibrary", + "installAction": { + "installLibraryFile": "libbeatsaber-hook_0_8_4.so" + } + } + ] +} diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..b24935d --- /dev/null +++ b/build.ps1 @@ -0,0 +1,8 @@ +$NDKPath = Get-Content $PSScriptRoot/ndkpath.txt + +$buildScript = "$NDKPath/build/ndk-build" +if (-not ($PSVersionTable.PSEdition -eq "Core")) { + $buildScript += ".cmd" +} + +& $buildScript NDK_PROJECT_PATH=$PSScriptRoot APP_BUILD_SCRIPT=$PSScriptRoot/Android.mk NDK_APPLICATION_MK=$PSScriptRoot/Application.mk diff --git a/buildBMBF.ps1 b/buildBMBF.ps1 new file mode 100644 index 0000000..646d5d6 --- /dev/null +++ b/buildBMBF.ps1 @@ -0,0 +1,6 @@ +# Builds a .zip file for loading with BMBF +& $PSScriptRoot/build.ps1 + +if ($?) { + Compress-Archive -Path "./libs/arm64-v8a/libclockmod.so", "./libs/arm64-v8a/libbeatsaber-hook_0_8_4.so", "./bmbfmod.json" -DestinationPath "./clockmod_v0.1.0.zip" -Update +} diff --git a/copy.ps1 b/copy.ps1 new file mode 100644 index 0000000..bc544b3 --- /dev/null +++ b/copy.ps1 @@ -0,0 +1,12 @@ +& $PSScriptRoot/build.ps1 +if ($?) { + adb push libs/arm64-v8a/libclockmod.so /sdcard/Android/data/com.beatgames.beatsaber/files/mods/libclockmod.so + 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") { + $timestamp = Get-Date -Format "MM-dd HH:mm:ss.fff" + adb logcat -T "$timestamp" main-modloader:W QuestHook[clockmod`|v0.1.0]:* AndroidRuntime:E *:S + } + } +} diff --git a/default-config.json b/default-config.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/default-config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/include/main.hpp b/include/main.hpp new file mode 100644 index 0000000..db7ebec --- /dev/null +++ b/include/main.hpp @@ -0,0 +1,14 @@ +#pragma once + +// Include the modloader header, which allows us to tell the modloader which mod this is, and the version etc. +#include "modloader/shared/modloader.hpp" + +// 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/logging.hpp" +#include "beatsaber-hook/shared/config/config-utils.hpp" +#include "beatsaber-hook/shared/utils/il2cpp-functions.hpp" + +// Define these functions here so that we can easily read configuration and log information from other files +Configuration& getConfig(); +const Logger& getLogger(); \ No newline at end of file diff --git a/qpm.json b/qpm.json new file mode 100644 index 0000000..f03a751 --- /dev/null +++ b/qpm.json @@ -0,0 +1,38 @@ +{ + "sharedDir": "shared", + "dependenciesDir": "extern", + "info": { + "name": "CLock Mod", + "id": "clockmod", + "version": "0.1.0", + "url": null, + "additionalData": {} + }, + "dependencies": [ + { + "id": "beatsaber-hook", + "versionRange": "0.8.4", + "additionalData": { + "extraFiles": [ + "src/inline-hook" + ] + } + }, + { + "id": "codegen", + "versionRange": "*", + "additionalData": {} + }, + { + "id": "libil2cpp", + "versionRange": "*", + "additionalData": {} + }, + { + "id": "questui", + "versionRange": "*", + "additionalData": {} + } + ], + "additionalData": {} +} \ No newline at end of file diff --git a/shared/ClockUpdater.hpp b/shared/ClockUpdater.hpp new file mode 100644 index 0000000..adf22c8 --- /dev/null +++ b/shared/ClockUpdater.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "custom-types/shared/macros.hpp" +#include "UnityEngine/MonoBehaviour.hpp" +using namespace UnityEngine; + +DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour, + + DECLARE_METHOD(void, Update); + + REGISTER_FUNCTION(ClockUpdater, + REGISTER_METHOD(Update); + ) +) \ No newline at end of file diff --git a/shared/ClockViewController.hpp b/shared/ClockViewController.hpp new file mode 100644 index 0000000..0b03a8f --- /dev/null +++ b/shared/ClockViewController.hpp @@ -0,0 +1,14 @@ +#include "custom-types/shared/macros.hpp" +#include "HMUI/ViewController.hpp" + +DECLARE_CLASS_CODEGEN(ClockMod, ClockViewController, HMUI::ViewController, + + DECLARE_OVERRIDE_METHOD(void, DidActivate, il2cpp_utils::FindMethodUnsafe("HMUI", "ViewController", "DidActivate", 3), bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling); + DECLARE_OVERRIDE_METHOD(void, DidDeactivate, il2cpp_utils::FindMethodUnsafe("HMUI", "ViewController", "DidDeactivate", 2), bool removedFromHierarchy, bool systemScreenDisabling); + + REGISTER_FUNCTION(ClockViewController, + REGISTER_METHOD(DidActivate); + REGISTER_METHOD(DidDeactivate); + ) + +); \ No newline at end of file diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp new file mode 100644 index 0000000..b42a087 --- /dev/null +++ b/src/ClockUpdater.cpp @@ -0,0 +1,21 @@ +#include "ClockUpdater.hpp" +#include "UnityEngine/GameObject.hpp" +#include "TMPro/TextMeshProUGUI.hpp" +#include +using namespace UnityEngine; +using namespace TMPro; + +DEFINE_CLASS(ClockMod::ClockUpdater); + +void ClockMod::ClockUpdater::Update(){ + time_t rawtime; + struct tm * timeinfo; + time (&rawtime); + timeinfo = localtime (&rawtime); + + std::string timedate = asctime(timeinfo); + std::string time = timedate.substr(11,5); + + auto text = get_gameObject()->GetComponent(); + text->set_text(il2cpp_utils::createcsstr(time)); +} \ No newline at end of file diff --git a/src/ClockViewContoller.cpp b/src/ClockViewContoller.cpp new file mode 100644 index 0000000..53bdf58 --- /dev/null +++ b/src/ClockViewContoller.cpp @@ -0,0 +1,37 @@ +#include "ClockViewController.hpp" +#include "main.hpp" + +#include "questui/shared/BeatSaberUI.hpp" + +#include "UnityEngine/UI/VerticalLayoutGroup.hpp" +#include "UnityEngine/Events/UnityAction_1.hpp" +#include "UnityEngine/GameObject.hpp" +#include "HMUI/Touchable.hpp" +#include "HMUI/ScrollView.hpp" +using namespace UnityEngine::UI; +using namespace UnityEngine; +using namespace HMUI; + +DEFINE_CLASS(ClockMod::ClockViewController); + +void ToggleMethod(ClockMod::ClockViewController* parent, bool newValue){ + getConfig().config["insong"].SetBool(newValue); +} + +void ClockMod::ClockViewController::DidActivate(bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling){ + if(firstActivation){ + + get_gameObject()->AddComponent(); + GameObject* container = QuestUI::BeatSaberUI::CreateScrollableSettingsContainer(get_transform()); + + UnityEngine::Events::UnityAction_1* onSettingChange = il2cpp_utils::MakeDelegate*>( + classof(UnityEngine::Events::UnityAction_1*), this, ToggleMethod + ); + + QuestUI::BeatSaberUI::CreateToggle(container->get_transform(), "Show During Song", getConfig().config["insong"].GetBool(), onSettingChange); + } +} + +void ClockMod::ClockViewController::DidDeactivate(bool removedFromHierarchy, bool systemScreenDisabling){ + getConfig().Write(); +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..38fdc98 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,175 @@ +#include "main.hpp" + + +#include "GlobalNamespace/MainMenuViewController.hpp" +#include "GlobalNamespace/AudioTimeSyncController.hpp" +#include "GlobalNamespace/PauseMenuManager.hpp" +#include "GlobalNamespace/SoloFreePlayFlowCoordinator.hpp" +#include "GlobalNamespace/MultiplayerLobbyController.hpp" +using namespace GlobalNamespace; + +#include "TMPro/TextMeshPro.hpp" +#include "TMPro/TextMeshProUGUI.hpp" +#include "TMPro/TextAlignmentOptions.hpp" +using namespace TMPro; + +#include "UnityEngine/Canvas.hpp" +#include "unityEngine/CanvasRenderer.hpp" +#include "UnityEngine/Vector3.hpp" +#include "UnityEngine/Vector2.hpp" +#include "UnityEngine/GameObject.hpp" +#include "UnityEngine/UI/LayoutElement.hpp" +#include "UnityEngine/RenderMode.hpp" +#include "UnityEngine/UI/CanvasScaler.hpp" +#include "UnityEngine/CanvasRenderer.hpp" +using namespace UnityEngine; +using namespace UnityEngine::UI; + +#include "questui/shared/BeatSaberUI.hpp" +#include "questui/shared/QuestUI.hpp" +using namespace QuestUI; + +#include "HMUI/CurvedCanvasSettings.hpp" +using namespace HMUI; + +#include "ClockUpdater.hpp" +#include "ClockViewController.hpp" +using namespace ClockMod; + +#include "custom-types/shared/register.hpp" +using namespace custom_types; + +static ModInfo modInfo; // Stores the ID and version of our mod, and is sent to the modloader upon startup + +// Loads the config from disk using our modInfo, then returns it for use +Configuration& getConfig() { + static Configuration config(modInfo); + config.Load(); + return config; +} + +// Returns a logger, useful for printing debug messages +const Logger& getLogger() { + static const Logger logger(modInfo); + return logger; +} + +UnityEngine::Canvas* canvas; +UnityEngine::UI::VerticalLayoutGroup* layout; + +MAKE_HOOK_OFFSETLESS(MainMenuViewController_DidActivate, void, MainMenuViewController* self, bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling){ + MainMenuViewController_DidActivate(self, firstActivation, addedToHierarchy, screenSystemEnabling); + + if(firstActivation){ + auto canvas_object = UnityEngine::GameObject::New_ctor(il2cpp_utils::createcsstr("Canvas")); + canvas = canvas_object->AddComponent(); + auto canvas_scaler = canvas_object->AddComponent(); + auto canvas_renderer = canvas_object->AddComponent(); + + canvas_object->AddComponent(); + canvas_object->get_transform()->set_position(UnityEngine::Vector3(0,0.5,2.6)); + canvas_object->get_transform()->set_localScale(UnityEngine::Vector3(0.1,0.1,0.1)); + + Object::DontDestroyOnLoad(canvas_object); + + canvas->set_renderMode(UnityEngine::RenderMode::WorldSpace); + + layout = QuestUI::BeatSaberUI::CreateVerticalLayoutGroup(canvas_object->get_transform()); + auto clock_text = QuestUI::BeatSaberUI::CreateText(layout->get_rectTransform(), ""); + + layout->GetComponent()->set_minWidth(7); + layout->GetComponent()->set_minHeight(80); + layout->set_childAlignment(TMPro::TextAlignmentOptions::Center); + layout->get_transform()->set_position(UnityEngine::Vector3(0,-2.20,3)); + clock_text->set_fontSize(4); + clock_text->get_transform()->set_position(UnityEngine::Vector3(0,1,2.6)); + clock_text->get_gameObject()->AddComponent(); + } + canvas->get_gameObject()->SetActive(true); +} + +MAKE_HOOK_OFFSETLESS(AudioTimeSyncController_StartSong, void, AudioTimeSyncController* self, float startTimeOffset){ + AudioTimeSyncController_StartSong(self, startTimeOffset); + + if(getConfig().config["insong"].GetBool() == false){ + canvas->get_gameObject()->SetActive(false); + getLogger().info("SetActive"); + } +} + +MAKE_HOOK_OFFSETLESS(SoloFreePlayFlowCoordinator_SinglePlayerLevelSelectionFlowCoordinatorDidActivate, void, SoloFreePlayFlowCoordinator* self, bool firstActivation, bool addedToHierarchy){ + SoloFreePlayFlowCoordinator_SinglePlayerLevelSelectionFlowCoordinatorDidActivate(self, firstActivation, addedToHierarchy); + + if(getConfig().config["insong"].GetBool() == false){ + canvas->get_gameObject()->SetActive(true); + getLogger().info("SetActive"); + } +} + +MAKE_HOOK_OFFSETLESS(PauseMenuManager_ShowMenu, void, PauseMenuManager* self){ + PauseMenuManager_ShowMenu(self); + + if(getConfig().config["insong"].GetBool() == false){ + canvas->get_gameObject()->SetActive(true); + getLogger().info("SetActive"); + } +} + +MAKE_HOOK_OFFSETLESS(PauseMenuManager_StartResumeAnimation, void, PauseMenuManager* self){ + PauseMenuManager_StartResumeAnimation(self); + + if(getConfig().config["insong"].GetBool() == false){ + canvas->get_gameObject()->SetActive(false); + getLogger().info("SetActive"); + } +} + +MAKE_HOOK_OFFSETLESS(MultiplayerLobbyController_ActivateMultiplayerLobby, void, MultiplayerLobbyController* self){ + MultiplayerLobbyController_ActivateMultiplayerLobby(self); + + layout->get_transform()->set_position(UnityEngine::Vector3(0,-1.9,3)); +} + +MAKE_HOOK_OFFSETLESS(MultiplayerLobbyController_DeactivateMultiplayerLobby, void, MultiplayerLobbyController* self){ + MultiplayerLobbyController_DeactivateMultiplayerLobby(self); + + layout->get_transform()->set_position(UnityEngine::Vector3(0,-2.2,3)); +} + +// Called at the early stages of game loading +extern "C" void setup(ModInfo& info) { + info.id = "clockmod"; + info.version = VERSION; + modInfo = info; + + getConfig().Load(); // Load the config file + getLogger().info("Completed setup!"); + + rapidjson::Document::AllocatorType& allocator = getConfig().config.GetAllocator(); + if(!getConfig().config.HasMember("insong")){ + getConfig().config.AddMember("insong", rapidjson::Value(0).SetBool(false), allocator); + getConfig().Write(); + } +} + +// Called later on in the game loading - a good time to install function hooks +extern "C" void load() { + il2cpp_functions::Init(); + QuestUI::Init(); + + getLogger().info("Installing hooks..."); + + custom_types::Register::RegisterType(); + custom_types::Register::RegisterType(); + QuestUI::Register::RegisterModSettingsViewController(modInfo); + + INSTALL_HOOK_OFFSETLESS(MainMenuViewController_DidActivate, il2cpp_utils::FindMethodUnsafe("", "MainMenuViewController", "DidActivate", 3)); + INSTALL_HOOK_OFFSETLESS(AudioTimeSyncController_StartSong, il2cpp_utils::FindMethodUnsafe("", "AudioTimeSyncController", "StartSong", 1)); + INSTALL_HOOK_OFFSETLESS(SoloFreePlayFlowCoordinator_SinglePlayerLevelSelectionFlowCoordinatorDidActivate, il2cpp_utils::FindMethodUnsafe("", "SoloFreePlayFlowCoordinator", "SinglePlayerLevelSelectionFlowCoordinatorDidActivate", 2)); + INSTALL_HOOK_OFFSETLESS(PauseMenuManager_ShowMenu, il2cpp_utils::FindMethodUnsafe("", "PauseMenuManager", "ShowMenu", 0)); + INSTALL_HOOK_OFFSETLESS(PauseMenuManager_StartResumeAnimation, il2cpp_utils::FindMethodUnsafe("", "PauseMenuManager", "StartResumeAnimation", 0)); + INSTALL_HOOK_OFFSETLESS(MultiplayerLobbyController_ActivateMultiplayerLobby, il2cpp_utils::FindMethodUnsafe("", "MultiplayerLobbyController", "ActivateMultiplayerLobby", 0)); + INSTALL_HOOK_OFFSETLESS(MultiplayerLobbyController_DeactivateMultiplayerLobby, il2cpp_utils::FindMethodUnsafe("", "MultiplayerLobbyController", "DeactivateMultiplayerLobby", 0)); + + getLogger().info("Installed all hooks!"); +} \ No newline at end of file diff --git a/startlogging.bat b/startlogging.bat new file mode 100644 index 0000000..652e342 --- /dev/null +++ b/startlogging.bat @@ -0,0 +1,2 @@ +@ECHO OFF +adb logcat > log.txt \ No newline at end of file