From 030850a6ddffa439cd198f7e7d4ff82b2eb5ec14 Mon Sep 17 00:00:00 2001 From: somewhatlurker <52014015+somewhatlurker@users.noreply.github.com> Date: Sat, 19 Oct 2019 15:29:07 +1100 Subject: [PATCH] significant work on Pause component (not ready yet, but feel free to test) --- .../TLAC/Components/ComponentsManager.cpp | 10 ++ .../TLAC/Components/ComponentsManager.h | 1 + .../TLAC/Components/EmulatorComponent.h | 1 + .../source/plugins/TLAC/Components/Pause.cpp | 124 ++++++++++++++++++ .../source/plugins/TLAC/Components/Pause.h | 29 ++++ source-code/source/plugins/TLAC/Constants.h | 12 ++ source-code/source/plugins/TLAC/TLAC.vcxproj | 2 + .../source/plugins/TLAC/TLAC.vcxproj.filters | 6 + source-code/source/plugins/TLAC/dllmain.cpp | 2 + 9 files changed, 187 insertions(+) create mode 100644 source-code/source/plugins/TLAC/Components/Pause.cpp create mode 100644 source-code/source/plugins/TLAC/Components/Pause.h diff --git a/source-code/source/plugins/TLAC/Components/ComponentsManager.cpp b/source-code/source/plugins/TLAC/Components/ComponentsManager.cpp index a5599c8..99ccff2 100644 --- a/source-code/source/plugins/TLAC/Components/ComponentsManager.cpp +++ b/source-code/source/plugins/TLAC/Components/ComponentsManager.cpp @@ -12,6 +12,7 @@ #include "DebugComponent.h" #include "ScaleComponent.h" #include "ScoreSaver.h" +#include "Pause.h" #include "GameTargets/TargetInspector.h" using ConfigFile = TLAC::FileSystem::ConfigFile; @@ -36,6 +37,7 @@ namespace TLAC::Components new InputEmulator(), new TouchSliderEmulator(), new TouchPanelEmulator(), + new Pause(), // ensure pause is always immediately after input emulators so it can swallow inputs new PlayerDataManager(), new FrameRateManager(), new FastLoader(), @@ -133,6 +135,14 @@ namespace TLAC::Components component->UpdateInput(); } + void ComponentsManager::UpdatePostInput() + { + for (auto& component : components) + { + component->UpdatePostInput(); + } + } + void ComponentsManager::OnFocusGain() { for (auto& component : components) diff --git a/source-code/source/plugins/TLAC/Components/ComponentsManager.h b/source-code/source/plugins/TLAC/Components/ComponentsManager.h index 0c20c0e..c263f37 100644 --- a/source-code/source/plugins/TLAC/Components/ComponentsManager.h +++ b/source-code/source/plugins/TLAC/Components/ComponentsManager.h @@ -27,6 +27,7 @@ namespace TLAC::Components void Initialize(); void Update(); void UpdateInput(); + void UpdatePostInput(); void OnFocusGain(); void OnFocusLost(); void Dispose(); diff --git a/source-code/source/plugins/TLAC/Components/EmulatorComponent.h b/source-code/source/plugins/TLAC/Components/EmulatorComponent.h index 48b6175..6b940a6 100644 --- a/source-code/source/plugins/TLAC/Components/EmulatorComponent.h +++ b/source-code/source/plugins/TLAC/Components/EmulatorComponent.h @@ -16,6 +16,7 @@ namespace TLAC::Components virtual void Update() = 0; virtual void UpdateInput() {}; + virtual void UpdatePostInput() {}; virtual void OnFocusGain() {}; virtual void OnFocusLost() {}; diff --git a/source-code/source/plugins/TLAC/Components/Pause.cpp b/source-code/source/plugins/TLAC/Components/Pause.cpp new file mode 100644 index 0000000..fb349a4 --- /dev/null +++ b/source-code/source/plugins/TLAC/Components/Pause.cpp @@ -0,0 +1,124 @@ +#include "Pause.h" +#include "../Constants.h" +#include "GameState.h" +#include "Input/InputState.h" +#include +#include + +namespace TLAC::Components +{ + Pause::Pause() + { + } + + Pause::~Pause() + { + } + + const char* Pause::GetDisplayName() + { + return "pause"; + } + + void Pause::Initialize(ComponentsManager*) + { + origAetMovOp.resize(8); + memcpy(&origAetMovOp[0], aetMovPatchAddress, 8); + } + + void Pause::Update() + { + + } + + void Pause::UpdatePostInput() + { + if (isPaused) + { + // exit pause if key is tapped or no longer in game somehow + if (isPauseKeyTapped() || *(GameState*)CURRENT_GAME_STATE_ADDRESS != GS_GAME || *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS != SUB_GAME_MAIN) + { + setPaused(false); + } + else + { + // swallow all button inputs if paused + InputState* inputState = (InputState*)(*(uint64_t*)INPUT_STATE_PTR_ADDRESS); + inputState->Tapped.Buttons = JVS_NONE; + inputState->DoubleTapped.Buttons = JVS_NONE; + inputState->Down.Buttons = JVS_NONE; + inputState->Released.Buttons = JVS_NONE; + inputState->IntervalTapped.Buttons = JVS_NONE; + // todo: slider + } + } + else + { + // only enter pause if in game + if (*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN) + { + if (isPauseKeyTapped()) + { + setPaused(true); + } + } + } + } + + bool Pause::isPauseKeyTapped() + { + return ((InputState*)(*(uint64_t*)INPUT_STATE_PTR_ADDRESS))->Tapped.Buttons & JVS_START; + } + + void Pause::setPaused(bool pause) + { + uint64_t audioMixerAddr = *(uint64_t*)(AUDIO_MAIN_CLASS_ADDRESS + 0x70); + uint64_t audioStreamsAddress = *(uint64_t*)(audioMixerAddr + 0x18);; + int nAudioStreams = *(uint64_t*)(audioMixerAddr + 0x20); + + if (pause) + { + *(float*)FRAME_SPEED_ADDRESS = 0.0f; // todo: hook getFrameSpeed so this can't be screwed up + ((void(*)())DSC_PAUSE_FUNC_ADDRESS)(); + + InjectCode(aetMovPatchAddress, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); + + for (int i = 0; i < nAudioStreams; i++) + { + uint32_t* playstate = (uint32_t*)(audioStreamsAddress + i * 0x50 + 0x18); + if (i < streamPlayStates.size()) + streamPlayStates[i] = *playstate; + else + streamPlayStates.push_back(*playstate); + + *playstate = 0; + } + } + else + { + *(float*)FRAME_SPEED_ADDRESS = 1.0f; + ((void(*)())DSC_UNPAUSE_FUNC_ADDRESS)(); + + InjectCode(aetMovPatchAddress, origAetMovOp); + + for (int i = 0; i < nAudioStreams; i++) + { + uint32_t* playstate = (uint32_t*)(audioStreamsAddress + i * 0x50 + 0x18); + if (i < streamPlayStates.size()) + *playstate = streamPlayStates[i]; + } + } + + isPaused = pause; + } + + void Pause::InjectCode(void* address, const std::vector data) + { + const size_t byteCount = data.size() * sizeof(uint8_t); + + DWORD oldProtect; + VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect); + memcpy(address, data.data(), byteCount); + VirtualProtect(address, byteCount, oldProtect, nullptr); + } +} diff --git a/source-code/source/plugins/TLAC/Components/Pause.h b/source-code/source/plugins/TLAC/Components/Pause.h new file mode 100644 index 0000000..762845a --- /dev/null +++ b/source-code/source/plugins/TLAC/Components/Pause.h @@ -0,0 +1,29 @@ +#pragma once +#include "EmulatorComponent.h" +#include + +namespace TLAC::Components +{ + class Pause : public EmulatorComponent + { + public: + Pause(); + ~Pause(); + + virtual const char* GetDisplayName() override; + + virtual void Initialize(ComponentsManager*) override; + virtual void Update() override; + virtual void UpdatePostInput() override; + + private: + bool isPaused; + bool isPauseKeyTapped(); + void setPaused(bool pause); + std::vector streamPlayStates; + void InjectCode(void* address, const std::vector data); + + std::vector origAetMovOp; + uint8_t* aetMovPatchAddress = (uint8_t*)0x1401703b3; + }; +} diff --git a/source-code/source/plugins/TLAC/Constants.h b/source-code/source/plugins/TLAC/Constants.h index d5ce191..6f51f6f 100644 --- a/source-code/source/plugins/TLAC/Constants.h +++ b/source-code/source/plugins/TLAC/Constants.h @@ -97,6 +97,18 @@ constexpr uint64_t CURRENT_SONG_ID_ADDRESS = 0x0000000140CDD8E0; constexpr uint64_t SELPV_CURRENT_SONG_ADDRESS = 0x000000014CC12438; constexpr uint64_t SONG_CLEAR_COUNTS_ADDRESS = 0x00000001411A95E8; +constexpr uint64_t AUDIO_MAIN_CLASS_ADDRESS = 0x000000014CC61120; + +constexpr uint64_t DSC_TIME_ADDRESS = 0x0000000140D0B518; +constexpr uint64_t DSC_START_FROM_TIME_ADDRESS = 0x0000000140D0B540; +constexpr uint64_t DSC_START_SYS_TIME_ADDRESS = 0x0000000140D0B548; +constexpr uint64_t DSC_TIME_ADDRESS_2 = 0x0000000140D0B520; +constexpr uint64_t DSC_START_FROM_TIME_ADDRESS_2 = 0x0000000140D0B560; +constexpr uint64_t DSC_START_SYS_TIME_ADDRESS_2 = 0x0000000140D0B568; + +constexpr uint64_t DSC_PAUSE_FUNC_ADDRESS = 0x00000001401295C0; +constexpr uint64_t DSC_UNPAUSE_FUNC_ADDRESS = 0x0000000140129590; + #define XINPUT_A 0x00 #define XINPUT_B 0x01 #define XINPUT_X 0x02 diff --git a/source-code/source/plugins/TLAC/TLAC.vcxproj b/source-code/source/plugins/TLAC/TLAC.vcxproj index 7fa64e0..ca6164c 100644 --- a/source-code/source/plugins/TLAC/TLAC.vcxproj +++ b/source-code/source/plugins/TLAC/TLAC.vcxproj @@ -128,6 +128,7 @@ + @@ -181,6 +182,7 @@ + diff --git a/source-code/source/plugins/TLAC/TLAC.vcxproj.filters b/source-code/source/plugins/TLAC/TLAC.vcxproj.filters index d95a19b..c1a7c42 100644 --- a/source-code/source/plugins/TLAC/TLAC.vcxproj.filters +++ b/source-code/source/plugins/TLAC/TLAC.vcxproj.filters @@ -195,6 +195,9 @@ Header Files + + Header Files + @@ -329,5 +332,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/source-code/source/plugins/TLAC/dllmain.cpp b/source-code/source/plugins/TLAC/dllmain.cpp index 26efd73..1b474ef 100644 --- a/source-code/source/plugins/TLAC/dllmain.cpp +++ b/source-code/source/plugins/TLAC/dllmain.cpp @@ -101,6 +101,8 @@ namespace TLAC ComponentsManager.UpdateInput(); } + ComponentsManager.UpdatePostInput(); + if ((framework::inputDisable)) { Input::Keyboard::GetInstance()->PollInput();