-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split up hooks into separate cpp files
- Loading branch information
1 parent
15f8f33
commit c5e2144
Showing
5 changed files
with
364 additions
and
231 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#pragma once | ||
|
||
#include "beatsaber-hook/shared/utils/hooking.hpp" | ||
#include "beatsaber-hook/shared/utils/logging.hpp" | ||
#include <vector> | ||
|
||
namespace QuestSounds { | ||
class Hooking { | ||
private: | ||
inline static std::vector<void (*)()> installFuncs; | ||
|
||
public: | ||
static void AddInstallFunc(void (*installFunc)()) { | ||
installFuncs.push_back(installFunc); | ||
} | ||
|
||
static inline void InstallHooks() { | ||
for (auto& func : installFuncs) func(); | ||
} | ||
}; | ||
|
||
template<auto mPtr> | ||
concept has_metadata = requires() { | ||
{ ::il2cpp_utils::il2cpp_type_check::MetadataGetter<mPtr>::methodInfo() } -> std::same_as<MethodInfo const*>; | ||
}; | ||
|
||
template<auto mPtr> | ||
requires(has_metadata<mPtr>) | ||
using Metadata = ::il2cpp_utils::il2cpp_type_check::MetadataGetter<mPtr>; | ||
|
||
/// @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<auto mPtr> | ||
concept match_hookable = has_metadata<mPtr> && Metadata<mPtr>::size >= (0x5 * sizeof(int32_t)) && Metadata<mPtr>::addrs != 0x0; | ||
} | ||
|
||
#define AUTO_INSTALL_PATCH(name_) \ | ||
struct Auto_Patch_##name_ { \ | ||
Auto_Patch_##name_() { \ | ||
::QuestSounds::Hooking::AddInstallFunc(Patch_##name_); \ | ||
} \ | ||
}; \ | ||
static Auto_Patch_##name_ Auto_Patch_Instance_##name_ | ||
|
||
#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<Hook_##name_>(logger); \ | ||
} \ | ||
Auto_Hook_##name_() { ::QuestSounds::Hooking::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<Hook_##name_>(logger); \ | ||
} \ | ||
Auto_Hook_##name_() { ::QuestSounds::Hooking::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(QuestSounds::match_hookable<mPtr>); \ | ||
static_assert(std::is_same_v<funcType, ::Hooking::InternalMethodCheck<decltype(mPtr)>::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<mPtr>::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_FIND_VERBOSE(name_, infoGet, retval, ...) \ | ||
struct Hook_##name_ { \ | ||
constexpr static const char* name() { return #name_; } \ | ||
static const MethodInfo* getInfo() { return infoGet; } \ | ||
using funcType = retval (*)(__VA_ARGS__); \ | ||
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__) | ||
|
||
#define MAKE_AUTO_HOOK_ORIG_MATCH(name_, mPtr, retval, ...) \ | ||
struct Hook_##name_ \ | ||
{ \ | ||
using funcType = retval (*)(__VA_ARGS__); \ | ||
static_assert(QuestSounds::match_hookable<mPtr>); \ | ||
static_assert(std::is_same_v<funcType, ::Hooking::InternalMethodCheck<decltype(mPtr)>::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<mPtr>::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__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#include "hooking.hpp" | ||
#include "logging.hpp" | ||
#include "Config.hpp" | ||
using namespace QuestSounds; | ||
|
||
// TODO: I'd like to get rid of this header | ||
#include "AudioClips.hpp" | ||
using namespace QuestSounds::AudioClips; | ||
|
||
#include "GlobalNamespace/SongPreviewPlayer.hpp" | ||
#include "GlobalNamespace/GameServerLobbyFlowCoordinator.hpp" | ||
#include "GlobalNamespace/MultiplayerModeSelectionFlowCoordinator.hpp" | ||
using namespace GlobalNamespace; | ||
|
||
|
||
MAKE_AUTO_HOOK_MATCH(SongPreviewPlayer_OnEnable, &SongPreviewPlayer::OnEnable, void, SongPreviewPlayer* self) { | ||
getLogger().info("is it true: %i", menuMusicLoader.loaded); | ||
|
||
if (!menuMusicLoader.OriginalAudioSource) { | ||
menuMusicLoader.set_OriginalClip(self->_defaultAudioClip); | ||
} | ||
|
||
if (menuMusicLoader.loaded && Config.Sounds.MenuMusic.Active) | ||
{ | ||
getLogger().debug("Overriding MenuMusic Audio"); | ||
UnityEngine::AudioClip* audioClip = menuMusicLoader.getClip(); | ||
if (audioClip != nullptr) | ||
self->_defaultAudioClip = audioClip; | ||
} | ||
else { | ||
getLogger().debug("Loading MenuMusic Audio normally: isLoaded='{}' isActive='{}'", menuMusicLoader.loaded, Config.Sounds.MenuMusic.Active); | ||
self->_defaultAudioClip = menuMusicLoader.get_OriginalClip(); | ||
} | ||
SongPreviewPlayer_OnEnable(self); | ||
} | ||
|
||
MAKE_AUTO_HOOK_MATCH(GameServerLobbyFlowCoordinator_DidActivate, &GameServerLobbyFlowCoordinator::DidActivate, void, GameServerLobbyFlowCoordinator* self, bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling) | ||
{ | ||
getLogger().debug("GameServerLobbyFlowCoordinator_DidActivate"); | ||
if (!lobbyAmbienceLoader.OriginalAudioSource) lobbyAmbienceLoader.set_OriginalClip(self->_ambienceAudioClip); | ||
|
||
if (lobbyAmbienceLoader.loaded && Config.Sounds.LobbyMusic.Active) | ||
{ | ||
getLogger().debug("Overwriting LobbyAmbience Audio"); | ||
self->_ambienceAudioClip = lobbyAmbienceLoader.getClip(); | ||
} | ||
else { | ||
self->_ambienceAudioClip = lobbyAmbienceLoader.get_OriginalClip(); | ||
} | ||
GameServerLobbyFlowCoordinator_DidActivate(self, firstActivation, addedToHierarchy, screenSystemEnabling); | ||
} | ||
|
||
MAKE_AUTO_HOOK_MATCH(GameServerLobbyFlowCoordinator_DidDeactivate, &GameServerLobbyFlowCoordinator::DidDeactivate, void, GameServerLobbyFlowCoordinator* self, bool removedFromHierarchy, bool screenSystemDisabling) | ||
{ | ||
getLogger().debug("GameServerLobbyFlowCoordinator_DidActivate"); | ||
if (menuMusicLoader.loaded && Config.Sounds.MenuMusic.Active && removedFromHierarchy) | ||
{ | ||
getLogger().debug("Switching LobbyMusic to MenuMusic Audio"); | ||
self->_ambienceAudioClip = menuMusicLoader.getClip(); | ||
} | ||
else { | ||
self->_ambienceAudioClip = menuMusicLoader.get_OriginalClip(); | ||
} | ||
GameServerLobbyFlowCoordinator_DidDeactivate(self, removedFromHierarchy, screenSystemDisabling); | ||
} | ||
|
||
MAKE_AUTO_HOOK_MATCH(MultiplayerModeSelectionFlowCoordinator_DidActivate, &MultiplayerModeSelectionFlowCoordinator::DidActivate, void, MultiplayerModeSelectionFlowCoordinator* self, bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling) | ||
{ | ||
getLogger().debug("MultiplayerModeSelectionFlowCoordinator_DidActivate"); | ||
if (menuMusicLoader.loaded && Config.Sounds.MenuMusic.Active) | ||
{ | ||
getLogger().debug("Switching LobbyMusic to MenuMusic Audio"); | ||
self->_ambienceAudioClip = menuMusicLoader.getClip(); | ||
} | ||
else { | ||
self->_ambienceAudioClip = menuMusicLoader.get_OriginalClip(); | ||
} | ||
MultiplayerModeSelectionFlowCoordinator_DidActivate(self, firstActivation, addedToHierarchy, screenSystemEnabling); // This has to be ran last, otherwise it will not work correctly | ||
} | ||
|
||
MAKE_AUTO_HOOK_MATCH(MultiplayerModeSelectionFlowCoordinator_DidDeactivate, &MultiplayerModeSelectionFlowCoordinator::DidDeactivate, void, MultiplayerModeSelectionFlowCoordinator* self, bool removedFromHierarchy, bool screenSystemDisabling) | ||
{ | ||
getLogger().debug("MultiplayerModeSelectionFlowCoordinator_DidDeactivate"); | ||
if (menuMusicLoader.loaded && Config.Sounds.MenuMusic.Active && removedFromHierarchy) | ||
{ | ||
self->_ambienceAudioClip = menuMusicLoader.getClip(); | ||
} | ||
else { | ||
self->_ambienceAudioClip = menuMusicLoader.get_OriginalClip(); | ||
} | ||
|
||
MultiplayerModeSelectionFlowCoordinator_DidDeactivate(self, removedFromHierarchy, screenSystemDisabling); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#include "hooking.hpp" | ||
#include "logging.hpp" | ||
#include "Config.hpp" | ||
using namespace QuestSounds; | ||
|
||
// TODO: I'd like to get rid of this header | ||
#include "AudioClips.hpp" | ||
using namespace QuestSounds::AudioClips; | ||
|
||
#include "GlobalNamespace/ResultsViewController.hpp" | ||
#include "GlobalNamespace/LevelCompletionResults.hpp" | ||
#include "GlobalNamespace/SongPreviewPlayer.hpp" | ||
#include "GlobalNamespace/FireworkItemController.hpp" | ||
using namespace GlobalNamespace; | ||
|
||
#pragma region LevelResultSound | ||
MAKE_AUTO_HOOK_MATCH(ResultsViewController_DidActivate, &ResultsViewController::DidActivate, void, ResultsViewController* self, bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling) { | ||
if (firstActivation && addedToHierarchy && !levelClearedLoader.OriginalAudioSource) { | ||
levelClearedLoader.set_OriginalClip(self->_levelClearedAudioClip); | ||
} | ||
if (self->_levelCompletionResults->levelEndStateType == LevelCompletionResults::LevelEndStateType::Failed) { | ||
self->_songPreviewPlayer->StopAllCoroutines(); | ||
if (levelFailedLoader.loaded && addedToHierarchy && Config.Sounds.LevelFailed.Active) { | ||
UnityEngine::AudioClip* FailedSound = levelFailedLoader.getClip(); | ||
float length = FailedSound->get_length(); | ||
getLogger().debug("Duration of LevelFailed Sound: {}", length); | ||
if (length > 7.0f) { | ||
getLogger().info("Long LevelFailedSound"); | ||
self->_songPreviewPlayer->CrossfadeTo(FailedSound, -4.0f, 0.0f, length, nullptr); | ||
} | ||
else { | ||
getLogger().info("Short LevelFailedSound"); | ||
self->_songPreviewPlayer->FadeOut(0.1f); | ||
self->_songPreviewPlayer->_fadeSpeed = self->_songPreviewPlayer->_fadeInSpeed; | ||
getLogger().debug("volume: {}", self->_songPreviewPlayer->_volume); | ||
getLogger().debug("AmbientVolume: {}", self->_songPreviewPlayer->_ambientVolumeScale); | ||
getLogger().debug("Set Volume: {}", self->_songPreviewPlayer->_volume * self->_songPreviewPlayer->_ambientVolumeScale); | ||
|
||
levelFailedLoader.audioSource->set_volume(self->_songPreviewPlayer->_volume * self->_songPreviewPlayer->_ambientVolumeScale); | ||
self->_songPreviewPlayer->StartCoroutine(self->_songPreviewPlayer->CrossFadeAfterDelayCoroutine(length - 1.2f)); | ||
levelFailedLoader.audioSource->Play(); | ||
} | ||
} | ||
} | ||
else { | ||
if (levelClearedLoader.loaded && addedToHierarchy && Config.Sounds.LevelCleared.Active) | ||
{ | ||
UnityEngine::AudioClip* audioClip = levelClearedLoader.getClip(); | ||
self->_levelClearedAudioClip = audioClip; | ||
} | ||
else { | ||
self->_levelClearedAudioClip = levelClearedLoader.get_OriginalClip(); | ||
} | ||
} | ||
ResultsViewController_DidActivate(self, firstActivation, addedToHierarchy, screenSystemEnabling); | ||
} | ||
|
||
MAKE_AUTO_HOOK_MATCH(ResultsViewController_RestartButtonPressed, &ResultsViewController::RestartButtonPressed, void, ResultsViewController* self) { | ||
if (levelFailedLoader.loaded && levelFailedLoader.audioSource->get_isPlaying()) { | ||
levelFailedLoader.audioSource->Stop(); | ||
} | ||
ResultsViewController_RestartButtonPressed(self); | ||
} | ||
#pragma endregion | ||
|
||
#pragma region FireworkSound | ||
// Replacing the function here, as replacing the AudioClips proves to be difficult | ||
MAKE_AUTO_HOOK_MATCH(FireworkItemController_PlayExplosionSound, &FireworkItemController::PlayExplosionSound, void, FireworkItemController* self) { | ||
if (fireworkSoundLoader.loaded && Config.Sounds.Firework.Active) { | ||
self->_audioSource->set_clip(fireworkSoundLoader.getClip()); | ||
float pitch = 1.2f + (((float)rand()) / (float)RAND_MAX) * (0.8f - 1.2f); | ||
self->_audioSource->set_pitch(pitch); | ||
self->_audioSource->Play(); | ||
} | ||
else FireworkItemController_PlayExplosionSound(self); | ||
} | ||
#pragma endregion |
Oops, something went wrong.