From 43a9a323af8cc110ccba45a7ffea55a59af48636 Mon Sep 17 00:00:00 2001 From: arol <completionoftime@gmail.com> Date: Tue, 23 Jul 2024 00:37:22 -0600 Subject: [PATCH] Revamped API for main, new imgui style, etc. --- mod-demo/include/api.h | 26 ++++++-- src/api.cpp | 139 ++++++++++++++++++++++++++++++++++++++--- src/include/api.h | 22 +++++-- src/main.cpp | 32 ++++++---- src/menu.cpp | 133 ++++++++++++++++++++++++++++++++------- src/mod_loader.cpp | 9 ++- 6 files changed, 302 insertions(+), 59 deletions(-) diff --git a/mod-demo/include/api.h b/mod-demo/include/api.h index 368254c..2c60096 100644 --- a/mod-demo/include/api.h +++ b/mod-demo/include/api.h @@ -36,12 +36,28 @@ class ModApi { uintptr_t GetSkyBase(); uintptr_t GetSkySize(); - uintptr_t Scan(const char *signature); - uintptr_t Scan(const char *signature, uintptr_t start, size_t size); - - void Hook(uintptr_t addr, void* newFn, void** oldFn); + uintptr_t Scan(const char* signature); + uintptr_t Scan(const char* signature, uintptr_t start, size_t size); - void UnHook(uintptr_t addr); + uintptr_t ScanPattern(lm_bytearr_t pattern, const char* masking); + uintptr_t ScanPattern(lm_bytearr_t pattern, const char* masking, uintptr_t start, size_t size); + + uintptr_t ScanData(lm_bytearr_t data, size_t scansize); + uintptr_t ScanData(lm_bytearr_t data, size_t size, uintptr_t start, size_t scansize); + + bool Hook(uintptr_t addr, void* newFn, void** oldFn); + bool Patch(uintptr_t address, const std::vector<unsigned char>& patchBytes, bool toggle = true); + bool Unpatch(uintptr_t address, const std::vector<unsigned char>& unpatchBytes); + bool Restore(uintptr_t address); + bool SetByte(uintptr_t address, std::vector<unsigned char> setByte); + + bool FastHook(uintptr_t addr, void* newFn, void** oldFn); + bool FastPatch(uintptr_t address, const std::vector<unsigned char>& patchBytes, bool toggle = true); + bool FastUnpatch(uintptr_t address, const std::vector<unsigned char>& unpatchBytes); + bool FastRestore(uintptr_t address); + bool FastSetByte(uintptr_t address, std::vector<unsigned char> setByte); + + bool UnHook(uintptr_t addr); }; #define API ModApi::Instance() \ No newline at end of file diff --git a/src/api.cpp b/src/api.cpp index b754643..41104e8 100644 --- a/src/api.cpp +++ b/src/api.cpp @@ -56,26 +56,43 @@ uintptr_t ModApi::Scan(const char *signature, uintptr_t start, size_t size){ return LM_SigScan(signature, start, size); } +uintptr_t ModApi::ScanPattern(lm_bytearr_t pattern, const char* masking) { + return LM_PatternScan(pattern, masking, skyBase, skySize); +} + +uintptr_t ModApi::ScanPattern(lm_bytearr_t pattern, const char* masking, uintptr_t start, size_t size) { + return LM_PatternScan(pattern, masking, start, size); +} + +uintptr_t ModApi::ScanData(lm_bytearr_t data, size_t scansize) { + return LM_DataScan(data, skySize, skyBase, scansize); +} +uintptr_t ModApi::ScanData(lm_bytearr_t data, size_t size, uintptr_t start, size_t scansize) { + return LM_DataScan(data, size, start, scansize); +} bool ModApi::Hook(uintptr_t addr, void* newFn, void** oldFn) { - //todo: check if already hooked,Multiple modification hooks for the same function HookDef hook; - hook.addr = addr; - hook.newFn = newFn; - hook.oldFn = oldFn; + + if (hooks.contains(addr)) { // dogshit_check.cpp + printf("hooking : function is already hooked!"); + return true; + } + hook.addr = addr; hook.newFn = newFn; hook.oldFn = oldFn; + hook.size = LM_HookCode(addr, (lm_address_t)newFn, (lm_address_t*)oldFn); - if(!hook.size) + if (!hook.size) return false; + hooks[addr] = hook; return true; } bool ModApi::UnHook(uintptr_t addr) { - //todo: auto it = hooks.begin(); - if ((it = hooks.find(addr)) != hooks.end()) { - if(LM_UnhookCode(addr, (lm_address_t )*(it->second.oldFn), it->second.size)){ + if ((it = hooks.find(addr)) != hooks.end()) { + if (LM_UnhookCode(addr, (lm_address_t) * (it->second.oldFn), it->second.size)) { hooks.erase(addr); return true; } @@ -92,7 +109,7 @@ bool ModApi::Patch(uintptr_t address, const std::vector<unsigned char>& patchByt if (it == OriginalBytes.end()) { size_t size = patchBytes.size(); // Change the protection to ReadWriteable - if (!LM_ProtMemory(address, size,LM_PROT_XRW, NULL)) { + if (!LM_ProtMemory(address, size, LM_PROT_XRW, NULL)) { std::cerr << "Failed to Change protection at address: " << std::hex << address << std::endl; return false; } @@ -114,5 +131,109 @@ bool ModApi::Patch(uintptr_t address, const std::vector<unsigned char>& patchByt return false; } + return true; +} + +bool ModApi::Unpatch(uintptr_t address, const std::vector<unsigned char>& unpatchBytes) { + size_t size = unpatchBytes.size(); + if (!LM_FreeMemory(address, size)) { + std::cerr << "Failed to free memory at address: " << std::hex << address << std::endl; + return true; + } + + return false; +} + +bool ModApi::Restore(uintptr_t address) { + auto it = OriginalBytes.find(address); + if (it == OriginalBytes.end()) { + std::cerr << "Original bytes not found for address: " << std::hex << address << std::endl; + return false; + } + + const std::vector<unsigned char>& OriginalBytes = it->second; + if (!LM_WriteMemory(address, OriginalBytes.data(), OriginalBytes.size())) { + std::cerr << "Failed to restore memory at address: " << std::hex << address << std::endl; + return false; + } + + return true; +} + +bool ModApi::SetByte(uintptr_t address, std::vector<unsigned char> setByte) { + address += skyBase; // Ensure address is relative to Sky_Base + + if (OriginalBytes.find(address) == OriginalBytes.end()) { + if (!LM_ProtMemory(address, setByte.size(), LM_PROT_XRW, NULL)) { + std::cerr << "Failed to Change protection at address: " << std::hex << address << std::endl; + return false; + } + } + + lm_byte_t* byte = setByte.data(); + if (!LM_SetMemory(address, *(byte), OriginalBytes[address].size())) { + std::cerr << "Failed to set memory at address: " << std::hex << address << std::endl; + return false; + } + + return true; +} + +// fastfunctions (basically functions checkless counterparts) +// WARNING : fastfunctions should only be used for patches if you are extremely confident that it wont kill your game. +bool ModApi::FastHook(uintptr_t addr, void* newFn, void** oldFn) { + HookDef hook; + + hook.addr = addr; hook.newFn = newFn; hook.oldFn = oldFn; + hook.size = LM_HookCode(addr, (lm_address_t)newFn, (lm_address_t*)oldFn); + + hooks[addr] = hook; + return true; +} + +bool ModApi::FastPatch(uintptr_t address, const std::vector<unsigned char>& patchBytes, bool toggle) { + address += skyBase; + + auto it = OriginalBytes.find(address); + if (it == OriginalBytes.end()) { + size_t size = patchBytes.size(); + LM_ProtMemory(address, size, LM_PROT_XRW, NULL); + + std::vector<unsigned char> originalBytes(size); + LM_ReadMemory(address, originalBytes.data(), size); + } + + const unsigned char* dataPtr = toggle ? patchBytes.data() : OriginalBytes[address].data(); + LM_WriteMemory(address, dataPtr, OriginalBytes[address].size()); + return true; +} + + +bool ModApi::FastUnpatch(uintptr_t address, const std::vector<unsigned char>& unpatchBytes) { + size_t size = unpatchBytes.size(); + LM_FreeMemory(address, size); + + return false; +} + +bool ModApi::FastRestore(uintptr_t address) { + auto it = OriginalBytes.find(address); + + const std::vector<unsigned char>& OriginalBytes = it->second; + LM_WriteMemory(address, OriginalBytes.data(), OriginalBytes.size()); + + return true; +} + +bool ModApi::FastSetByte(uintptr_t address, std::vector<unsigned char> setByte) { + address += skyBase; // Ensure address is relative to Sky_Base + + if (OriginalBytes.find(address) == OriginalBytes.end()) { + LM_ProtMemory(address, setByte.size(), LM_PROT_XRW, NULL); + } + + lm_byte_t* byte = setByte.data(); + LM_SetMemory(address, *(byte), OriginalBytes[address].size()); + return true; } \ No newline at end of file diff --git a/src/include/api.h b/src/include/api.h index 54ac943..5b07c0c 100644 --- a/src/include/api.h +++ b/src/include/api.h @@ -4,6 +4,7 @@ #include <cstdint> #include <string> #include <vector> +#include <libmem.h> #ifdef _MSC_VER #define MOD_API __declspec(dllexport) @@ -41,13 +42,26 @@ class MOD_API ModApi { uintptr_t GetSkyBase(); uintptr_t GetSkySize(); - uintptr_t Scan(const char *signature); - uintptr_t Scan(const char *signature, uintptr_t start, size_t size); + uintptr_t Scan(const char* signature); + uintptr_t Scan(const char* signature, uintptr_t start, size_t size); - bool Hook(uintptr_t addr, void* newFn, void** oldFn); + uintptr_t ScanPattern(lm_bytearr_t pattern, const char* masking); + uintptr_t ScanPattern(lm_bytearr_t pattern, const char* masking, uintptr_t start, size_t size); - bool UnHook(uintptr_t addr); + uintptr_t ScanData(lm_bytearr_t data, size_t scansize); + uintptr_t ScanData(lm_bytearr_t data, size_t size, uintptr_t start, size_t scansize); + bool Hook(uintptr_t addr, void* newFn, void** oldFn); bool Patch(uintptr_t address, const std::vector<unsigned char>& patchBytes, bool toggle = true); + bool Unpatch(uintptr_t address, const std::vector<unsigned char>& unpatchBytes); + bool Restore(uintptr_t address); + bool SetByte(uintptr_t address, std::vector<unsigned char> setByte); + bool FastHook(uintptr_t addr, void* newFn, void** oldFn); + bool FastPatch(uintptr_t address, const std::vector<unsigned char>& patchBytes, bool toggle = true); + bool FastUnpatch(uintptr_t address, const std::vector<unsigned char>& unpatchBytes); + bool FastRestore(uintptr_t address); + bool FastSetByte(uintptr_t address, std::vector<unsigned char> setByte); + + bool UnHook(uintptr_t addr); }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 94dbde1..60e623a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,7 +47,7 @@ __declspec(dllexport) POWER_PLATFORM_ROLE PowerDeterminePlatformRole(){ void InitConsole(){ FreeConsole(); AllocConsole(); - SetConsoleTitle("SML Console"); + SetConsoleTitle("SML Console - 0.1.2 - TgcMainWindow::VulkanRendering"); if (IsValidCodePage(CP_UTF8)) { SetConsoleCP(CP_UTF8); @@ -88,6 +88,8 @@ void loadWrapper(){ dllHandle = LoadLibrary("C:\\Windows\\System32\\POWRPROF.dll"); } + printf("Loading powrprof.dll symbols..."); + if (dllHandle != NULL) { o_GetPwrCapabilities = (BOOLEAN(*)(PSYSTEM_POWER_CAPABILITIES))GetProcAddress(dllHandle, "GetPwrCapabilities"); o_CallNtPowerInformation = (NTSTATUS (*)(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG))GetProcAddress(dllHandle, "CallNtPowerInformation"); @@ -127,18 +129,19 @@ static LRESULT WINAPI WndProc(const HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM void terminateCrashpadHandler() { - PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (Process32First(snapshot, &entry) == TRUE) { while (Process32Next(snapshot, &entry) == TRUE) { if (lstrcmp(entry.szExeFile, "crashpad_handler.exe") == 0) { HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, entry.th32ProcessID); - if (hProcess!= NULL) { + if (hProcess != NULL) { TerminateProcess(hProcess, 0); CloseHandle(hProcess); + printf("Detected and closed crashpad_handler.exe"); } } } @@ -237,18 +240,21 @@ LSTATUS hkRegEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpc } -DWORD WINAPI hook_thread(PVOID lParam){ - HWND window = nullptr; - printf("Searching for window...\n"); - while(!window){ +DWORD WINAPI hook_thread(PVOID lParam) { + HWND window = nullptr; + printf("Searching for TgcMainWindow...\n"); + while (!window) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); window = FindWindowA("TgcMainWindow", "Sky"); - } - printf("Window Found: %p\n", window); - layer::setup(window); + } + printf("Complete! info: %p\n", window); + + // todo: add something a little special here. + layer::setup(window); oWndProc = reinterpret_cast<WNDPROC>(SetWindowLongPtr(window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc))); InitConsole(); Sleep(3000); + printf("Finished hook_thread routine, loading mods."); //clear_screen(); return EXIT_SUCCESS; } @@ -259,7 +265,7 @@ DWORD WINAPI console_thread(LPVOID lpParam){ } -void onAttach(){ +void onAttach() { loadWrapper(); WCHAR path[MAX_PATH]; GetModuleFileNameW(NULL, path, MAX_PATH); @@ -267,9 +273,9 @@ void onAttach(){ std::string _path(ws.begin(), ws.end()); g_path = _path.substr(0, _path.find_last_of("\\/")); HMODULE handle = LoadLibrary("advapi32.dll"); - if(handle!= NULL){ + if (handle != NULL) { lm_address_t fnRegEnumValue = (lm_address_t)GetProcAddress(handle, "RegEnumValueA"); - LM_HookCode(fnRegEnumValue, (lm_address_t)&hkRegEnumValueA, (lm_address_t *)&oRegEnumValueA); + LM_HookCode(fnRegEnumValue, (lm_address_t)&hkRegEnumValueA, (lm_address_t*)&oRegEnumValueA); InitConsole(); terminateCrashpadHandler(); ModApi::Instance().InitSkyBase(); diff --git a/src/menu.cpp b/src/menu.cpp index a47eaff..784c6c6 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -105,6 +105,91 @@ namespace Menu { ImGui::CreateContext( ); ImGui_ImplWin32_Init(hwnd); +#pragma region imgui-style + ImGuiStyle* style = &ImGui::GetStyle(); + style->WindowPadding = ImVec2(9, 9); + style->FramePadding = ImVec2(9, 4); + style->ItemSpacing = ImVec2(6, 4); + style->ItemInnerSpacing = ImVec2(4, 4); + style->IndentSpacing = 20; + style->ScrollbarSize = 8; + style->ScrollbarRounding = 12; + style->GrabMinSize = 15; + style->WindowBorderSize = 1; + style->ChildBorderSize = 1; + style->PopupBorderSize = 1; + style->FrameBorderSize = 0; // ?? + style->TabBorderSize = 1; + style->TabBarBorderSize = 1; + style->WindowRounding = 6; + style->ChildRounding = 6; + style->FrameRounding = 3; + style->PopupRounding = 6; + style->GrabRounding = 4; + style->TabRounding = 4; + style->CellPadding = ImVec2(2, 2); + style->WindowTitleAlign = ImVec2(0.02f, 0.50f); + style->SeparatorTextBorderSize = 2; + style->SeparatorTextPadding = ImVec2(8, 0); + + ImVec4* colors = style->Colors; + colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.08f, 0.08f, 0.08f, 1.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.21f, 0.21f, 0.21f, 0.18f); + colors[ImGuiCol_PopupBg] = ImVec4(0.05f, 0.05f, 0.05f, 0.73f); + colors[ImGuiCol_Border] = ImVec4(1.00f, 1.00f, 1.00f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.18f, 0.18f, 0.18f, 0.54f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.29f, 0.29f, 0.29f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.53f, 0.53f, 0.53f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.65f, 0.65f, 0.65f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.21f, 0.21f, 0.21f, 1.00f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.52f, 0.52f, 0.52f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.54f, 0.54f, 0.54f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.83f, 0.83f, 0.83f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.29f, 0.29f, 0.29f, 0.50f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.29f, 0.29f, 0.29f, 0.50f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.29f, 0.29f, 0.29f, 0.50f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.52f, 0.52f, 0.52f, 0.50f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.67f, 0.67f, 0.67f, 0.50f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.74f, 0.74f, 0.74f, 0.95f); + colors[ImGuiCol_Tab] = ImVec4(0.19f, 0.19f, 0.19f, 0.86f); + colors[ImGuiCol_TabHovered] = ImVec4(0.27f, 0.27f, 0.27f, 0.80f); + colors[ImGuiCol_TabActive] = ImVec4(0.46f, 0.46f, 0.46f, 1.00f); + colors[ImGuiCol_TabUnfocused] = ImVec4(0.27f, 0.27f, 0.27f, 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.37f, 0.37f, 0.37f, 1.00f); + colors[ImGuiCol_DockingPreview] = ImVec4(0.46f, 0.46f, 0.46f, 0.70f); + colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); + colors[ImGuiCol_PlotLines] = ImVec4(0.77f, 0.77f, 0.77f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.91f, 0.91f, 0.91f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.62f, 0.62f, 0.62f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.21f, 0.21f, 0.21f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.36f, 0.36f, 0.36f, 1.00f); + colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.23f, 1.00f); + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.72f, 0.72f, 0.72f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = ImVec4(0.66f, 0.66f, 0.66f, 1.00f); + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.19f, 0.19f, 0.19f, 1.00f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.63f, 0.63f, 0.63f, 1.00f); +#pragma endregion + loadFontConfig("sml_config.json", fontconfig); LoadFontsFromFolder(fontconfig); @@ -114,7 +199,7 @@ namespace Menu { void HelpMarker(const char* description){ - ImGui::TextDisabled("(?)"); + ImGui::TextDisabled("<?>"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); @@ -128,45 +213,47 @@ namespace Menu { void SMLMainMenu() { char buf[64]; - ig::SetNextWindowSize({200, 0}, ImGuiCond_Once); - if(ig::Begin("SML Main",nullptr,ImGuiWindowFlags_AlwaysAutoResize)) { + ImGuiIO& io = ImGui::GetIO(); + + ig::SetNextWindowSize({ 200, 0 }, ImGuiCond_Once); + if (ig::Begin("SML Main", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::SeparatorText(("Mods (" + std::to_string(ModLoader::GetModCount()) + ")").c_str()); ig::BeginTable("##mods", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBody); ig::TableSetupColumn("Mod", ImGuiTableColumnFlags_WidthStretch); - ig::TableSetupColumn( "Info", ImGuiTableColumnFlags_WidthFixed, ImGui::CalcTextSize("Info").x); - - for(int i = 0; i < ModLoader::GetModCount(); i++) { - snprintf(buf, 64, "%s##check%d", ModLoader::GetModName(i).data(), i); - ig::TableNextColumn(); - if(ig::Checkbox(buf, &ModLoader::GetModEnabled(i))) { - if(ModLoader::GetModEnabled(i)) { - ModLoader::EnableMod(i); - } else { - ModLoader::DisableMod(i); - } + ig::TableSetupColumn("Info", ImGuiTableColumnFlags_WidthFixed, ImGui::CalcTextSize("Info").x); + + for (int i = 0; i < ModLoader::GetModCount(); i++) { + snprintf(buf, 64, "%s##check%d", ModLoader::GetModName(i).data(), i); + ig::TableNextColumn(); + if (ig::Checkbox(buf, &ModLoader::GetModEnabled(i))) { + if (ModLoader::GetModEnabled(i)) { + ModLoader::EnableMod(i); } - ig::TableNextColumn(); - HelpMarker(ModLoader::toString(i).c_str()); + else { + ModLoader::DisableMod(i); + } + } + ig::TableNextColumn(); + HelpMarker(ModLoader::toString(i).c_str()); } ig::EndTable(); ImGui::SeparatorText("Settings"); - ImGuiIO& io = ImGui::GetIO(); ShowFontSelector(); ImGui::SameLine(); - HelpMarker(std::format("Total: {}\nPath: {}\nStart Range: {}\nEnd Range: {}\nSize: {}W / {}H\nConfig: sml_config.json", io.Fonts->Fonts.Size, fontconfig.fontPath.c_str(), fontconfig.unicodeRangeStart, fontconfig.unicodeRangeEnd, io.Fonts->TexWidth, io.Fonts->TexHeight).c_str()); - + HelpMarker(std::format("Total: {}\nPath: {}\nStart Range: {}\nEnd Range: {}\nSize: {}W / {}H\nConfig: sml_config.json", io.Fonts->Fonts.Size, fontconfig.fontPath.c_str(), fontconfig.unicodeRangeStart, fontconfig.unicodeRangeEnd, io.Fonts->TexWidth, io.Fonts->TexHeight).c_str()); + const float MIN_SCALE = 0.3f; const float MAX_SCALE = 3.0f; static float window_scale = 1.0f; - if (ImGui::DragFloat("Window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) + if (ImGui::DragFloat("Window Scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) ImGui::SetWindowFontScale(window_scale); - ImGui::DragFloat("Global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); - + ImGui::DragFloat("Global Scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); + ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); - ImGui::Text("FPS: %.1f | %.3f ms/frame", io.Framerate, 1000.0f / io.Framerate); + ImGui::Text("FPS: %.f | %.2f ms | DeltaTime: %.2f | amb", io.Framerate, 1000.0f / io.Framerate, io.DeltaTime); } ig::End(); } diff --git a/src/mod_loader.cpp b/src/mod_loader.cpp index 0da8653..993c89c 100644 --- a/src/mod_loader.cpp +++ b/src/mod_loader.cpp @@ -90,14 +90,13 @@ void ModLoader::RenderAll() { } std::string ModLoader::toString(int index) { std::stringstream ss; - - ss << "Mod Information" << "\n"; + + ss << "Information" << "\n"; ss << "Name: " << mods[index].info.name << "\n"; ss << "Version: " << mods[index].info.version << "\n"; ss << "Author: " << mods[index].info.author << "\n"; - ss << "Description: " << mods[index].info.description << "\n"; - // ss << "GetModInfo: " << mods[index].getInfo << "\n"; + ss << "Details: " << mods[index].info.description << "\n"; + //ss << "GetModInfo: " << mods[index].getInfo << "\n"; // ss << "Render: " << mods[index].render << "\n"; return ss.str(); } -