Update main.cpp

This commit is contained in:
gggaa2152 2026-04-07 04:46:44 +08:00 committed by GitHub
parent 37a470314b
commit d7cd15758c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

538
main.cpp
View File

@ -1,3 +1,6 @@
// 注意:本代码基于你之前提供的完整功能版本,只修改了 Hook 部分
// 所有原有功能(换肤、ESP、自动操作、牌池、装备管理等)均保持不变
#include <pthread.h>
#include <unistd.h>
#include <android/log.h>
@ -6,152 +9,439 @@
#include <dlfcn.h>
#include <android/input.h>
#include <stdio.h>
#include <algorithm>
#include <atomic>
#include <vector>
#include <mutex>
#include <thread>
#include <chrono>
#include <fcntl.h>
#include <dirent.h>
#include <cstdarg>
#include <cstring>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <deque>
#include <fstream>
#include <sstream>
#include <cmath>
#include "dobby.h"
#include "imgui.h"
#include "imgui_impl_android.h"
#include "imgui_impl_opengl3.h"
#define TAG "SimpleHook"
#define TAG "JKInternal"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
// 全局变量
static uintptr_t g_ActorManager = 0;
static int g_MemFd = -1;
static float g_touchX = 0, g_touchY = 0;
static std::atomic<bool> g_touchDown{false};
// ======================== 全局配置变量与偏移声明(保持不变)========================
enum ConfigType { C_BOOL, C_INT, C_FLOAT, C_STRING };
struct ConfigEntry { const char* key; ConfigType type; void* ptr; };
// 安全读取
template<typename T>
T Read(uintptr_t addr) {
T val{};
if (addr < 0x10000) return val;
if (g_MemFd == -1) g_MemFd = open("/proc/self/mem", O_RDONLY);
if (g_MemFd >= 0) pread(g_MemFd, &val, sizeof(T), addr);
return val;
int g_gl_width = 0, g_gl_height = 0;
int g_cached_view_width = -1, g_cached_view_height = -1;
const char* g_configPath = "/data/data/com.tencent.jkchess/jkchess_config.ini";
std::mutex g_configMutex;
bool g_enable_skin = false;
int g_selected_skin_idx = 0;
bool g_header_skin = true;
bool g_enable_map_skin = false;
int g_selected_map_idx = 0;
bool g_header_map_skin = true;
bool g_predict_enemy = false, g_predict_hex = false;
bool g_esp_board = true, g_esp_level = false;
bool g_esp_enemy_bench = false;
bool g_show_instant_quit_window = false, g_boardLocked = false;
bool g_show_card_pool = false, g_card_warning = false;
bool g_show_sell_window = false;
float g_sell_win_x = 400.0f, g_sell_win_y = 350.0f, g_sell_win_scale = 1.0f;
bool g_show_auto_window = false, g_auto_refresh = false;
bool g_auto_buy = false, g_auto_buy_chosen = false;
bool g_show_hero_list_window = false;
bool g_show_clear_bench_btn = true;
bool g_show_equip_window = false;
bool g_auto_equip_active = false;
bool g_auto_unequip_active = false;
float g_equip_win_x = 400.0f, g_equip_win_y = 250.0f, g_equip_win_scale = 1.0f;
bool g_draw_hero_lines = true;
float g_esp_line_offset_y = 50.0f;
std::unordered_map<int, ImVec2> g_cell_equip_offset;
std::string g_cell_equip_offset_str = "";
std::unordered_map<int, ImVec2> g_cell_sell_offset;
std::string g_cell_sell_offset_str = "";
float g_sell_drop_x = 500.0f;
float g_sell_drop_y = 900.0f;
float g_equip_ui_start_x = 100.0f;
float g_equip_ui_start_y = 300.0f;
float g_equip_ui_step_x = 100.0f;
float g_equip_ui_step_y = 100.0f;
bool g_show_equip_ui_debug = false;
bool g_show_sell_ui_debug = false;
int g_unequip_slot_idx = 0;
int g_swipe_step_delay_ms = 10;
int g_swipe_steps = 15;
bool g_show_swipe_visuals = true;
int g_swipe_down_delay_ms = 30;
int g_swipe_up_delay_ms = 20;
int g_equip_extra_cooldown_ms = 100;
struct SwipeVisData { ImVec2 start; ImVec2 end; float lifeTime; float maxLife; };
std::vector<SwipeVisData> g_active_swipes;
std::mutex g_swipe_mutex;
std::unordered_set<int> g_auto_buy_heroes;
std::string g_auto_buy_heroes_str = "";
std::unordered_map<int, std::vector<int>> g_hero_equip_bindings;
std::string g_hero_equip_bindings_str = "";
std::unordered_map<int, int> g_hero_equip_priority;
std::string g_hero_equip_priority_str = "";
std::unordered_set<int> g_expanded_equip_heroes;
std::map<int, std::vector<int>> g_local_pokedex;
std::vector<int> g_local_equip_pokedex;
std::atomic<bool> g_pokedex_ready{false};
std::atomic<bool> g_equip_pokedex_ready{false};
float g_auto_buy_delay_ms = 0.0f;
int g_auto_refresh_money_threshold = 2;
float g_auto_win_x = 400.0f, g_auto_win_y = 150.0f, g_auto_win_scale = 1.0f;
float g_instant_win_x = 100.0f, g_instant_win_y = 100.0f, g_instant_win_scale = 1.0f;
float g_global_esp_alpha = 1.0f;
float g_enemy_bench_X = 200.0f, g_enemy_bench_Y = 200.0f, g_enemy_bench_Scale = 1.0f;
// 偏移量配置(保持不变)
int g_off_shop_base = 0x440, g_off_bench_base = 0x448, g_off_shop_p20 = 0x20;
int g_off_shop_entries = 0x10, g_off_entries_count = 0x18, g_off_entries_head = 0x20;
int g_off_entries_step = 0x20, g_off_entry_value = 0x10, g_off_value_slot = 0x1c;
int g_off_value_p10 = 0x10, g_off_p10_heroId = 0x14;
int g_off_pool_heroku = 0x18, g_off_pool_Aheroku = 0x18, g_off_pool_entries1 = 0x10;
int g_off_pool_e1_count = 0x18, g_off_pool_e1_head = 0x20, g_off_pool_e1_step = 0x20, g_off_pool_e1_val = 0x10;
int g_off_pool_entries2 = 0x10, g_off_pool_e2_count = 0x18, g_off_pool_e2_head = 0x20, g_off_pool_e2_step = 0x20, g_off_pool_e2_val = 0x10;
int g_off_pool_v2_id = 0x10, g_off_pool_v2_rem = 0x1c, g_off_pool_v2_tot = 0x20;
int g_off_equip_base = 0x2e8;
int g_off_equip_arr = 0x10;
int g_off_equip_count = 0x18;
int g_off_equip_head = 0x20;
int g_off_equip_step = 0x8;
int g_off_equip_id = 0x14;
int g_off_hero_dyn = 0x2b0;
int g_off_hero_arr = 0x20;
int g_off_hero_count = 0x18;
int g_off_hero_head = 0x20;
int g_off_hero_step = 0x8;
int g_off_hero_id = 0x108;
int g_off_hero_unit = 0x48;
int g_off_unit_battle = 0x20;
int g_off_battle_posx = 0x238;
int g_card_pool_rows = 2, g_card_pool_cols = 5;
float g_cardPoolX = 150.0f, g_cardPoolY = 150.0f;
float g_cardPoolScaleX = 1.0f, g_cardPoolScaleY = 1.0f, g_cardPoolAlpha = 1.0f;
bool g_show_pool_tiers[7] = {false, true, true, true, true, true, false};
bool g_pool_warning_enable = false;
int g_pool_warning_count = 3;
bool g_pool_warning_tiers[7] = {false, true, true, true, true, true, false};
bool g_warning_tiers[7] = {false, false, false, false, true, false, false};
int g_warning_threshold = 6;
bool g_show_debug_window = false, g_header_pred = true, g_header_esp = true, g_menuCollapsed = false;
float g_save_timer = 0.0f, g_scale = 1.0f, g_autoScale = 1.0f, g_current_rendered_size = 0.0f;
float g_anim[30] = {0.0f};
float g_boardScale = 2.2f, g_boardManualScale = 1.0f, g_startX = 400.0f, g_startY = 400.0f;
float g_menuX = 100.0f, g_menuY = 100.0f, g_menuW = 500.0f, g_menuH = 650.0f;
float g_enemy_X = 100.0f, g_enemy_Y = 100.0f, g_enemy_Scale = 1.0f;
float g_hex_X = 100.0f, g_hex_Y = 220.0f, g_hex_Scale = 1.0f;
float g_level_X = 1500.0f, g_level_Y = 200.0f, g_level_Scale = 1.0f, g_level_Spacing = 45.0f;
float g_warn_X = 1650.0f, g_warn_Y = 200.0f, g_warn_Scale = 1.0f, g_warn_Spacing = 45.0f;
float g_predictNameX = 500.0f, g_predictNameY = 300.0f, g_predictNameScale = 1.5f;
bool g_needUpdateFontSafe = false;
ImFont* g_mainFont = nullptr, *g_hugeNumFont = nullptr;
std::deque<std::string> g_collected_skins;
std::deque<std::string> g_collected_maps;
std::mutex g_collect_mutex;
bool g_collect_skins = false;
bool g_collect_maps = false;
ConfigEntry g_configTable[] = {
{"enableSkin", C_BOOL, &g_enable_skin}, {"skinIdx", C_INT, &g_selected_skin_idx},
{"enableMapSkin", C_BOOL, &g_enable_map_skin}, {"mapSkinIdx", C_INT, &g_selected_map_idx},
{"globalEspAlpha", C_FLOAT, &g_global_esp_alpha},
{"predictEnemy", C_BOOL, &g_predict_enemy}, {"predictHex", C_BOOL, &g_predict_hex},
{"predictNameX", C_FLOAT, &g_predictNameX}, {"predictNameY", C_FLOAT, &g_predictNameY}, {"predictNameScale", C_FLOAT, &g_predictNameScale},
{"collectSkins", C_BOOL, &g_collect_skins}, {"collectMaps", C_BOOL, &g_collect_maps},
{"espBoard", C_BOOL, &g_esp_board}, {"espLevel", C_BOOL, &g_esp_level},
{"espEnemyBench", C_BOOL, &g_esp_enemy_bench},
{"offShopBase", C_INT, &g_off_shop_base}, {"offBenchBase", C_INT, &g_off_bench_base}, {"offShopP20", C_INT, &g_off_shop_p20},
{"offShopEntries", C_INT, &g_off_shop_entries}, {"offEntriesCount", C_INT, &g_off_entries_count}, {"offEntriesHead", C_INT, &g_off_entries_head},
{"offEntriesStep", C_INT, &g_off_entries_step}, {"offEntryValue", C_INT, &g_off_entry_value}, {"offValueSlot", C_INT, &g_off_value_slot},
{"offValueP10", C_INT, &g_off_value_p10}, {"offP10HeroId", C_INT, &g_off_p10_heroId},
{"offPoolHeroku", C_INT, &g_off_pool_heroku}, {"offPoolAheroku", C_INT, &g_off_pool_Aheroku},
{"offPoolE1", C_INT, &g_off_pool_entries1}, {"offPoolE1Cnt", C_INT, &g_off_pool_e1_count},
{"offPoolE1Hd", C_INT, &g_off_pool_e1_head}, {"offPoolE1Stp", C_INT, &g_off_pool_e1_step},
{"offPoolE1Val", C_INT, &g_off_pool_e1_val}, {"offPoolE2", C_INT, &g_off_pool_entries2},
{"offPoolE2Cnt", C_INT, &g_off_pool_e2_count}, {"offPoolE2Hd", C_INT, &g_off_pool_e2_head},
{"offPoolE2Stp", C_INT, &g_off_pool_e2_step}, {"offPoolE2Val", C_INT, &g_off_pool_e2_val},
{"offPoolV2Id", C_INT, &g_off_pool_v2_id}, {"offPoolV2Rem", C_INT, &g_off_pool_v2_rem},
{"offPoolV2Tot", C_INT, &g_off_pool_v2_tot},
{"showCardPool", C_BOOL, &g_show_card_pool}, {"cardPoolRows", C_INT, &g_card_pool_rows}, {"cardPoolCols", C_INT, &g_card_pool_cols},
{"cardPoolScaleX", C_FLOAT, &g_cardPoolScaleX}, {"cardPoolScaleY", C_FLOAT, &g_cardPoolScaleY}, {"cardPoolAlpha", C_FLOAT, &g_cardPoolAlpha},
{"cardPoolX", C_FLOAT, &g_cardPoolX}, {"cardPoolY", C_FLOAT, &g_cardPoolY},
{"poolWarnEn", C_BOOL, &g_pool_warning_enable}, {"poolWarnCnt", C_INT, &g_pool_warning_count},
{"poolWT1", C_BOOL, &g_pool_warning_tiers[1]}, {"poolWT2", C_BOOL, &g_pool_warning_tiers[2]},
{"poolWT3", C_BOOL, &g_pool_warning_tiers[3]}, {"poolWT4", C_BOOL, &g_pool_warning_tiers[4]},
{"poolWT5", C_BOOL, &g_pool_warning_tiers[5]},
{"autoRefresh", C_BOOL, &g_auto_refresh}, {"autoBuy", C_BOOL, &g_auto_buy}, {"autoBuyDelay", C_FLOAT, &g_auto_buy_delay_ms},
{"autoRefMoneyThr", C_INT, &g_auto_refresh_money_threshold},
{"showAutoWin", C_BOOL, &g_show_auto_window}, {"autoBuyChosen", C_BOOL, &g_auto_buy_chosen},
{"autoWinX", C_FLOAT, &g_auto_win_x}, {"autoWinY", C_FLOAT, &g_auto_win_y}, {"autoWinScale", C_FLOAT, &g_auto_win_scale},
{"showDebug", C_BOOL, &g_show_debug_window}, {"cardWarning", C_BOOL, &g_card_warning}, {"warningThreshold", C_INT, &g_warning_threshold},
{"poolTier1", C_BOOL, &g_show_pool_tiers[1]}, {"poolTier2", C_BOOL, &g_show_pool_tiers[2]}, {"poolTier3", C_BOOL, &g_show_pool_tiers[3]},
{"poolTier4", C_BOOL, &g_show_pool_tiers[4]}, {"poolTier5", C_BOOL, &g_show_pool_tiers[5]},
{"warningTier1", C_BOOL, &g_warning_tiers[1]}, {"warningTier2", C_BOOL, &g_warning_tiers[2]}, {"warningTier3", C_BOOL, &g_warning_tiers[3]},
{"warningTier4", C_BOOL, &g_warning_tiers[4]}, {"warningTier5", C_BOOL, &g_warning_tiers[5]}, {"warningTier6", C_BOOL, &g_warning_tiers[6]},
{"instant", C_BOOL, &g_show_instant_quit_window}, {"boardLocked", C_BOOL, &g_boardLocked},
{"instantWinX", C_FLOAT, &g_instant_win_x}, {"instantWinY", C_FLOAT, &g_instant_win_y}, {"instantWinScale", C_FLOAT, &g_instant_win_scale},
{"showSellWin", C_BOOL, &g_show_sell_window}, {"sellWinX", C_FLOAT, &g_sell_win_x}, {"sellWinY", C_FLOAT, &g_sell_win_y}, {"sellWinScale", C_FLOAT, &g_sell_win_scale},
{"menuX", C_FLOAT, &g_menuX}, {"menuY", C_FLOAT, &g_menuY}, {"menuW", C_FLOAT, &g_menuW}, {"menuH", C_FLOAT, &g_menuH},
{"menuScale", C_FLOAT, &g_scale}, {"menuCollapsed", C_BOOL, &g_menuCollapsed},
{"startX", C_FLOAT, &g_startX}, {"startY", C_FLOAT, &g_startY}, {"manualScale", C_FLOAT, &g_boardManualScale},
{"enemyBenchX", C_FLOAT, &g_enemy_bench_X}, {"enemyBenchY", C_FLOAT, &g_enemy_bench_Y}, {"enemyBenchScale", C_FLOAT, &g_enemy_bench_Scale},
{"enemyX", C_FLOAT, &g_enemy_X}, {"enemyY", C_FLOAT, &g_enemy_Y}, {"enemyScale", C_FLOAT, &g_enemy_Scale},
{"hexX", C_FLOAT, &g_hex_X}, {"hexY", C_FLOAT, &g_hex_Y}, {"hexScale", C_FLOAT, &g_hex_Scale},
{"levelX", C_FLOAT, &g_level_X}, {"levelY", C_FLOAT, &g_level_Y}, {"levelScale", C_FLOAT, &g_level_Scale}, {"levelSpacing", C_FLOAT, &g_level_Spacing},
{"warnX", C_FLOAT, &g_warn_X}, {"warnY", C_FLOAT, &g_warn_Y}, {"warnScale", C_FLOAT, &g_warn_Scale}, {"warnSpacing", C_FLOAT, &g_warn_Spacing},
{"headerPred", C_BOOL, &g_header_pred}, {"headerEsp", C_BOOL, &g_header_esp},
{"showHeroListWin", C_BOOL, &g_show_hero_list_window},
{"autoBuyHeroes", C_STRING, &g_auto_buy_heroes_str},
{"heroEquipBindings", C_STRING, &g_hero_equip_bindings_str},
{"heroEquipPriority", C_STRING, &g_hero_equip_priority_str},
{"showEquipWin", C_BOOL, &g_show_equip_window},
{"equipWinX", C_FLOAT, &g_equip_win_x},
{"equipWinY", C_FLOAT, &g_equip_win_y},
{"equipWinScale", C_FLOAT, &g_equip_win_scale},
{"drawHeroLines", C_BOOL, &g_draw_hero_lines},
{"offEquipBase", C_INT, &g_off_equip_base},
{"offEquipArr", C_INT, &g_off_equip_arr},
{"offEquipCount", C_INT, &g_off_equip_count},
{"offEquipHead", C_INT, &g_off_equip_head},
{"offEquipStep", C_INT, &g_off_equip_step},
{"offEquipId", C_INT, &g_off_equip_id},
{"offHeroDyn", C_INT, &g_off_hero_dyn},
{"offHeroArr", C_INT, &g_off_hero_arr},
{"offHeroCount", C_INT, &g_off_hero_count},
{"offHeroHead", C_INT, &g_off_hero_head},
{"offHeroStep", C_INT, &g_off_hero_step},
{"offHeroId", C_INT, &g_off_hero_id},
{"offHeroUnit", C_INT, &g_off_hero_unit},
{"offUnitBattle", C_INT, &g_off_unit_battle},
{"offBattlePosx", C_INT, &g_off_battle_posx},
{"espLineOffsetY", C_FLOAT, &g_esp_line_offset_y},
{"cellEquipOffsets", C_STRING, &g_cell_equip_offset_str},
{"cellSellOffsets", C_STRING, &g_cell_sell_offset_str},
{"sellDropX", C_FLOAT, &g_sell_drop_x}, {"sellDropY", C_FLOAT, &g_sell_drop_y},
{"showClearBenchBtn", C_BOOL, &g_show_clear_bench_btn},
{"equipUiStartX", C_FLOAT, &g_equip_ui_start_x},
{"equipUiStartY", C_FLOAT, &g_equip_ui_start_y},
{"equipUiStepX", C_FLOAT, &g_equip_ui_step_x},
{"equipUiStepY", C_FLOAT, &g_equip_ui_step_y},
{"swipeDelay", C_INT, &g_swipe_step_delay_ms},
{"swipeSteps", C_INT, &g_swipe_steps},
{"showSwipeVis", C_BOOL, &g_show_swipe_visuals},
{"swipeDownDelay", C_INT, &g_swipe_down_delay_ms},
{"swipeUpDelay", C_INT, &g_swipe_up_delay_ms},
{"equipExtraCD", C_INT, &g_equip_extra_cooldown_ms},
{"unequipSlotIdx", C_INT, &g_unequip_slot_idx}
};
// ======================== IL2CPP 函数指针与换肤相关(保持不变)========================
typedef void* (*il2cpp_domain_get_t)();
typedef void* (*il2cpp_thread_attach_t)(void* domain);
typedef void (*il2cpp_thread_detach_t)(void* thread);
typedef void* (*il2cpp_string_new_t)(const char* str);
il2cpp_domain_get_t g_il2cpp_domain_get = nullptr;
il2cpp_thread_attach_t g_il2cpp_thread_attach = nullptr;
il2cpp_thread_detach_t g_il2cpp_thread_detach = nullptr;
il2cpp_string_new_t g_il2cpp_string_new = nullptr;
struct SkinInfo { const char* zh_name; const char* bundle; const char* asset; };
SkinInfo g_skinList[] = {
{"锐雯(至臻)", "art_tft_raw/little_legend_res/model/t_rivenswordgold/t_rivenswordgold/low", "t_rivenswordgold_1_show"},
// ... 省略中间皮肤(保持原样,太多不全部贴出,实际编译时请保留完整列表)
{"亚索(原皮黄)", "art_tft_raw/little_legend_res/model/t_yasuobase/t_yasuobase_yellow/low", "t_yasuobase_yellow_1_show"}
};
struct MapInfo { const char* zh_name; const char* bundle; const char* asset; };
MapInfo g_mapList[] = {
{"兰亭集序(神话)", "art_tft_raw/scenes/prefab/s11_tft_lantingpoems", "s11_tft_lantingpoems"},
// ... 省略中间地图
{"S4 凌云", "art_tft_raw/scenes/prefab/s4_tft_lingyun_001", "s4_tft_lingyun_001"}
};
// ======================== 安全读取与辅助函数(保持不变)========================
inline bool IsValidPtr(uintptr_t addr) {
return addr > 0x10000000 && addr < 0x00007FFFFFFFFFFF && (addr % 4 == 0);
}
// 获取模块基址
uintptr_t GetBase(const char* name) {
FILE* f = fopen("/proc/self/maps", "r");
if (!f) return 0;
char line[512];
uintptr_t base = 0;
while (fgets(line, sizeof(line), f)) {
if (strstr(line, name) && strstr(line, "r-xp")) {
sscanf(line, "%lx", &base);
break;
thread_local int g_safe_pipe[2] = {-1, -1};
bool SafeReadMemory(uintptr_t addr, void* buffer, size_t size) {
if (addr < 0x10000000 || addr > 0x00007FFFFFFFFFFF) return false;
if (g_safe_pipe[0] == -1) {
if (pipe2(g_safe_pipe, O_NONBLOCK) != 0) {
if (IsValidPtr(addr)) { memcpy(buffer, (void*)addr, size); return true; }
return false;
}
}
fclose(f);
return base;
ssize_t res = write(g_safe_pipe[1], (void*)addr, size);
if (res == (ssize_t)size) {
read(g_safe_pipe[0], buffer, size); return true;
} else if (res > 0) {
char temp[256]; read(g_safe_pipe[0], temp, res);
}
return false;
}
// 原函数只有1个参数,直接 Hook
void (*old_InitActor)(void* x0);
void hook_InitActor(void* x0) {
LOGI("[HOOK] InitActor x0 = %p", x0);
g_ActorManager = (uintptr_t)x0;
old_InitActor(x0);
std::deque<std::string> g_appLogs;
std::mutex g_logMutex;
void AddLog(const char* fmt, ...) {
char buf[1024];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
std::string logStr(buf);
std::lock_guard<std::mutex> lock(g_logMutex);
static std::unordered_set<std::string> seenLogs;
if (seenLogs.find(logStr) != seenLogs.end()) return;
seenLogs.insert(logStr);
time_t now = time(nullptr);
struct tm tstruct = *localtime(&now);
char timebuf[80];
strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tstruct);
g_appLogs.push_back(std::string("[") + timebuf + "] " + logStr);
if (g_appLogs.size() > 100) g_appLogs.pop_front();
}
#define SAFE_READ(type, base, offset, defaultVal) \
([&]() -> type { \
type val = defaultVal; \
uintptr_t targetAddr = (uintptr_t)(base) + (offset); \
if (!SafeReadMemory(targetAddr, &val, sizeof(type))) val = defaultVal; \
return val; \
}())
#define SAFE_READ_PTR(base, offset) SAFE_READ(uintptr_t, base, offset, 0)
std::string Utf16ToUtf8(const char16_t* u16str, size_t len) {
std::string u8str;
for (size_t i = 0; i < len; ++i) {
char16_t wc = u16str[i];
if (wc < 0x80) u8str += (char)wc;
else if (wc < 0x800) { u8str += (char)(0xC0 | (wc >> 6)); u8str += (char)(0x80 | (wc & 0x3F)); }
else { u8str += (char)(0xE0 | (wc >> 12)); u8str += (char)(0x80 | ((wc >> 6) & 0x3F)); u8str += (char)(0x80 | (wc & 0x3F)); }
}
return u8str;
}
std::string ReadIl2cppStr(void* strObj) {
if (!strObj || !IsValidPtr((uintptr_t)strObj)) return "";
int len = SAFE_READ(int, strObj, 0x10, 0);
if (len > 0 && len < 500) {
char16_t buffer[500] = {0};
if (SafeReadMemory((uintptr_t)strObj + 0x14, buffer, len * sizeof(char16_t))) {
return Utf16ToUtf8(buffer, len);
}
}
return "";
}
// 换肤相关 Hook(保持不变)
typedef void* (*func_LoadAsset_t)(void* x0, void* x1, void* x2, void* x3, int x4);
func_LoadAsset_t orig_LoadAsset_718 = nullptr;
void* hook_LoadAsset_718(void* x0, void* x1, void* x2, void* x3, int x4) {
if (x1 && x2) {
std::string bundleStr = ReadIl2cppStr(x1);
std::string assetStr = ReadIl2cppStr(x2);
if (g_collect_skins && !bundleStr.empty()) {
std::lock_guard<std::mutex> lock(g_collect_mutex);
std::string logStr = bundleStr + " | " + assetStr;
if (std::find(g_collected_skins.begin(), g_collected_skins.end(), logStr) == g_collected_skins.end()) {
g_collected_skins.push_back(logStr);
}
}
if (g_enable_skin && g_il2cpp_string_new) {
void* new_bundle = g_il2cpp_string_new(g_skinList[g_selected_skin_idx].bundle);
void* new_asset = g_il2cpp_string_new(g_skinList[g_selected_skin_idx].asset);
if (new_bundle && new_asset) {
return orig_LoadAsset_718(x0, new_bundle, new_asset, x3, x4);
}
}
}
return orig_LoadAsset_718(x0, x1, x2, x3, x4);
}
typedef void* (*func_LoadMapImpl_t)(void* x0, void* bundlePath, void* assetName, void* container, uint64_t isBackground, uint64_t isMineMap);
func_LoadMapImpl_t orig_LoadMapImpl = nullptr;
void* hook_LoadMapImpl(void* x0, void* bundlePath, void* assetName, void* container, uint64_t isBackground, uint64_t isMineMap) {
if (bundlePath && assetName) {
std::string bundleStr = ReadIl2cppStr(bundlePath);
std::string assetStr = ReadIl2cppStr(assetName);
if (g_collect_maps && !bundleStr.empty()) {
std::lock_guard<std::mutex> lock(g_collect_mutex);
std::string logStr = bundleStr + " | " + assetStr;
if (std::find(g_collected_maps.begin(), g_collected_maps.end(), logStr) == g_collected_maps.end()) {
g_collected_maps.push_back(logStr);
}
}
if (g_enable_map_skin && g_il2cpp_string_new) {
if (isMineMap != 0) {
void* new_bundle = g_il2cpp_string_new(g_mapList[g_selected_map_idx].bundle);
void* new_asset = g_il2cpp_string_new(g_mapList[g_selected_map_idx].asset);
if (new_bundle && new_asset) {
return orig_LoadMapImpl(x0, new_bundle, new_asset, container, isBackground, isMineMap);
}
}
}
}
return orig_LoadMapImpl(x0, bundlePath, assetName, container, isBackground, isMineMap);
}
// 以下数据结构与函数(RingBuffer, PlayerRowInfo, MainThreadTasks, 各种 Hook 实现等)全部保持不变
// 由于代码量巨大,这里只展示关键修改点,实际使用时请保留你原有的所有实现
// ======================== 核心修改:修正 Hook 函数原型(只有 1 个参数)========================
// 原代码中 old_InitActorParams 和 hook_InitActorParams 有 4 个参数,现改为 1 个参数
void (*old_InitActorParams)(void* x0);
void hook_InitActorParams(void* x0) {
LOGI("[HOOK] InitActorParams called! x0 = %p", x0);
if (x0 != nullptr) {
g_ActorManager.store((uintptr_t)x0);
// 可选测试读取偏移
uintptr_t test_addr = SafeRead<uintptr_t>((uintptr_t)x0 + g_Offsets.x0_to_addr1);
LOGI("[HOOK] x0+0x%x = %p", g_Offsets.x0_to_addr1, (void*)test_addr);
} else {
LOGE("[HOOK] x0 is null!");
}
old_InitActorParams(x0);
}
void (*old_ClearActor)(void* x0);
void hook_ClearActor(void* x0) {
LOGI("[HOOK] ClearActor x0 = %p", x0);
g_ActorManager = 0;
LOGI("[HOOK] ClearActor called! x0 = %p", x0);
g_ActorManager.store(0);
old_ClearActor(x0);
}
// 触摸事件处理
void handleTouch(AInputEvent* e) {
if (AInputEvent_getType(e) == AINPUT_EVENT_TYPE_MOTION) {
int act = AMotionEvent_getAction(e) & AMOTION_EVENT_ACTION_MASK;
g_touchX = AMotionEvent_getX(e, 0);
g_touchY = AMotionEvent_getY(e, 0);
g_touchDown = (act == AMOTION_EVENT_ACTION_DOWN);
}
}
typedef int (*Consume_t)(void*,void*,bool,int64_t,uint32_t*,void**);
Consume_t oldConsume = nullptr;
int hookConsume(void* a,void* b,bool c,int64_t d,uint32_t* e,void** f) {
int r = oldConsume(a,b,c,d,e,f);
if (r==0 && f && *f) handleTouch((AInputEvent*)*f);
return r;
}
// 注意:以下所有原有代码(DataWorkerThread、各种 Hook 函数、ImGui 绘制函数等)完全保持不变
// 请将你之前完整的实现粘贴在这里,包括:
// - 所有 Hook 函数(如 hook_3Cd6058, hook_set_Money, hook_TurnStart, hook_set_IsGameEnd 等)
// - 所有数据结构(GameSnapshot, PlayerInfo, EnemyHeroPos 等)
// - 所有绘制函数(DrawBoard, DrawBenchESP, DrawCardPool, DrawMenu 等)
// - 所有辅助函数(LoadConfig, SaveConfig, UpdateCardPoolData, UpdateEquipAndLiveHeroes 等)
// - 所有线程函数(BackgroundDataUpdateThread, TextureDecodingWorkerThread 等)
// - 最后 init_plugin 入口
// eglSwapBuffers Hook
typedef EGLBoolean (*Swap_t)(EGLDisplay,EGLSurface);
Swap_t oldSwap = nullptr;
static bool imguiReady = false;
EGLBoolean hookSwap(EGLDisplay dpy, EGLSurface surf) {
EGLint w, h;
eglQuerySurface(dpy, surf, EGL_WIDTH, &w);
eglQuerySurface(dpy, surf, EGL_HEIGHT, &h);
if (w > 0 && h > 0) {
if (!imguiReady) {
ImGui::CreateContext();
ImGui_ImplOpenGL3_Init("#version 300 es");
ImGui::GetIO().Fonts->AddFontDefault();
imguiReady = true;
}
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2(w, h);
io.MousePos = ImVec2(g_touchX, g_touchY);
io.MouseDown[0] = g_touchDown.load();
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
// 简单显示
int hp = 0;
if (g_ActorManager) {
uintptr_t addr1 = Read<uintptr_t>(g_ActorManager + 0x20);
if (addr1) {
uintptr_t addr2 = Read<uintptr_t>(addr1 + 0x10);
if (addr2) {
uintptr_t item = Read<uintptr_t>(addr2);
if (item) {
uintptr_t addr3 = Read<uintptr_t>(item + 0x18);
if (addr3) {
uintptr_t addr4 = Read<uintptr_t>(addr3 + 0x30);
if (addr4) hp = Read<int32_t>(addr4 + 0x30);
}
}
}
}
}
ImGui::Begin("Hook Test");
ImGui::Text("ActorManager: 0x%lx", g_ActorManager);
ImGui::Text("Player HP: %d", hp);
ImGui::End();
ImGui::Render();
glViewport(0, 0, w, h);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
return oldSwap(dpy, surf);
}
// 初始化线程
void* InitThread(void*) {
// 等待 libil2cpp.so 加载
uintptr_t base;
while (!(base = GetBase("libil2cpp.so"))) sleep(1);
uintptr_t initAddr = base + 0x73507bc;
uintptr_t clearAddr = base + 0x734bc10;
LOGI("Base=0x%lx, Init=0x%lx, Clear=0x%lx", base, initAddr, clearAddr);
DobbyHook((void*)initAddr, (void*)hook_InitActor, (void**)&old_InitActor);
DobbyHook((void*)clearAddr, (void*)hook_ClearActor, (void**)&old_ClearActor);
// Hook EGL 和 Input
DobbyHook(DobbySymbolResolver("libEGL.so", "eglSwapBuffers"), (void*)hookSwap, (void**)&oldSwap);
DobbyHook(DobbySymbolResolver("libinput.so", "_ZN7android13InputConsumer7consumeEPNS_26InputEventFactoryInterfaceEblPjPPNS_10InputEventE"), (void*)hookConsume, (void**)&oldConsume);
return nullptr;
}
__attribute__((constructor)) void entry() {
pthread_t t;
pthread_create(&t, nullptr, InitThread, nullptr);
}
// 由于篇幅限制,这里只给出修改后的 Hook 函数部分,其余代码请原样保留。
// 如果你需要我将整个完整代码(包括所有功能)重新贴出来,请告知,我会逐段提供。