From 3c7768c147a228df06bacf6921baddff98ccec81 Mon Sep 17 00:00:00 2001 From: somewhatlurker <52014015+somewhatlurker@users.noreply.github.com> Date: Sun, 20 Oct 2019 02:49:54 +1100 Subject: [PATCH] add pause menu (with one option) this is pretty annoying becuase it requires drawing the overlay after drawing text.. it's probably not a bad idea to ship a new text renderer so some of the dodginess can be avoided --- .../TLAC/Components/ComponentsManager.cpp | 8 + .../TLAC/Components/ComponentsManager.h | 1 + .../source/plugins/TLAC/Components/DrawText.h | 195 ++++++++++++++++++ .../TLAC/Components/EmulatorComponent.h | 1 + .../TLAC/Components/Input/InputEmulator.cpp | 5 +- .../source/plugins/TLAC/Components/Pause.cpp | 121 ++++++++++- .../source/plugins/TLAC/Components/Pause.h | 8 + source-code/source/plugins/TLAC/Constants.h | 1 + source-code/source/plugins/TLAC/TLAC.vcxproj | 1 + .../source/plugins/TLAC/TLAC.vcxproj.filters | 3 + source-code/source/plugins/TLAC/dllmain.cpp | 19 ++ 11 files changed, 350 insertions(+), 13 deletions(-) create mode 100644 source-code/source/plugins/TLAC/Components/DrawText.h diff --git a/source-code/source/plugins/TLAC/Components/ComponentsManager.cpp b/source-code/source/plugins/TLAC/Components/ComponentsManager.cpp index 4a63456..22e099d 100644 --- a/source-code/source/plugins/TLAC/Components/ComponentsManager.cpp +++ b/source-code/source/plugins/TLAC/Components/ComponentsManager.cpp @@ -143,6 +143,14 @@ namespace TLAC::Components } } + void ComponentsManager::UpdateDrawSprites() + { + for (auto& component : components) + { + component->UpdateDrawSprites(); + } + } + void ComponentsManager::UpdatePostDraw() { 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 1057940..cc1a397 100644 --- a/source-code/source/plugins/TLAC/Components/ComponentsManager.h +++ b/source-code/source/plugins/TLAC/Components/ComponentsManager.h @@ -28,6 +28,7 @@ namespace TLAC::Components void Update(); void UpdateInput(); void UpdatePostInput(); + void UpdateDrawSprites(); void UpdatePostDraw(); void OnFocusGain(); void OnFocusLost(); diff --git a/source-code/source/plugins/TLAC/Components/DrawText.h b/source-code/source/plugins/TLAC/Components/DrawText.h new file mode 100644 index 0000000..6ae3487 --- /dev/null +++ b/source-code/source/plugins/TLAC/Components/DrawText.h @@ -0,0 +1,195 @@ +#pragma once +#include +#include + +namespace TLAC::Components +{ +#pragma pack(push, 1) + struct RawFont + { + uint32_t sprId; // ? + uint8_t width1; // glyph? + uint8_t height1; // glyph? + uint8_t width2; // advance? + uint8_t height2; // advance? + uint8_t metric08; // or flag? + uint8_t metric09; // or flag? + uint8_t padding0a[0x06]; + float metric08divby09; + uint64_t _0x10; + int64_t dataBegin; + int64_t dataEnd; + int64_t dataCapacityEnd; + uint8_t padding38[0x8]; + }; + + struct RawFontHolderIdk // ...SeemsPrettyPointlessTbh + { + RawFont* rawfont; + uint16_t width1; + uint16_t height1; + uint16_t zero1; // ? + uint16_t zero2; // ? + uint8_t zero3; // some kind of flag, but seems unused + }; + + struct FontInfo + { + uint32_t fontId; + uint8_t padding04[0x4]; + RawFont* rawfont; + uint16_t flag10; // (zero3 != 0 && padding38[0] != 0) ? 2 : (metric08 != metric09 ? 1 : 0) + uint8_t padding12[0x02]; + float width1; + float height1; + float width2; + float height2; + float userSizeWidth; + float userSizeHeight; + float userSizeWidthMultiplier; // userSizeWidth / width1 + float userSizeHeightMultiplier; // userSizeHeight / width2 + float zero1; // ? + float zero2; // ? + + void setSize(float width, float height) + { + ((void(*)(FontInfo* fi, float width, float height))0x140199e60)(this, width, height); + } + + FontInfo(uint32_t id) + { + ((FontInfo*(*)(FontInfo* fi, uint32_t id))0x140196510)(this, id); + } + }; + + FontInfo*(*getFont)(FontInfo* fi, uint32_t id) = (FontInfo*(*)(FontInfo* fi, uint32_t id))0x140196510; + void(*fontSize)(FontInfo* fi, float width, float height) = (void(*)(FontInfo* fi, float width, float height))0x140199e60; + + struct DrawTextParams + { + uint32_t textColour; // RGBA byte array?, so set as 0xAABBGGRR + uint32_t strokeColour; // ?? RGBA byte array?, so set as 0xAABBGGRR + uint8_t unk08; + uint8_t padding09[0x3]; + uint32_t unk0c; + uint32_t unk10; + uint32_t unk14; + uint32_t unk18; + uint64_t unk1c; + uint32_t unk24; + uint32_t unk28; + float xBegin; // ? + float yBegin; // ? + float xCurrent; // ? + float yCurrent; // ? + uint8_t padding3c[0x4]; + uint64_t unk40; + FontInfo* font; + uint16_t unk50; + + DrawTextParams(FontInfo* fi) + { + textColour = 0xffffffff; + strokeColour = 0xff808080; + unk08 = 0; + unk0c = 0; + unk10 = 0; + unk14 = 0; + unk18 = 0; + unk1c = 0x7; + unk24 = 0xd; + unk28 = 0; + xBegin = 0; + yBegin = 0; + xCurrent = 0; + yCurrent = 0; + unk40 = 0; + font = fi; + unk50 = 0x25a1; + } + + DrawTextParams() + { + DrawTextParams((FontInfo*)0x140eda860); + } + }; + + /* struct MsString { + union { + char* string_ptr; + char string_buf[16]; + }; + uint64_t len; + uint64_t bufsize; + + char* GetCharBuf() + { + if (bufsize > 0xf && string_ptr != nullptr) + return string_ptr; + else + return string_buf; + }; + + void SetCharBuf(char* newcontent) + { + len = strlen(newcontent); + bufsize = len; + if (len > 0xf) + { + string_ptr = strdup(newcontent); + } + else + { + strcpy_s(string_buf, newcontent); + } + } + }; */ + + /* struct MsStringW { + union { + wchar_t* string_ptr; + wchar_t string_buf[8]; + }; + uint64_t len; + uint64_t bufsize; + + wchar_t* GetCharBuf() + { + if (bufsize > 0x7 && string_ptr != nullptr) + return string_ptr; + else + return string_buf; + }; + + void SetCharBuf(wchar_t* newcontent) + { + len = wcslen(newcontent); + bufsize = len; + if (len > 0xf) + { + string_ptr = wcsdup(newcontent); + } + else + { + wcscpy_s(string_buf, newcontent); + } + } + }; */ + + // flags aren't really known, but 1 == normal, 2 == right align?, 8 == centered + void drawText(DrawTextParams* dtParam, uint32_t flags, std::string str) + { + ((void(*)(DrawTextParams*, uint32_t, const char*, int64_t))0x140198500)(dtParam, flags, str.c_str(), str.length()); + } + + void drawTextW(DrawTextParams* dtParam, uint32_t flags, std::wstring str) + { + const wchar_t* ptrs[2]; + ptrs[0] = str.c_str(); + ptrs[1] = (wchar_t*)((uint64_t)ptrs[0] + str.length() * 2); + + ((void(*)(DrawTextParams*, uint32_t, const wchar_t**))0x140198380)(dtParam, flags, &ptrs[0]); + } + //void(*drawTextW)(DrawTextParams* dtParam, uint32_t flags, MsStringW str) = (void(*)(DrawTextParams* dtParam, uint32_t flags, MsStringW str))0x140198380; +#pragma pack(pop) +} \ No newline at end of file diff --git a/source-code/source/plugins/TLAC/Components/EmulatorComponent.h b/source-code/source/plugins/TLAC/Components/EmulatorComponent.h index 20955ae..69f63e8 100644 --- a/source-code/source/plugins/TLAC/Components/EmulatorComponent.h +++ b/source-code/source/plugins/TLAC/Components/EmulatorComponent.h @@ -17,6 +17,7 @@ namespace TLAC::Components virtual void UpdateInput() {}; virtual void UpdatePostInput() {}; + virtual void UpdateDrawSprites() {}; virtual void UpdatePostDraw() {}; virtual void OnFocusGain() {}; virtual void OnFocusLost() {}; diff --git a/source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp b/source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp index a26b38a..ce6776a 100644 --- a/source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp +++ b/source-code/source/plugins/TLAC/Components/Input/InputEmulator.cpp @@ -13,6 +13,7 @@ #include "../../Utilities/EnumBitwiseOperations.h" #include "../../FileSystem/ConfigFile.h" #include "../GameState.h" +#include "../Pause.h" const std::string KEY_CONFIG_FILE_NAME = "keyconfig.ini"; @@ -236,13 +237,13 @@ namespace TLAC::Components { JvsButtons buttons = JVS_NONE; - if (!(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN) && + if ((Pause::isPaused || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)) && buttonTestFunc(MenuLBinding)) { buttons |= JVS_L; return buttons; } - if (!(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN) && + if ((Pause::isPaused || !(*(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME && *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS == SUB_GAME_MAIN)) && buttonTestFunc(MenuRBinding)) { buttons |= JVS_R; diff --git a/source-code/source/plugins/TLAC/Components/Pause.cpp b/source-code/source/plugins/TLAC/Components/Pause.cpp index 9903377..8d198c0 100644 --- a/source-code/source/plugins/TLAC/Components/Pause.cpp +++ b/source-code/source/plugins/TLAC/Components/Pause.cpp @@ -1,8 +1,9 @@ #include "Pause.h" #include "../Constants.h" #include "GameState.h" +#include "DrawText.h" #include "Input/InputState.h" -#include "GL\glut.h" +#include "GL/glut.h" #include #include @@ -41,7 +42,7 @@ namespace TLAC::Components 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) + if (isUnpauseKeyTapped() || *(GameState*)CURRENT_GAME_STATE_ADDRESS != GS_GAME || *(SubGameState*)CURRENT_GAME_SUB_STATE_ADDRESS != SUB_GAME_MAIN) { setPaused(false); } @@ -60,6 +61,11 @@ namespace TLAC::Components menuPos %= menuItems.size(); + // actually use released when unpausing from a face button so it doesn't trigger input + // (this can trigger an unpause too) + if (inputState->Released.Buttons & JVS_CIRCLE) + menuItems[menuPos].second(); + // swallow all button inputs if paused inputState->Tapped.Buttons = JVS_NONE; inputState->DoubleTapped.Buttons = JVS_NONE; @@ -82,6 +88,47 @@ namespace TLAC::Components } } + void Pause::UpdateDrawSprites() + { + if (isPaused && showUI) + { + FontInfo fontInfo(0x11); + fontInfo.setSize(menuTextSize, menuTextSize); + DrawTextParams dtParams(&fontInfo); + + dtParams.strokeColour = 0xff000000; + + dtParams.xBegin = menuX; + dtParams.yBegin = menuY - menuItemHeight * (menuItems.size() / 2.0); + + for (int i = 0; i < menuItems.size(); i++) + { + std::pair &item = menuItems[i]; + + if (i == menuPos) + dtParams.textColour = 0xffffff00; + else + dtParams.textColour = 0xffffffff; + + dtParams.xCurrent = dtParams.xBegin; + dtParams.yCurrent = dtParams.yBegin; + drawText(&dtParams, 8, item.first); + dtParams.yBegin += menuItemHeight; + } + + fontInfo.setSize(18, 18); + + dtParams.xBegin = menuX; + dtParams.yBegin = 600; + dtParams.xCurrent = dtParams.xBegin; + dtParams.yCurrent = dtParams.yBegin; + + dtParams.textColour = 0xffffffff; + + drawTextW(&dtParams, 8, L"○:Select ×:Close L/R:Move □:Hide Menu"); + } + } + void Pause::UpdatePostDraw() { if (isPaused && showUI) @@ -111,24 +158,69 @@ namespace TLAC::Components glBegin(GL_QUADS); glBindTexture(GL_TEXTURE_2D, 0); - glColor4ub(0, 0, 0, 127); + glColor4ub(0, 0, 0, 64); glVertex2i(0, 0); glVertex2i(1280, 0); glVertex2i(1280, 720); glVertex2i(0, 720); + const int pauseWidth = 80; + const int pauseHeight = 110; + const int pauseGap = 20; + const int pausePosX = 32; + const int pausePosY = 32; + + const int pauseX1 = pausePosX; + const int pauseX2 = pauseX1 + (pauseWidth - pauseGap) / 2; + const int pauseX3 = pauseX2 + pauseGap; + const int pauseX4 = pauseX1 + pauseWidth; + + const int pauseY1 = pausePosY; + const int pauseY2 = pauseY1 + pauseHeight; + glColor4ub(255, 255, 255, 127); - glVertex2i(560, 250); - glVertex2i(620, 250); - glVertex2i(620, 470); - glVertex2i(560, 470); - glVertex2i(660, 250); - glVertex2i(720, 250); - glVertex2i(720, 470); - glVertex2i(660, 470); + glVertex2i(pauseX1, pauseY1); + glVertex2i(pauseX2, pauseY1); + glVertex2i(pauseX2, pauseY2); + glVertex2i(pauseX1, pauseY2); + glVertex2i(pauseX3, pauseY1); + glVertex2i(pauseX4, pauseY1); + glVertex2i(pauseX4, pauseY2); + glVertex2i(pauseX3, pauseY2); glEnd(); + glBegin(GL_QUAD_STRIP); + int selectBoxOrigin = menuY - menuItemHeight * (menuItems.size() / 2.0) - (menuItemHeight - menuTextSize) / 2; + int selectBoxPos = selectBoxOrigin + menuItemHeight * menuPos; + const int selectBoxWidth = 200; + const int selectBoxHeight = menuItemHeight; + const int selectBoxThickness = 2; + + const int selectBoxX1 = menuX - selectBoxWidth / 2; + const int selectBoxX4 = selectBoxX1 + selectBoxWidth; + const int selectBoxX2 = selectBoxX1 + selectBoxThickness; + const int selectBoxX3 = selectBoxX4 - selectBoxThickness; + + const int selectBoxY1 = selectBoxPos; + const int selectBoxY4 = selectBoxY1 + selectBoxHeight; + const int selectBoxY2 = selectBoxY1 + selectBoxThickness; + const int selectBoxY3 = selectBoxY4 - selectBoxThickness; + + glColor4ub(0, 255, 255, 127); + glVertex2i(selectBoxX2, selectBoxY2); + glVertex2i(selectBoxX1, selectBoxY1); + glVertex2i(selectBoxX3, selectBoxY2); + glVertex2i(selectBoxX4, selectBoxY1); + glVertex2i(selectBoxX3, selectBoxY3); + glVertex2i(selectBoxX4, selectBoxY4); + glVertex2i(selectBoxX2, selectBoxY3); + glVertex2i(selectBoxX1, selectBoxY4); + glVertex2i(selectBoxX2, selectBoxY2); + glVertex2i(selectBoxX1, selectBoxY1); + + glEnd(); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); @@ -142,6 +234,13 @@ namespace TLAC::Components return ((InputState*)(*(uint64_t*)INPUT_STATE_PTR_ADDRESS))->Tapped.Buttons & JVS_START; } + bool Pause::isUnpauseKeyTapped() + { + // actually use released when unpausing from a face button so it doesn't trigger input + return ((InputState*)(*(uint64_t*)INPUT_STATE_PTR_ADDRESS))->Tapped.Buttons & JVS_START || + ((InputState*)(*(uint64_t*)INPUT_STATE_PTR_ADDRESS))->Released.Buttons & JVS_CROSS; + } + void Pause::setPaused(bool pause) { uint64_t audioMixerAddr = *(uint64_t*)(AUDIO_MAIN_CLASS_ADDRESS + 0x70); diff --git a/source-code/source/plugins/TLAC/Components/Pause.h b/source-code/source/plugins/TLAC/Components/Pause.h index 0825cb9..70a3c18 100644 --- a/source-code/source/plugins/TLAC/Components/Pause.h +++ b/source-code/source/plugins/TLAC/Components/Pause.h @@ -15,12 +15,14 @@ namespace TLAC::Components virtual void Initialize(ComponentsManager*) override; virtual void Update() override; virtual void UpdatePostInput() override; + virtual void UpdateDrawSprites() override; virtual void UpdatePostDraw() override; static bool isPaused; private: // this is a mess of static so that menuItems can work static bool isPauseKeyTapped(); + static bool isUnpauseKeyTapped(); static void setPaused(bool pause); static std::vector streamPlayStates; static void InjectCode(void* address, const std::vector data); @@ -28,11 +30,17 @@ namespace TLAC::Components static std::vector origAetMovOp; static constexpr uint8_t* aetMovPatchAddress = (uint8_t*)0x1401703b3; + static const int menuX = 640; + static const int menuY = 360; + static const int menuItemHeight = 36; + static const int menuTextSize = 24; + bool showUI = true; unsigned int menuPos = 0; static void unpause() { setPaused(false); }; std::vector> menuItems = { std::pair(std::string("RESUME"), &unpause), + //std::pair(std::string("GIVE UP"), &unpause), }; }; } diff --git a/source-code/source/plugins/TLAC/Constants.h b/source-code/source/plugins/TLAC/Constants.h index 84ec16d..6714d3b 100644 --- a/source-code/source/plugins/TLAC/Constants.h +++ b/source-code/source/plugins/TLAC/Constants.h @@ -8,6 +8,7 @@ constexpr uint8_t JNE_OPCODE = 0x85; //constexpr uint64_t ENGINE_UPDATE_HOOK_TARGET_ADDRESS = 0x000000014018CC40; constexpr uint64_t ENGINE_UPDATE_INPUT_ADDRESS = 0x000000014018CBB0; +constexpr uint64_t ENGINE_DRAW_SPRITES_ADDRESS = 0x0000000140500EA0; constexpr uint64_t ENGINE_FINISH_DRAW_ADDRESS = 0x0000000140192730; constexpr uint64_t CURRENT_GAME_STATE_ADDRESS = 0x0000000140EDA810; diff --git a/source-code/source/plugins/TLAC/TLAC.vcxproj b/source-code/source/plugins/TLAC/TLAC.vcxproj index ca6164c..4ba0caf 100644 --- a/source-code/source/plugins/TLAC/TLAC.vcxproj +++ b/source-code/source/plugins/TLAC/TLAC.vcxproj @@ -111,6 +111,7 @@ + diff --git a/source-code/source/plugins/TLAC/TLAC.vcxproj.filters b/source-code/source/plugins/TLAC/TLAC.vcxproj.filters index c1a7c42..0d80993 100644 --- a/source-code/source/plugins/TLAC/TLAC.vcxproj.filters +++ b/source-code/source/plugins/TLAC/TLAC.vcxproj.filters @@ -198,6 +198,9 @@ Header Files + + Header Files + diff --git a/source-code/source/plugins/TLAC/dllmain.cpp b/source-code/source/plugins/TLAC/dllmain.cpp index 32c0b79..6bdf252 100644 --- a/source-code/source/plugins/TLAC/dllmain.cpp +++ b/source-code/source/plugins/TLAC/dllmain.cpp @@ -19,6 +19,7 @@ #pragma comment(lib, "detours.lib") void(__cdecl* divaEngineUpdate)() = (void(__cdecl*)())0x14018CC40; +void(__cdecl* divaEngineDrawSprites)(void* addr, int idk) = (void(__cdecl*)(void* addr, int idk))ENGINE_DRAW_SPRITES_ADDRESS; void(__cdecl* divaEngineFinishDraw)() = (void(__cdecl*)())ENGINE_FINISH_DRAW_ADDRESS; LRESULT CALLBACK MessageWindowProcessCallback(HWND, UINT, WPARAM, LPARAM); @@ -127,6 +128,11 @@ namespace TLAC ComponentsManager.OnFocusLost(); } + void UpdateDrawSprites() + { + ComponentsManager.UpdateDrawSprites(); + } + void UpdatePostDraw() { ComponentsManager.UpdatePostDraw(); @@ -348,6 +354,13 @@ void hookedEngineUpdate() //divaEngineUpdate(); } +void hookedEngineDrawSprites(void* addr, int idk) +{ + divaEngineDrawSprites(addr, idk); + if (idk == 0x0a) + TLAC::UpdateDrawSprites(); +} + void hookedEngineFinishDraw() { TLAC::UpdatePostDraw(); @@ -374,6 +387,12 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaEngineUpdate, hookedEngineUpdate); DetourTransactionCommit(); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourAttach(&(PVOID&)divaEngineDrawSprites, hookedEngineDrawSprites); + DetourTransactionCommit(); + DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)divaEngineFinishDraw, hookedEngineFinishDraw);