From ee0e2af974b64c862f89f6eba54e8245c8c605e1 Mon Sep 17 00:00:00 2001 From: gggaa2152 <60614405+gggaa2152@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:37:05 +0800 Subject: [PATCH] Update main.cpp --- main.cpp | 1033 +++++++++++++++++++++++++++--------------------------- 1 file changed, 507 insertions(+), 526 deletions(-) diff --git a/main.cpp b/main.cpp index ac607d2b3..c224b8381 100644 --- a/main.cpp +++ b/main.cpp @@ -5,7 +5,10 @@ #include #include #include -#include +#include +#include + +#include #include #include #include @@ -13,133 +16,126 @@ #include #include #include -#include -#include #include +#include + #include "dobby.h" #include "imgui.h" #include "imgui_impl_android.h" #include "imgui_impl_opengl3.h" -#define TAG "IL2CPP_Drive" -#define GAME_MODULE "libil2cpp.so" +namespace Overlay { -// --- 实时日志系统 (优化:使用 deque 提升性能) --- -std::atomic g_InitCallCount{0}; -std::deque g_AppLogs; -std::mutex g_LogMutex; +// ============================================================================ +// 常量定义 +// ============================================================================ +constexpr const char* kTag = "IL2CPP_Drive"; +constexpr const char* kGameModule = "libil2cpp.so"; +constexpr size_t kMaxLogSize = 30; +constexpr size_t kMaxPlayers = 15; -void AddLog(const char* fmt, ...) { - char buf[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - __android_log_print(ANDROID_LOG_INFO, TAG, "%s", buf); - - std::lock_guard lock(g_LogMutex); - if (g_AppLogs.size() > 30) g_AppLogs.pop_front(); - g_AppLogs.push_back(buf); -} +// ============================================================================ +// 日志系统类 (封装) +// ============================================================================ +class Logger { +public: + static Logger& GetInstance() { + static Logger instance; + return instance; + } -#undef LOGI -#undef LOGE -#define LOGI(...) AddLog(__VA_ARGS__) -#define LOGE(...) AddLog("[ERROR] " __VA_ARGS__) + void Print(const char* level, const char* fmt, ...) { + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); -// --- 基础状态变量 --- -static bool g_Initialized = false; -static bool g_FontLoaded = false; -static bool g_IsHookInstalled = false; -static std::string g_HookStatusMsg = "等待手动挂钩... (请在大厅/选区界面操作)"; + __android_log_print(ANDROID_LOG_INFO, kTag, "%s%s", level, buf); -struct { - float x = 0.0f; - float y = 0.0f; - std::atomic down{false}; - float renderW = 0.0f; - float renderH = 0.0f; - float physW = 3392.0f; - float physH = 2400.0f; - bool isSizeAutoDetected = false; - float offsetX = 0.0f; - float offsetY = 0.0f; -} g_Touch; + std::lock_guard lock(m_mutex); + if (m_logs.size() >= kMaxLogSize) { + m_logs.pop_front(); + } + m_logs.emplace_back(buf); + } -static float g_DynamicScale = 1.0f; -static float g_BaseWindowHeight = 0.0f; -static float g_UserUIScale = 1.0f; + const std::deque& GetLogs() const { return m_logs; } + std::mutex& GetMutex() { return m_mutex; } -static uintptr_t g_GameBase = 0; -static uintptr_t g_HookAddr_InitActor = 0; - -static std::atomic g_CapturedX0{0}; -static std::atomic g_CapturedX1{0}; -static std::atomic g_CapturedX2{0}; - -// 交互式探测器状态变量 -static std::vector g_ExploreHistory; -static uintptr_t g_CurrentExploreAddr = 0; -static uintptr_t g_LastRootBase = 0; - -static bool g_ForceDirectRead = false; - -struct DynamicOffsets { - uint32_t x0_to_addr1 = 0x20; - uint32_t addr1_to_addr2 = 0x10; - uint32_t item_to_addr3 = 0x18; - uint32_t addr3_to_addr4 = 0x30; - uint32_t addr3_to_addr5 = 0x100; - uint32_t addr3_to_addr6 = 0x70; - - uint32_t prop_gold = 0x20; - uint32_t prop_hp = 0x30; - uint32_t prop_maxhp = 0x32; - uint32_t prop_level = 0x50; - uint32_t prop_mana = 0x28; +private: + Logger() = default; + std::deque m_logs; + std::mutex m_mutex; }; -DynamicOffsets g_Offsets; -std::mutex g_OffsetMutex; +#define LOG_INFO(...) Overlay::Logger::GetInstance().Print("", __VA_ARGS__) +#define LOG_ERROR(...) Overlay::Logger::GetInstance().Print("[ERROR] ", __VA_ARGS__) -// --- 优化点 1:安全内存校验器 (告别频繁的高开销 SIGSEGV) --- -// 利用 /dev/random 或管道验证内存页是否可读,不抛出系统异常,极其稳定 -bool IsValidMemory(uintptr_t address) { - if (address < 0x10000000 || address > 0x00007FFFFFFFFFFF) return false; - static int dev_random_fd = open("/dev/random", O_WRONLY); - if (dev_random_fd < 0) dev_random_fd = open("/dev/null", O_WRONLY); - - // 尝试向安全区域写出 4 字节,如果返回 -1 (EFAULT) 说明指针无效 - ssize_t ret = write(dev_random_fd, (void*)address, 4); - return ret >= 0; -} +// ============================================================================ +// 内存读取工具类 (封装与安全保障) +// ============================================================================ +class MemoryReader { +public: + static bool IsValidAddress(uintptr_t address) { + if (address < 0x10000000 || address > 0x00007FFFFFFFFFFF) return false; + + static int devRandomFd = open("/dev/random", O_WRONLY); + if (devRandomFd < 0) { + devRandomFd = open("/dev/null", O_WRONLY); + } + + ssize_t ret = write(devRandomFd, reinterpret_cast(address), 4); + return ret >= 0; + } -// 安全读取包装器 -template -T SafeRead(uintptr_t address) { - if (!IsValidMemory(address)) return T{}; - return *(volatile T*)address; -} + template + static T SafeRead(uintptr_t address) { + if (!IsValidAddress(address)) return T{}; + return *reinterpret_cast(address); + } -// 快速/激进读取 (用于确定父指针必然有效时,提取内部连续的结构体属性,性能拉满) -template -inline T FastRead(uintptr_t address) { - return *(volatile T*)address; -} + template + static T FastRead(uintptr_t address) { + return *reinterpret_cast(address); + } +}; + +// ============================================================================ +// 游戏数据结构定义 +// ============================================================================ +struct DynamicOffsets { + uint32_t x0ToAddr1 = 0x20; + uint32_t addr1ToAddr2 = 0x10; + uint32_t itemToAddr3 = 0x18; + uint32_t addr3ToAddr4 = 0x30; + uint32_t addr3ToAddr5 = 0x100; + uint32_t addr3ToAddr6 = 0x70; + + uint32_t propGold = 0x20; + uint32_t propHp = 0x30; + uint32_t propMaxHp = 0x32; + uint32_t propLevel = 0x50; + uint32_t propMana = 0x28; +}; struct PlayerData { - int hp = 0, maxHp = 0, mana = 0, gold = 0, level = 0; - float worldX = 0, worldY = 0, worldZ = 0; - float mapX = 0, mapY = 0; + int32_t hp = 0; + int16_t maxHp = 0; + int32_t mana = 0; + int32_t gold = 0; + int32_t level = 0; + float worldX = 0.0f, worldY = 0.0f, worldZ = 0.0f; + float mapX = 0.0f, mapY = 0.0f; +}; + +struct DebugItem { + uintptr_t base = 0, addr3 = 0, addr4 = 0, addr5 = 0, addr6 = 0; }; struct DebugChain { - uintptr_t baseX0 = 0; - uintptr_t addr1 = 0; - uintptr_t addr2 = 0; - struct Item { - uintptr_t base = 0, addr3 = 0, addr4 = 0, addr5 = 0, addr6 = 0; - } items[15]; + uintptr_t baseX0 = 0, addr1 = 0, addr2 = 0; + DebugItem items[kMaxPlayers]; }; struct GameSnapshot { @@ -149,94 +145,361 @@ struct GameSnapshot { std::vector players; }; -// --- 优化点 2:无锁化快照渲染 (解决界面卡顿) --- -std::mutex g_SnapshotMutex; -std::shared_ptr g_CurrentSnapshot = std::make_shared(); -std::atomic g_ActorManager{0}; +// ============================================================================ +// 触控管理类 +// ============================================================================ +class TouchManager { +public: + static TouchManager& GetInstance() { + static TouchManager instance; + return instance; + } -void DataWorkerThread() { - while (true) { - // 在本地构建完整快照,期间不加锁,彻底释放 UI 线程 - auto newSnap = std::make_shared(); - DynamicOffsets currOff; - { - std::lock_guard lock(g_OffsetMutex); - currOff = g_Offsets; + void ProcessEvent(AInputEvent* event) { + if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { + int32_t action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; + + float autoScaleX = m_renderW / m_physW; + float autoScaleY = m_renderH / m_physH; + + m_x = (AMotionEvent_getX(event, 0) * autoScaleX) + m_offsetX; + m_y = (AMotionEvent_getY(event, 0) * autoScaleY) + m_offsetY; + + if (action == AMOTION_EVENT_ACTION_DOWN) m_isDown.store(true); + else if (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL) m_isDown.store(false); } - newSnap->offsets = currOff; + } - uintptr_t baseX0 = g_ActorManager.load(); - if (baseX0 != 0 && IsValidMemory(baseX0)) { - newSnap->inMatch = true; - newSnap->debug.baseX0 = baseX0; + void UpdateRenderSize(float w, float h) { m_renderW = w; m_renderH = h; } + + float GetX() const { return m_x; } + float GetY() const { return m_y; } + bool IsDown() const { return m_isDown.load(); } + + float m_offsetX = 0.0f; + float m_offsetY = 0.0f; + float m_renderW = 0.0f; + float m_renderH = 0.0f; - uintptr_t addr1 = SafeRead(baseX0 + currOff.x0_to_addr1); - newSnap->debug.addr1 = addr1; - if (addr1) { - uintptr_t addr2 = SafeRead(addr1 + currOff.addr1_to_addr2); - newSnap->debug.addr2 = addr2; - if (addr2) { - for (int i = 0; i < 15; ++i) { - // 【核心修复】:直接跳过 IL2CPP 数组的 0x20 头部字节 - uintptr_t item = SafeRead(addr2 + 0x20 + (i * 0x8)); - newSnap->debug.items[i].base = item; - if (!item) continue; +private: + TouchManager() = default; + float m_x = 0.0f, m_y = 0.0f; + std::atomic m_isDown{false}; + float m_physW = 3392.0f; + float m_physH = 2400.0f; +}; - uintptr_t addr3 = SafeRead(item + currOff.item_to_addr3); - newSnap->debug.items[i].addr3 = addr3; - if (!addr3) continue; +// ============================================================================ +// 核心引擎引擎类 (单例,管理整个外挂生命周期) +// ============================================================================ +class EngineCore { +public: + static EngineCore& GetInstance() { + static EngineCore instance; + return instance; + } - PlayerData p; + void InitWorkerThread() { + std::thread(&EngineCore::DataWorkerLoop, this).detach(); + } - // 优化:父指针有效时直接 FastRead,减少 Syscall 提高帧率 - uintptr_t addr4 = SafeRead(addr3 + currOff.addr3_to_addr4); - newSnap->debug.items[i].addr4 = addr4; - if (addr4) { - p.gold = FastRead(addr4 + currOff.prop_gold); - p.hp = FastRead(addr4 + currOff.prop_hp); - p.maxHp = FastRead(addr4 + currOff.prop_maxhp); - p.level = FastRead(addr4 + currOff.prop_level); - } + std::shared_ptr GetLatestSnapshot() { + std::lock_guard lock(m_snapshotMutex); + return m_currentSnapshot; + } - uintptr_t addr5 = SafeRead(addr3 + currOff.addr3_to_addr5); - newSnap->debug.items[i].addr5 = addr5; - if (addr5) { - p.worldX = FastRead(addr5 + 0x0); - p.worldZ = FastRead(addr5 + 0x4); - p.worldY = FastRead(addr5 + 0x8); - p.mana = FastRead(addr5 + currOff.prop_mana); - } + DynamicOffsets GetOffsets() { + std::lock_guard lock(m_offsetMutex); + return m_offsets; + } - uintptr_t addr6 = SafeRead(addr3 + currOff.addr3_to_addr6); - newSnap->debug.items[i].addr6 = addr6; - if (addr6) { - p.mapX = FastRead(addr6 + 0x50); - p.mapY = FastRead(addr6 + 0x54); - } + void SetOffsets(const DynamicOffsets& offsets) { + std::lock_guard lock(m_offsetMutex); + m_offsets = offsets; + } - if (p.maxHp > 0 && p.maxHp < 50000) - newSnap->players.push_back(p); + void SetActorManager(uintptr_t address) { + m_actorManager.store(address); + } + + std::mutex& GetOffsetMutex() { return m_offsetMutex; } + DynamicOffsets& GetOffsetsRef() { return m_offsets; } + +private: + EngineCore() : m_currentSnapshot(std::make_shared()) {} + + void DataWorkerLoop() { + while (true) { + auto newSnap = std::make_shared(); + newSnap->offsets = GetOffsets(); + + uintptr_t baseX0 = m_actorManager.load(); + if (baseX0 != 0 && MemoryReader::IsValidAddress(baseX0)) { + newSnap->inMatch = true; + newSnap->debug.baseX0 = baseX0; + + uintptr_t addr1 = MemoryReader::SafeRead(baseX0 + newSnap->offsets.x0ToAddr1); + newSnap->debug.addr1 = addr1; + + if (addr1) { + uintptr_t addr2 = MemoryReader::SafeRead(addr1 + newSnap->offsets.addr1ToAddr2); + newSnap->debug.addr2 = addr2; + + if (addr2) { + ParsePlayers(newSnap, addr2); } } } - } - // 瞬间原子化替换指针,不阻塞渲染线程 - { - std::lock_guard lock(g_SnapshotMutex); - g_CurrentSnapshot = newSnap; + { + std::lock_guard lock(m_snapshotMutex); + m_currentSnapshot = newSnap; + } + std::this_thread::sleep_for(std::chrono::milliseconds(16)); } - std::this_thread::sleep_for(std::chrono::milliseconds(16)); } -} + void ParsePlayers(std::shared_ptr& snap, uintptr_t addr2) { + for (size_t i = 0; i < kMaxPlayers; ++i) { + uintptr_t item = MemoryReader::SafeRead(addr2 + 0x20 + (i * 0x8)); + snap->debug.items[i].base = item; + if (!item) continue; + + uintptr_t addr3 = MemoryReader::SafeRead(item + snap->offsets.itemToAddr3); + snap->debug.items[i].addr3 = addr3; + if (!addr3) continue; + + PlayerData p; + + uintptr_t addr4 = MemoryReader::SafeRead(addr3 + snap->offsets.addr3ToAddr4); + snap->debug.items[i].addr4 = addr4; + if (addr4) { + p.gold = MemoryReader::FastRead(addr4 + snap->offsets.propGold); + p.hp = MemoryReader::FastRead(addr4 + snap->offsets.propHp); + p.maxHp = MemoryReader::FastRead(addr4 + snap->offsets.propMaxHp); + p.level = MemoryReader::FastRead(addr4 + snap->offsets.propLevel); + } + + uintptr_t addr5 = MemoryReader::SafeRead(addr3 + snap->offsets.addr3ToAddr5); + snap->debug.items[i].addr5 = addr5; + if (addr5) { + p.worldX = MemoryReader::FastRead(addr5 + 0x0); + p.worldZ = MemoryReader::FastRead(addr5 + 0x4); + p.worldY = MemoryReader::FastRead(addr5 + 0x8); + p.mana = MemoryReader::FastRead(addr5 + snap->offsets.propMana); + } + + uintptr_t addr6 = MemoryReader::SafeRead(addr3 + snap->offsets.addr3ToAddr6); + snap->debug.items[i].addr6 = addr6; + if (addr6) { + p.mapX = MemoryReader::FastRead(addr6 + 0x50); + p.mapY = MemoryReader::FastRead(addr6 + 0x54); + } + + if (p.maxHp > 0 && p.maxHp < 50000) { + snap->players.push_back(p); + } + } + } + + std::shared_ptr m_currentSnapshot; + std::mutex m_snapshotMutex; + + DynamicOffsets m_offsets; + std::mutex m_offsetMutex; + + std::atomic m_actorManager{0}; +}; + +// ============================================================================ +// UI 渲染器 (分离界面绘制逻辑) +// ============================================================================ +class UIRenderer { +public: + static void RenderFrame(float w, float h, std::shared_ptr& snap) { + static bool initialized = false; + if (!initialized) { + InitializeImGui(); + initialized = true; + } + + auto& touch = TouchManager::GetInstance(); + ImGuiIO& io = ImGui::GetIO(); + io.DisplaySize = ImVec2(w, h); + io.MousePos = ImVec2(touch.GetX(), touch.GetY()); + io.MouseDown[0] = touch.IsDown(); + + float finalScale = std::max(1.0f, h / 1000.0f) * m_userScale; + ImGuiStyle& style = ImGui::GetStyle(); + style = m_defaultStyle; + style.ScaleAllSizes(1.2f * finalScale); + style.WindowRounding = 12.0f; + io.FontGlobalScale = 1.2f * finalScale; + + ImGui_ImplOpenGL3_NewFrame(); + ImGui::NewFrame(); + + if (touch.IsDown()) { + ImGui::GetForegroundDrawList()->AddCircleFilled(io.MousePos, 20.0f, IM_COL32(0, 255, 0, 200)); + } + + DrawMainWindow(w, h, snap); + + if (m_showDebugger) DrawDebugger(w, h, snap); + if (m_showRadar && snap->inMatch) DrawRadar(w, h, snap, finalScale); + + ImGui::Render(); + } + + static bool m_isHookInstalled; + static std::string m_hookStatusMsg; + +private: + static float m_userScale; + static ImGuiStyle m_defaultStyle; + static bool m_showDebugger; + static bool m_showRadar; + + static void InitializeImGui() { + ImGui::CreateContext(); + ImGui_ImplOpenGL3_Init("#version 300 es"); + ImGuiIO& io = ImGui::GetIO(); + m_defaultStyle = ImGui::GetStyle(); + + const char* systemFonts[] = { "/system/fonts/SysSans-Hans-Regular.ttf", "/system/fonts/NotoSansCJKjp-Regular.otc" }; + for (const char* fontPath : systemFonts) { + if (access(fontPath, R_OK) == 0) { + io.Fonts->AddFontFromFileTTF(fontPath, 32.0f, nullptr, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); + break; + } + } + } + + static void DrawMainWindow(float w, float h, std::shared_ptr& snap) { + ImGui::SetNextWindowPos(ImVec2(30, 30), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(w * 0.6f, h * 0.45f), ImGuiCond_FirstUseEver); + + if (ImGui::Begin("IL2CPP 性能极客版透视框架 [重构版]")) { + ImGui::BeginChild("HookController", ImVec2(0, 70), true); + if (!m_isHookInstalled) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.2f, 0.2f, 1.0f)); + if (ImGui::Button("🔴 注入基址", ImVec2(-1, 40))) { + extern void InstallHooks(); + InstallHooks(); + } + ImGui::PopStyleColor(); + } else { + ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "✅ Hook 注入完成!"); + } + ImGui::Text("状态: %s", m_hookStatusMsg.c_str()); + ImGui::EndChild(); + + if (ImGui::CollapsingHeader("基础校准")) { + ImGui::SliderFloat("菜单缩放", &m_userScale, 0.5f, 2.0f); + ImGui::Checkbox("雷达 (Radar)", &m_showRadar); ImGui::SameLine(); + ImGui::Checkbox("指针断点调试", &m_showDebugger); + } + + ImGui::TextColored(ImVec4(0, 1, 0, 1), "状态: %s", snap->inMatch ? "局内" : "等待数据..."); + + if (ImGui::BeginTable("PlayersTable", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("等级"); ImGui::TableSetupColumn("血量"); + ImGui::TableSetupColumn("蓝量"); ImGui::TableSetupColumn("金币"); + ImGui::TableSetupColumn("坐标"); ImGui::TableHeadersRow(); + for (const auto& p : snap->players) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); ImGui::Text("Lv.%d", p.level); + ImGui::TableNextColumn(); ImGui::Text("%d/%d", p.hp, p.maxHp); + ImGui::TableNextColumn(); ImGui::Text("%d", p.mana); + ImGui::TableNextColumn(); ImGui::Text("%d", p.gold); + ImGui::TableNextColumn(); ImGui::Text("%.0f, %.0f", p.mapX, p.mapY); + } + ImGui::EndTable(); + } + } + ImGui::End(); + } + + static void DrawRadar(float w, float h, std::shared_ptr& snap, float finalScale) { + ImGui::SetNextWindowPos(ImVec2(w - 350, 30), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0.5f)); + + if (ImGui::Begin("Radar", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize)) { + ImVec2 p0 = ImGui::GetCursorScreenPos(); + ImVec2 size = ImGui::GetContentRegionAvail(); + ImDrawList* dl = ImGui::GetWindowDrawList(); + dl->AddRect(p0, ImVec2(p0.x + size.x, p0.y + size.y), IM_COL32(255, 255, 255, 100)); + + for (const auto& p : snap->players) { + float nX = p.mapX / 10000.0f; + float nY = p.mapY / 10000.0f; + float rX = p0.x + (nX * size.x); + float rY = p0.y + size.y - (nY * size.y); + if (nX > 0 && nX < 1 && nY > 0 && nY < 1) { + dl->AddCircleFilled(ImVec2(rX, rY), 5.0f * finalScale, IM_COL32(255, 0, 0, 255)); + } + } + } + ImGui::End(); + ImGui::PopStyleColor(); + } + + static void DrawDebugger(float w, float h, std::shared_ptr& snap) { + ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(w * 0.65f, h * 0.85f), ImGuiCond_FirstUseEver); + + if (ImGui::Begin("指针断点排错器")) { + if (ImGui::CollapsingHeader("动态偏移修改面板 (十进制)", ImGuiTreeNodeFlags_DefaultOpen)) { + auto& engine = EngineCore::GetInstance(); + std::lock_guard lock(engine.GetOffsetMutex()); + auto& offsets = engine.GetOffsetsRef(); + + auto drawOffsetBtn = [](const char* label, uint32_t& val) { + ImGui::PushID(&val); + ImGui::TextColored(ImVec4(0.5f, 0.8f, 1.0f, 1.0f), "%s -> 当前: %d (0x%X)", label, val, val); + if (ImGui::Button("-4")) { if (val >= 4) val -= 4; else val = 0; } ImGui::SameLine(); + if (ImGui::Button("+4")) val += 4; + ImGui::Separator(); + ImGui::PopID(); + }; + + drawOffsetBtn("地址1", offsets.x0ToAddr1); + drawOffsetBtn("英雄数组", offsets.addr1ToAddr2); + drawOffsetBtn("实体数据", offsets.itemToAddr3); + } + ImGui::Separator(); + + if (ImGui::CollapsingHeader("实时运行日志", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::BeginChild("LogRegion", ImVec2(0, 120), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); + auto& logger = Logger::GetInstance(); + std::lock_guard lock(logger.GetMutex()); + for (const auto& log : logger.GetLogs()) { ImGui::TextUnformatted(log.c_str()); } + if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) ImGui::SetScrollHereY(1.0f); + ImGui::EndChild(); + } + } + ImGui::End(); + } +}; + +float UIRenderer::m_userScale = 1.0f; +ImGuiStyle UIRenderer::m_defaultStyle; +bool UIRenderer::m_showDebugger = false; +bool UIRenderer::m_showRadar = true; +bool UIRenderer::m_isHookInstalled = false; +std::string UIRenderer::m_hookStatusMsg = "等待点击注入..."; + +// ============================================================================ +// Dobby Hook 回调函数与模块基址寻找 (C 风格回调区) +// ============================================================================ struct ModuleInfo { const char* name; uintptr_t base; }; -static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *data) { - ModuleInfo* modInfo = (ModuleInfo*)data; +int DlIterateCallback(struct dl_phdr_info *info, size_t size, void *data) { + auto* modInfo = reinterpret_cast(data); if (info->dlpi_name && strstr(info->dlpi_name, modInfo->name)) { modInfo->base = info->dlpi_addr; return 1; @@ -244,15 +507,15 @@ static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *dat return 0; } -uintptr_t GetRealModuleBase(const char* module_name) { - ModuleInfo info = {module_name, 0}; - dl_iterate_phdr(dl_iterate_callback, &info); +uintptr_t GetModuleBase(const char* moduleName) { + ModuleInfo info = {moduleName, 0}; + dl_iterate_phdr(DlIterateCallback, &info); + if (info.base == 0) { - FILE* f = fopen("/proc/self/maps", "r"); - if (f) { + if (FILE* f = fopen("/proc/self/maps", "r")) { char line[512]; while (fgets(line, sizeof(line), f)) { - if (strstr(line, module_name)) { + if (strstr(line, moduleName)) { uintptr_t start; if (sscanf(line, "%lx", &start) == 1) { info.base = start; break; } } @@ -263,390 +526,108 @@ uintptr_t GetRealModuleBase(const char* module_name) { return info.base; } -typedef void (*t_InitActorParams)(void* x0, void* x1, void* x2, void* x3, void* x4, void* x5, void* x6, void* x7); -t_InitActorParams old_InitActorParams = nullptr; +typedef void (*InitActorParamsFunc)(void* x0, void* x1, void* x2, void* x3, void* x4, void* x5, void* x6, void* x7); +static InitActorParamsFunc g_oldInitActorParams = nullptr; -void hook_InitActorParams(void* x0, void* x1, void* x2, void* x3, void* x4, void* x5, void* x6, void* x7) { - g_InitCallCount++; - - if (x0 != nullptr) g_CapturedX0.store((uintptr_t)x0); - if (x1 != nullptr) g_CapturedX1.store((uintptr_t)x1); - if (x2 != nullptr) g_CapturedX2.store((uintptr_t)x2); - - if (x0 != nullptr && (uintptr_t)x0 > 0x10000000) { - g_ActorManager.store((uintptr_t)x0); - if (g_InitCallCount.load() % 5 == 1) { - LOGI("[+] 拦截到实体生成! 捕获基址 x0: 0x%lx", (uintptr_t)x0); - } +void HookInitActorParams(void* x0, void* x1, void* x2, void* x3, void* x4, void* x5, void* x6, void* x7) { + if (x0 != nullptr && reinterpret_cast(x0) > 0x10000000) { + EngineCore::GetInstance().SetActorManager(reinterpret_cast(x0)); } - - if (old_InitActorParams) { - old_InitActorParams(x0, x1, x2, x3, x4, x5, x6, x7); + if (g_oldInitActorParams) { + g_oldInitActorParams(x0, x1, x2, x3, x4, x5, x6, x7); } } -void InstallCoreHook() { - if (g_IsHookInstalled) return; +void InstallHooks() { + if (UIRenderer::m_isHookInstalled) return; - uintptr_t base = GetRealModuleBase(GAME_MODULE); + uintptr_t base = GetModuleBase(kGameModule); if (!base) { - g_HookStatusMsg = "未找到 libil2cpp.so,游戏可能未加载完全!"; - LOGE("[-] %s", g_HookStatusMsg.c_str()); + UIRenderer::m_hookStatusMsg = "未找到 libil2cpp.so!"; + LOG_ERROR("未找到目标游戏模块模块!"); return; } - g_GameBase = base; - g_HookAddr_InitActor = base + 0x73507bc; + uintptr_t targetAddr = base + 0x73507bc; + LOG_INFO("真实基址: 0x%lx, 目标: 0x%lx", base, targetAddr); - LOGI("[*] 准备硬核挂钩! 真实基址: 0x%lx, 目标: 0x%lx", base, g_HookAddr_InitActor); + void* pageStart = reinterpret_cast(targetAddr & ~0xFFF); + mprotect(pageStart, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC); - void* page_start = (void*)(g_HookAddr_InitActor & ~0xFFF); - mprotect(page_start, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC); - - int ret = DobbyHook((void*)g_HookAddr_InitActor, (void*)hook_InitActorParams, (void**)&old_InitActorParams); - __builtin___clear_cache((char*)g_HookAddr_InitActor, (char*)(g_HookAddr_InitActor + 16)); + int ret = DobbyHook(reinterpret_cast(targetAddr), + reinterpret_cast(HookInitActorParams), + reinterpret_cast(&g_oldInitActorParams)); if (ret == 0) { - g_IsHookInstalled = true; - g_HookStatusMsg = "✅ 核心 Hook 注入成功!请进入对局。"; - LOGI("[+] 手动安装 Hook 成功!"); + UIRenderer::m_isHookInstalled = true; + UIRenderer::m_hookStatusMsg = "✅ 核心 Hook 注入成功!"; + LOG_INFO("手动安装 Hook 成功!"); } else { - g_HookStatusMsg = "❌ 挂钩失败,Dobby 错误码: " + std::to_string(ret); - LOGE("[-] %s", g_HookStatusMsg.c_str()); + UIRenderer::m_hookStatusMsg = "❌ 挂钩失败"; + LOG_ERROR("挂钩失败, 返回码: %d", ret); } } -// 恢复完整版的排错器UI -void DrawPointerDebugger(const GameSnapshot& snap, float w, float h) { - ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowSize(ImVec2(w * 0.65f, h * 0.85f), ImGuiCond_FirstUseEver); - if (ImGui::Begin("指针断点排错器")) { +// ---------------- EGL & Input Hook ---------------- +typedef int (*InputConsumerConsumeFunc)(void* instance, void* factory, bool consumeBatches, int64_t frameTime, uint32_t* outSeq, void** outEvent); +static InputConsumerConsumeFunc g_oldConsume = nullptr; - if (ImGui::CollapsingHeader("高级排错 (已升级为无异常读取)", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.4f, 1.0f, 0.4f, 1.0f)); - ImGui::Text("✔️ 当前已启用 /dev/random 内核级安全读取,告别由于捕获异常导致的卡顿和崩溃。"); - ImGui::PopStyleColor(); - } - ImGui::Separator(); - - // ========================================== - // 交互式基址内存探查器 (0x1000 范围) - // ========================================== - if (ImGui::CollapsingHeader("交互式内存探查器 (无限层级点入)", ImGuiTreeNodeFlags_DefaultOpen)) { - uintptr_t rootBase = g_ActorManager.load(); - - if (rootBase != 0 && rootBase != g_LastRootBase) { - g_LastRootBase = rootBase; - g_CurrentExploreAddr = rootBase; - g_ExploreHistory.clear(); - } - - if (g_CurrentExploreAddr != 0) { - ImGui::TextColored(ImVec4(1, 0.5, 0, 1), "当前探查地址: 0x%lx", g_CurrentExploreAddr); - - if (g_ExploreHistory.size() > 0) { - if (ImGui::Button("⬅️ 返回上一层")) { - g_CurrentExploreAddr = g_ExploreHistory.back(); - g_ExploreHistory.pop_back(); - } - ImGui::SameLine(); - } - if (ImGui::Button("🏠 回到起点 (x0)")) { - g_ExploreHistory.clear(); - g_CurrentExploreAddr = rootBase; - } - ImGui::SameLine(); - ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), " | 层级深度: %zu", g_ExploreHistory.size()); - - ImGui::BeginChild("MemDump", ImVec2(0, 450), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); - - for (uint32_t offset = 0; offset <= 0x1000; offset += 8) { - uintptr_t val = SafeRead(g_CurrentExploreAddr + offset); - - if (val > 0x10000000 && val < 0x00007FFFFFFFFFFF && IsValidMemory(val)) { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 1, 0, 1)); - ImGui::Text("+0x%03X : 0x%lx", offset, val); - ImGui::PopStyleColor(); - - ImGui::SameLine(350.0f); - ImGui::PushID(offset); - if (ImGui::Button("👉 点入", ImVec2(100, 0))) { - g_ExploreHistory.push_back(g_CurrentExploreAddr); - g_CurrentExploreAddr = val; - } - ImGui::PopID(); - - } else if (val != 0) { - float fval = 0.0f; - memcpy(&fval, &val, sizeof(float)); - - ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.8f, 1), "+0x%03X : 0x%lx", offset, val); - ImGui::SameLine(300.0f); - ImGui::TextColored(ImVec4(0.5f, 0.8f, 1.0f, 1), "(整数:%lu, 浮点:%.2f)", val & 0xFFFFFFFF, fval); - } else { - ImGui::TextColored(ImVec4(0.4f, 0.4f, 0.4f, 1), "+0x%03X : 0x0", offset); - } - ImGui::Separator(); - } - ImGui::EndChild(); - } else { - ImGui::Text("等待获取有效基址..."); - } - } - ImGui::Separator(); - - if (ImGui::CollapsingHeader("动态偏移修改面板 (十进制)", ImGuiTreeNodeFlags_DefaultOpen)) { - std::lock_guard lock(g_OffsetMutex); - auto drawOffsetBtn = [](const char* label, uint32_t& val) { - ImGui::PushID(&val); - ImGui::TextColored(ImVec4(0.5f, 0.8f, 1.0f, 1.0f), "%s -> 当前: %d (0x%X)", label, val, val); - if (ImGui::Button("-8")) { if (val >= 8) val -= 8; else val = 0; } ImGui::SameLine(); - if (ImGui::Button("-4")) { if (val >= 4) val -= 4; else val = 0; } ImGui::SameLine(); - if (ImGui::Button("-1")) { if (val >= 1) val -= 1; else val = 0; } ImGui::SameLine(); - if (ImGui::Button("+1")) val += 1; ImGui::SameLine(); - if (ImGui::Button("+4")) val += 4; ImGui::SameLine(); - if (ImGui::Button("+8")) val += 8; - ImGui::Separator(); - ImGui::PopID(); - }; - ImGui::TextColored(ImVec4(1, 0, 1, 1), "※ 提示: 英雄数组底层代码已自动跳过 0x20 的对象头,无需在此重复计算!"); - drawOffsetBtn("地址1 (x0 + ?)", g_Offsets.x0_to_addr1); - drawOffsetBtn("英雄数组 (addr1 + ?)", g_Offsets.addr1_to_addr2); - drawOffsetBtn("实体数据 (item + ?)", g_Offsets.item_to_addr3); - drawOffsetBtn("血量属性 (addr3 + ?)", g_Offsets.addr3_to_addr4); - drawOffsetBtn("坐标数据 (addr3 + ?)", g_Offsets.addr3_to_addr5); - drawOffsetBtn("雷达坐标 (addr3 + ?)", g_Offsets.addr3_to_addr6); - ImGui::Separator(); - drawOffsetBtn("金币偏移", g_Offsets.prop_gold); - drawOffsetBtn("血量偏移", g_Offsets.prop_hp); - drawOffsetBtn("最大血量偏移", g_Offsets.prop_maxhp); - drawOffsetBtn("等级偏移", g_Offsets.prop_level); - drawOffsetBtn("蓝量偏移", g_Offsets.prop_mana); - } - ImGui::Separator(); - - const auto& d = snap.debug; - const auto& off = snap.offsets; - ImGui::TextColored(d.baseX0 ? ImVec4(0,1,0,1) : ImVec4(1,0,0,1), "[起点] 捕获到的 x0: 0x%lx", d.baseX0); - ImGui::TextColored(d.addr1 ? ImVec4(0,1,0,1) : ImVec4(1,0,0,1), " └─ [+%d] 地址 1: 0x%lx", off.x0_to_addr1, d.addr1); - ImGui::TextColored(d.addr2 ? ImVec4(0,1,0,1) : ImVec4(1,0,0,1), " └─ [+%d] 英雄数组: 0x%lx", off.addr1_to_addr2, d.addr2); - if (d.addr2 != 0) { - for (int i = 0; i < 15; i++) { - if (d.items[i].base == 0) continue; - char nodeName[64]; - snprintf(nodeName, sizeof(nodeName), "数组序号 [%d] - 0x%lx", i, d.items[i].base); - if (ImGui::TreeNodeEx(nodeName, ImGuiTreeNodeFlags_Framed)) { - ImGui::TextColored(d.items[i].addr3 ? ImVec4(0,1,0,1) : ImVec4(1,0,0,1), " └─ [+%d] 实体数据: 0x%lx", off.item_to_addr3, d.items[i].addr3); - if (d.items[i].addr3) { - ImGui::TextColored(d.items[i].addr4 ? ImVec4(0,1,0,1) : ImVec4(1,0,0,1), " ├─ [+%d] 属性区: 0x%lx", off.addr3_to_addr4, d.items[i].addr4); - ImGui::TextColored(d.items[i].addr5 ? ImVec4(0,1,0,1) : ImVec4(1,0,0,1), " ├─ [+%d] 坐标区: 0x%lx", off.addr3_to_addr5, d.items[i].addr5); - ImGui::TextColored(d.items[i].addr6 ? ImVec4(0,1,0,1) : ImVec4(1,0,0,1), " └─ [+%d] 小地图: 0x%lx", off.addr3_to_addr6, d.items[i].addr6); - } - ImGui::TreePop(); - } - } - } - ImGui::Separator(); - if (ImGui::CollapsingHeader("实时运行日志", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::TextColored(g_InitCallCount > 0 ? ImVec4(0, 1, 0, 1) : ImVec4(1, 1, 0, 1), - "> 当前成功拦截次数: %d", g_InitCallCount.load()); - ImGui::BeginChild("LogRegion", ImVec2(0, 120), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); - std::lock_guard lock(g_LogMutex); - for (const auto& log : g_AppLogs) { ImGui::TextUnformatted(log.c_str()); } - if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) ImGui::SetScrollHereY(1.0f); - ImGui::EndChild(); - } +int HookConsume(void* instance, void* factory, bool consumeBatches, int64_t frameTime, uint32_t* outSeq, void** outEvent) { + int res = g_oldConsume(instance, factory, consumeBatches, frameTime, outSeq, outEvent); + if (res == 0 && outEvent && *outEvent) { + TouchManager::GetInstance().ProcessEvent(reinterpret_cast(*outEvent)); } - ImGui::End(); -} - -void handle_android_event(AInputEvent* event) { - if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { - int32_t action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; - float autoScaleX = g_Touch.renderW / g_Touch.physW; - float autoScaleY = g_Touch.renderH / g_Touch.physH; - g_Touch.x = (AMotionEvent_getX(event, 0) * autoScaleX) + g_Touch.offsetX; - g_Touch.y = (AMotionEvent_getY(event, 0) * autoScaleY) + g_Touch.offsetY; - if (action == AMOTION_EVENT_ACTION_DOWN) g_Touch.down.store(true); - else if (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL) g_Touch.down.store(false); - } -} - -typedef int (*p_InputConsumer_consume)(void* instance, void* factory, bool consumeBatches, int64_t frameTime, uint32_t* outSeq, void** outEvent); -static p_InputConsumer_consume old_consume = nullptr; - -int hook_consume(void* instance, void* factory, bool consumeBatches, int64_t frameTime, uint32_t* outSeq, void** outEvent) { - int res = old_consume(instance, factory, consumeBatches, frameTime, outSeq, outEvent); - if (res == 0 && outEvent && *outEvent) handle_android_event((AInputEvent*)(*outEvent)); return res; } -typedef EGLBoolean (*p_eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); -static p_eglSwapBuffers old_eglSwapBuffers = nullptr; +typedef EGLBoolean (*EglSwapBuffersFunc)(EGLDisplay dpy, EGLSurface surface); +static EglSwapBuffersFunc g_oldEglSwapBuffers = nullptr; -EGLBoolean hook_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { - EGLint w, h; +EGLBoolean HookEglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { + EGLint w = 0, h = 0; eglQuerySurface(dpy, surface, EGL_WIDTH, &w); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); - if (w <= 0 || h <= 0) return old_eglSwapBuffers(dpy, surface); - g_Touch.renderW = (float)w; - g_Touch.renderH = (float)h; + + if (w <= 0 || h <= 0) return g_oldEglSwapBuffers(dpy, surface); + + TouchManager::GetInstance().UpdateRenderSize(static_cast(w), static_cast(h)); + auto snapshot = EngineCore::GetInstance().GetLatestSnapshot(); - // 提取智能指针快照数据,实现无锁极速渲染 - std::shared_ptr snapshot; - { - std::lock_guard lock(g_SnapshotMutex); - snapshot = g_CurrentSnapshot; - } - - if (!g_Initialized) { - ImGui::CreateContext(); - ImGui_ImplOpenGL3_Init("#version 300 es"); - ImGuiIO& io = ImGui::GetIO(); - const char* systemFonts[] = { "/system/fonts/SysSans-Hans-Regular.ttf", "/system/fonts/NotoSansCJKjp-Regular.otc", "/system/fonts/NotoSansSC-Regular.otf", "/system/fonts/DroidSansFallback.ttf" }; - for (int i = 0; i < 4; i++) { - if (access(systemFonts[i], R_OK) == 0) { - io.Fonts->AddFontFromFileTTF(systemFonts[i], 32.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); - g_FontLoaded = true; break; - } - } - g_Initialized = true; - } - - ImGuiIO& io = ImGui::GetIO(); - io.DisplaySize = ImVec2(g_Touch.renderW, g_Touch.renderH); - io.MousePos = ImVec2(g_Touch.x, g_Touch.y); - io.MouseDown[0] = g_Touch.down.load(); - - float deviceScale = (float)h / 1000.0f; - if (deviceScale < 1.0f) deviceScale = 1.0f; - float finalScale = deviceScale * g_DynamicScale * g_UserUIScale; - - static ImGuiStyle default_style = ImGui::GetStyle(); - ImGuiStyle& style = ImGui::GetStyle(); - style = default_style; - style.ScaleAllSizes(1.2f * finalScale); - style.WindowRounding = 12.0f; - style.WindowMinSize = ImVec2(100.0f, 100.0f); - io.FontGlobalScale = 1.2f * finalScale; - - ImGui_ImplOpenGL3_NewFrame(); - ImGui::NewFrame(); - - if (g_Touch.down.load()) - ImGui::GetForegroundDrawList()->AddCircleFilled(io.MousePos, 20.0f, IM_COL32(0, 255, 0, 200)); - - if (g_BaseWindowHeight == 0.0f) g_BaseWindowHeight = h * 0.45f; - ImGui::SetNextWindowPos(ImVec2(30, 30), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowSize(ImVec2(w * 0.6f, g_BaseWindowHeight), ImGuiCond_FirstUseEver); - - static bool show_pointer_debugger = true; - static bool show_radar = true; - - // 恢复主控界面 - if (ImGui::Begin("IL2CPP 性能极客版透视框架")) { - - ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.1f, 0.1f, 0.15f, 1.0f)); - ImGui::BeginChild("HookController", ImVec2(0, 70), true); - if (!g_IsHookInstalled) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.2f, 0.2f, 1.0f)); - if (ImGui::Button("🔴 在大厅界面点击此按钮注入", ImVec2(-1, 40))) { - InstallCoreHook(); - } - ImGui::PopStyleColor(); - } else { - ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "✅ Hook 注入完成!快去进对局测试。"); - } - ImGui::Text("状态: %s", g_HookStatusMsg.c_str()); - ImGui::EndChild(); - ImGui::PopStyleColor(); - ImGui::Separator(); - - if (ImGui::CollapsingHeader("基础校准 (触控与缩放)")) { - ImGui::SliderFloat("菜单缩放", &g_UserUIScale, 0.5f, 2.0f); - ImGui::Text("坐标偏移 X:%.1f Y:%.1f", g_Touch.offsetX, g_Touch.offsetY); - if (ImGui::Button("-10##x")) g_Touch.offsetX -= 10; ImGui::SameLine(); - if (ImGui::Button("+10##x")) g_Touch.offsetX += 10; ImGui::SameLine(); - if (ImGui::Button("-10##y")) g_Touch.offsetY -= 10; ImGui::SameLine(); - if (ImGui::Button("+10##y")) g_Touch.offsetY += 10; - } - ImGui::Separator(); - ImGui::Checkbox("雷达 (Radar)", &show_radar); ImGui::SameLine(); - ImGui::Checkbox("指针断点调试", &show_pointer_debugger); - ImGui::Separator(); - - ImGui::TextColored(ImVec4(0, 1, 0, 1), "状态: %s", snapshot->inMatch ? "局内" : "未获取到对象"); - - if (ImGui::BeginTable("PlayersTable", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn("等级"); ImGui::TableSetupColumn("血量"); - ImGui::TableSetupColumn("蓝量"); ImGui::TableSetupColumn("金币"); - ImGui::TableSetupColumn("雷达坐标"); ImGui::TableHeadersRow(); - for (const auto& p : snapshot->players) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); ImGui::Text("Lv.%d", p.level); - ImGui::TableNextColumn(); ImGui::Text("%d/%d", p.hp, p.maxHp); - ImGui::TableNextColumn(); ImGui::Text("%d", p.mana); - ImGui::TableNextColumn(); ImGui::Text("%d", p.gold); - ImGui::TableNextColumn(); ImGui::Text("%.0f, %.0f", p.mapX, p.mapY); - } - ImGui::EndTable(); - } - } - ImGui::End(); - - // 将指针解引用传入以供原始函数调用 - if (show_pointer_debugger) DrawPointerDebugger(*snapshot, w, h); - - // 恢复雷达绘制逻辑 - if (show_radar && snapshot->inMatch) { - ImGui::SetNextWindowPos(ImVec2(w - 350, 30), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver); - ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0.5f)); - if (ImGui::Begin("Radar", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize)) { - ImVec2 p0 = ImGui::GetCursorScreenPos(); - ImVec2 size = ImGui::GetContentRegionAvail(); - ImDrawList* dl = ImGui::GetWindowDrawList(); - dl->AddRect(p0, ImVec2(p0.x + size.x, p0.y + size.y), IM_COL32(255, 255, 255, 100)); - for (const auto& p : snapshot->players) { - float nX = p.mapX / 10000.0f; - float nY = p.mapY / 10000.0f; - float rX = p0.x + (nX * size.x); - float rY = p0.y + size.y - (nY * size.y); - if (nX > 0 && nX < 1 && nY > 0 && nY < 1) - dl->AddCircleFilled(ImVec2(rX, rY), 5.0f * finalScale, IM_COL32(255, 0, 0, 255)); - } - } - ImGui::End(); - ImGui::PopStyleColor(); - } - - ImGui::Render(); - GLint v[4]; glGetIntegerv(GL_VIEWPORT, v); - GLint d; glGetIntegerv(GL_DEPTH_TEST, &d); + GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); + GLint depthTest; glGetIntegerv(GL_DEPTH_TEST, &depthTest); + glDisable(GL_DEPTH_TEST); glViewport(0, 0, w, h); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - glViewport(v[0], v[1], v[2], v[3]); - if (d) glEnable(GL_DEPTH_TEST); - return old_eglSwapBuffers(dpy, surface); + UIRenderer::RenderFrame(static_cast(w), static_cast(h), snapshot); + + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + if (depthTest) glEnable(GL_DEPTH_TEST); + + return g_oldEglSwapBuffers(dpy, surface); } -void* DelayedHookThread(void*) { - void* egl = nullptr; - while (!egl) { egl = DobbySymbolResolver("libEGL.so", "eglSwapBuffers"); if (!egl) sleep(1); } - DobbyHook(egl, (void*)hook_eglSwapBuffers, (void**)&old_eglSwapBuffers); +void* BootstrapThread(void*) { + void* eglSym = nullptr; + while (!(eglSym = DobbySymbolResolver("libEGL.so", "eglSwapBuffers"))) { sleep(1); } + DobbyHook(eglSym, reinterpret_cast(HookEglSwapBuffers), reinterpret_cast(&g_oldEglSwapBuffers)); - void* ins = nullptr; - while (!ins) { ins = DobbySymbolResolver("libinput.so", "_ZN7android13InputConsumer7consumeEPNS_26InputEventFactoryInterfaceEblPjPPNS_10InputEventE"); if (!ins) sleep(1); } - DobbyHook(ins, (void*)hook_consume, (void**)&old_consume); - - std::thread(DataWorkerThread).detach(); + void* inputSym = nullptr; + while (!(inputSym = DobbySymbolResolver("libinput.so", "_ZN7android13InputConsumer7consumeEPNS_26InputEventFactoryInterfaceEblPjPPNS_10InputEventE"))) { sleep(1); } + DobbyHook(inputSym, reinterpret_cast(HookConsume), reinterpret_cast(&g_oldConsume)); + EngineCore::GetInstance().InitWorkerThread(); return nullptr; } -__attribute__((constructor)) void init_plugin() { - pthread_t t; - pthread_create(&t, nullptr, DelayedHookThread, nullptr); +} // namespace Overlay + +// ============================================================================ +// 模块入口点 +// ============================================================================ +__attribute__((constructor)) void InitializePlugin() { + pthread_t threadId; + pthread_create(&threadId, nullptr, Overlay::BootstrapThread, nullptr); }