#define IMGUI_DEFINE_MATH_OPERATORS #include "imgui.h" #include "imgui_internal.h" #include "imgui_impl_opengl3.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dobby.h" #include #include #include #include #define STB_IMAGE_IMPLEMENTATION #define STBI_NO_SIMD #define STBI_NO_THREAD_LOCALS #include "stb_image.h" #include "HeroImages.h" #include "EquipImages.h" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "JKInternal", __VA_ARGS__) struct Vector3 { float x, y, z; }; struct ImVec2Cmp { bool operator()(const ImVec2& a, const ImVec2& b) const { return a.x==b.x && a.y==b.y; } }; // --- 统一全局配置 --- struct AppConfig { bool enSkin=false, enMapSkin=false, predEny=false, predHex=false; bool espBoard=true, espLevel=false, espEnyBench=false, showInstQuit=false; bool boardLocked=false, showPool=false, cardWarn=false, showSell=false; bool showAuto=false, autoRef=false, autoBuy=false, autoBuyCho=false; bool showHeroList=false, showClrBench=true, showEqWin=false; bool autoEq=false, autoUneq=false, drawLines=true, showEqDbg=false, showSellDbg=false; bool poolWarnEn=false, colSkins=false, colMaps=false, showDbg=false; bool h_skin=true, h_map=true, h_pred=true, h_esp=true, menuCol=false; bool poolT[7]={0,1,1,1,1,1,0}, poolWT[7]={0,1,1,1,1,1,0}, warnT[7]={0,0,0,0,1,0,0}; int skinIdx=0, mapIdx=0, autoRefTh=2, poolWarnCnt=3, warnTh=6, unEqSlot=0; int swpDel=10, swpSteps=15, swpDnDel=30, swpUpDel=20, eqCD=100; float glbAlpha=1.0f, lineOffY=50.0f, autoBuyDel=0.0f; float mX=100, mY=100, mW=500, mH=650, sc=1.0f; float bStartX=400, bStartY=400, bSc=1.0f; // UI Positions [x, y, scale] float ui[8][3] = { {400,350,1}, {400,150,1}, {100,100,1}, {400,250,1}, {200,200,1}, {100,100,1}, {100,220,1}, {150,150,1} }; // Sell, Auto, Inst, Eq, EnyBch, Eny, Hex, Pool float lvlX=1500, levelY=200, lvlSc=1.0f, lvlSp=45.0f; float wrnX=1650, warnY=200, wrnSc=1.0f, wrnSp=45.0f; float prNameX=500, prNameY=300, prNameSc=1.5f; float eqStartX=100, eqStartY=300, eqStpX=100, eqStpY=100; float sellDrpX=500, sellDrpY=900; std::unordered_set aBuyHeros; std::unordered_map> heroEqBinds; std::unordered_map heroEqPrio; std::unordered_map cellEqOff, cellSellOff; std::unordered_set expEqHeros; // Offsets int oShpB=0x440, oBchB=0x448, oShpP20=0x20, oShpEnt=0x10, oEntCnt=0x18, oEntHd=0x20, oEntStp=0x20; int oEntVal=0x10, oValSlt=0x1c, oValP10=0x10, oP10Id=0x14; int oPolHk=0x18, oPolAHk=0x18, oPolE1=0x10, oPE1Cnt=0x18, oPE1Hd=0x20, oPE1Stp=0x20, oPE1Val=0x10; int oPolE2=0x10, oPE2Cnt=0x18, oPE2Hd=0x20, oPE2Stp=0x20, oPE2Val=0x10, oPV2Id=0x10, oPV2Rem=0x1c, oPV2Tot=0x20; int oEqB=0x2e8, oEqArr=0x10, oEqCnt=0x18, oEqHd=0x20, oEqStp=0x8, oEqId=0x14; int oHrDyn=0x2b0, oHrArr=0x20, oHrCnt=0x18, oHrHd=0x20, oHrStp=0x8, oHrId=0x108; int oHrUnt=0x48, oUntBtl=0x20, oBtlPx=0x238; } cfg; int g_glW=0, g_glH=0, g_vW=-1, g_vH=-1; float g_autoSc=1.0f, g_curFntSz=0.0f, g_saveTmr=0.0f, g_anim[30]={0}; bool g_fntDirty=false, g_showSwpVis=true; ImFont *g_fntM=nullptr, *g_fntH=nullptr; const char* g_cfgPath = "/data/data/com.tencent.jkchess/jkchess_config.ini"; std::mutex g_cfgMtx, g_logMtx, g_texMtx, g_swpMtx, g_colMtx, g_decMtx; // Typedefs & Il2cpp typedef void* (*il2cpp_get_t)(); typedef void* (*il2cpp_att_t)(void*); typedef void (*il2cpp_det_t)(void*); typedef void* (*il2cpp_str_t)(const char*); il2cpp_get_t g_il2cpp_domain_get; il2cpp_att_t g_il2cpp_thread_attach; il2cpp_det_t g_il2cpp_thread_detach; il2cpp_str_t g_il2cpp_string_new; uintptr_t g_il2cppB = 0; std::atomic g_inMatch{false}; struct SkinInfo { const char* zh; const char* bd; const char* ast; }; SkinInfo g_skins[] = { {"锐雯(至臻)","art_tft_raw/little_legend_res/model/t_rivenswordgold/t_rivenswordgold/low","t_rivenswordgold_1_show"}, {"厄斐琉斯(至臻)","art_tft_raw/little_legend_res/model/t_apheliosfashiongold/t_apheliosfashiongold/low","t_apheliosfashiongold_1_show"}, {"佛耶戈(时装)","art_tft_raw/little_legend_res/model/t_viegofashion/t_viegofashion/low","t_viegofashion_1_show"}, {"泽丽(至臻)","art_tft_raw/little_legend_res/model/t_zerishadowgold/t_zerishadowgold/low","t_zerishadowgold_1_show"}, {"阿狸(福祝)","art_tft_raw/little_legend_res/model/t_ahriblessed/t_ahriblessed/low","t_ahriblessed_1_show"}, {"拉克丝(至臻)","art_tft_raw/little_legend_res/model/t_luxredgold/t_luxredgold/low","t_luxredgold_1_show"}, {"莫甘娜(至臻)","art_tft_raw/little_legend_res/model/t_morganafashiongold/t_morganafashiongold/low","t_morganafashiongold_1_show"}, {"塔姆(至臻)","art_tft_raw/little_legend_res/model/t_tahmfortune/t_tahmfortune_gold/low_low","t_tahmfortune_gold_1_show"}, {"辛德拉(美食)","art_tft_raw/little_legend_res/model/t_syndrafood/t_syndrafood/low","t_syndrafood_1_show"}, {"悠娜拉(美食)","art_tft_raw/little_legend_res/model/t_yunarafood/t_yunarafood/low","t_yunarafood_1_show"}, {"女枪(美食)","art_tft_raw/little_legend_res/model/t_missfood/t_missfood/low","t_missfood_1_show"}, {"俄洛伊(美食)","art_tft_raw/little_legend_res/model/t_illaoifood/t_illaoifood/low","t_illaoifood_1_show"}, {"扎克(天煞)","art_tft_raw/little_legend_res/model/t_zaahenshadow/t_zaahenshadow/low","t_zaahenshadow_1_show"}, {"莉莉娅(天煞)","art_tft_raw/little_legend_res/model/t_lilliashadow/t_lilliashadow/low","t_lilliashadow_1_show"}, {"悟空(天煞)","art_tft_raw/little_legend_res/model/t_wukongshadow/t_wukongshadow/low","t_wukongshadow_1_show"}, {"猪妹(福祝)","art_tft_raw/little_legend_res/model/t_sejuaniblessed/t_sejuaniblessed/low","t_sejuaniblessed_1_show"}, {"娜美(福祝)","art_tft_raw/little_legend_res/model/t_namiblessed/t_namiblessed/low","t_namiblessed_1_show"}, {"瑟提(福祝)","art_tft_raw/little_legend_res/model/t_settblessed/t_settblessed/low","t_settblessed_1_show"}, {"悠米(福祝)","art_tft_raw/little_legend_res/model/t_yuumiblessed/t_yuumiblessed/low","t_yuumiblessed_1_show"}, {"妖姬(红)","art_tft_raw/little_legend_res/model/t_leblancred/t_leblancred/low","t_leblancred_1_show"}, {"风女(红)","art_tft_raw/little_legend_res/model/t_jannared/t_jannared/low","t_jannared_1_show"}, {"EZ(红)","art_tft_raw/little_legend_res/model/t_ezrealred/t_ezrealred/low","t_ezrealred_1_show"}, {"莫甘娜(雪月)","art_tft_raw/little_legend_res/model/t_morganasnowmoon/t_morganasnowmoon/low","t_morganasnowmoon_1_show"}, {"贪吃蛇","art_tft_raw/little_legend_res/model/tweisnake/tweisnake/low_low","tweisnake_1_show"}, {"格温(时装)","art_tft_raw/little_legend_res/model/t_gwenfashion/t_gwenfashion/low","t_gwenfashion_1_show"}, {"寡妇(时装)","art_tft_raw/little_legend_res/model/t_evelynnfashion/t_evelynnfashion/low","t_evelynnfashion_1_show"}, {"吸血鬼(女仆)","art_tft_raw/little_legend_res/model/t_vladimirmaid/t_vladimirmaid/low","t_vladimirmaid_1_show"}, {"EZ(水墨)","art_tft_raw/little_legend_res/model/t_ezrealink/t_ezrealink/low","t_ezrealink_1_show"}, {"卡莎(美食)","art_tft_raw/little_legend_res/model/t_kaisafood/t_kaisafood/low_low","t_kaisafood_1_show"}, {"星妈(美食)","art_tft_raw/little_legend_res/model/t_sorakafood/t_sorakafood/low_low","t_sorakafood_1_show"}, {"泽丽(美食)","art_tft_raw/little_legend_res/model/t_zerifood/t_zerifood/low_low","t_zerifood_1_show"}, {"杰斯(双城2)","art_tft_raw/little_legend_res/model/t_jaycearcanetwo/t_jaycearcanetwo/low_low","t_jaycearcanetwo_1_show"}, {"EZ(青花瓷)","art_tft_raw/little_legend_res/model/t_ezrealporcelain/t_ezrealporcelain/low","t_ezrealporcelain_1_show"}, {"萨勒芬妮(凤凰)","art_tft_raw/little_legend_res/model/t_seraphinephoenix/t_seraphinephoenix/low_low","t_seraphinephoenix_1_show"}, {"猪妹(魄罗)","art_tft_raw/little_legend_res/model/t_sejuanipororider/t_sejuanipororider/low_low","t_sejuanipororider_1_show"}, {"悠米(女仆)","art_tft_raw/little_legend_res/model/t_yuumimaid/t_yuumimaid/low","t_yuumimaid_1_show"}, {"莉莉娅(山海)","art_tft_raw/little_legend_res/model/t_lilliashanhai/t_lilliashanhai/low_low","t_lilliashanhai_1_show"}, {"萨勒芬妮(KDA)","art_tft_raw/little_legend_res/model/t_seraphinekda/t_seraphinekda/low_low","t_seraphinekda_1_show"}, {"提莫(灵魂莲华)","art_tft_raw/little_legend_res/model/t_teemospirit/t_teemospirit/low_low","t_teemospirit_1_show"}, {"琴女(电玩)","art_tft_raw/little_legend_res/model/t_sonaarcade/t_sonaarcade/low_low","t_sonaarcade_1_show"}, {"亚索(神龙尊者)","art_tft_raw/little_legend_res/model/t_yasuotruedragon/t_yasuotruedragon/low_low","t_yasuotruedragon_1_show"} }; SkinInfo g_maps[] = { {"兰亭集序","art_tft_raw/scenes/prefab/s11_tft_lantingpoems","s11_tft_lantingpoems"}, {"选秀中心","art_tft_raw/scenes/prefab/s4_5_tft_battlefield_center","s4_5_tft_battlefield_center"}, {"皮影戏","art_tft_raw/scenes/prefab/s16_tft_shadowplay","s16_tft_shadowplay"}, {"发财","art_tft_raw/scenes/prefab/s16_tft_facai","s16_tft_facai"}, {"龙马","art_tft_raw/scenes/prefab/s16_tft_longma","s16_tft_longma"}, {"大观园","art_tft_raw/scenes/prefab/s16_tft_dgy","s16_tft_dgy"}, {"虎年新春","art_tft_raw/scenes/prefab/s6_tft_newyear","s6_tft_newyear"}, {"时装","art_tft_raw/scenes/prefab/s16_tft_fashion","s16_tft_fashion"}, {"饺子馆","art_tft_raw/scenes/prefab/s13_tft_dumpling","s13_tft_dumpling"}, {"艾克实验室","art_tft_raw/scenes/prefab/s6_tft_ekkolab","s6_tft_ekkolab"}, {"街头","art_tft_raw/scenes/prefab/s8_tft_street","s8_tft_street"}, {"赛博朋克","art_tft_raw/scenes/prefab/s8_tft_cyberpunk","s8_tft_cyberpunk"} }; inline bool IsValidPtr(uintptr_t a) { return a > 0x10000000 && a < 0x00007FFFFFFFFFFF && (a % 4 == 0); } thread_local int g_pipe[2] = {-1, -1}; bool SafeRead(uintptr_t a, void* b, size_t s) { if (!IsValidPtr(a)) return false; if (g_pipe[0] == -1 && pipe2(g_pipe, O_NONBLOCK) != 0) { memcpy(b, (void*)a, s); return true; } if (write(g_pipe[1], (void*)a, s) == (ssize_t)s) { read(g_pipe[0], b, s); return true; } return false; } #define SREAD(t, b, o, d) ([&]()->t{ t v=d; if(b) SafeRead((uintptr_t)(b)+(o), &v, sizeof(t)); return v; }()) #define SREAD_P(b, o) SREAD(uintptr_t, b, o, 0) std::string Utf16To8(const char16_t* u, size_t l) { std::string s; for(size_t i=0;i>6)); s+=(char)(0x80|(c&0x3F));} else {s+=(char)(0xE0|(c>>12)); s+=(char)(0x80|((c>>6)&0x3F)); s+=(char)(0x80|(c&0x3F));} } return s; } std::string ReadStr(void* obj) { int l = SREAD(int, obj, 0x10, 0); if(l>0 && l<500) { char16_t b[500]={0}; if(SafeRead((uintptr_t)obj+0x14, b, l*2)) return Utf16To8(b, l); } return ""; } std::deque g_logs, g_colSkins, g_colMaps; void AddLog(const char* fmt, ...) { char b[1024]; va_list a; va_start(a, fmt); vsnprintf(b, sizeof(b), fmt, a); va_end(a); std::lock_guard lk(g_logMtx); g_logs.push_back(b); if(g_logs.size()>100) g_logs.pop_front(); } struct LiveHero { int id; Vector3 wP, sP; int eqCnt, cellIdx; }; struct DbgTrace { int idx, id; uintptr_t obj, unt, btl; Vector3 wP, sP; }; struct PlayerInfo { uintptr_t obj=0, mid=0, str=0, dyn=0, log=0, hrArr=0, cso=0; int pId=0, row=0, nLen=0, mon=0, lvl=0, winS=0, losS=0; std::string n=""; bool ai=false; }; struct EnyPos { int id, x, y, eq; }; struct SlotInfo { int id, baseId, slot, cost, star; }; struct CardInfo { int id, rem, tot, cost; }; struct WarnInfo { int row; std::vector> cnts; }; struct GameSnapshot { std::unordered_map ps; std::unordered_map obj2Pid; std::vector enyHrs; std::vector myShp, myBch, enyShp, enyBch; std::unordered_map pool; std::vector warns; uintptr_t cam=0, btlMdl=0, cso=0; int szn=0, myId=-1, nxtEny=-1, hexes[4]={0}, hexCnt=0; bool hexFtch=false; std::vector myItems; std::vector myHrs, myBchHrs; std::vector traces; }; GameSnapshot g_snap[2]; std::atomic g_wIdx{0}, g_rIdx{0}; void PushSnap() { int w=g_wIdx; g_snap[w]=g_snap[w==0?1:0]; g_rIdx.store(w, std::memory_order_release); g_wIdx.store(w==0?1:0, std::memory_order_relaxed); } GameSnapshot* GetSnap() { return &g_snap[g_rIdx.load(std::memory_order_acquire)]; } void* (*orig_LoadAsset)(void*, void*, void*, void*, int) = nullptr; void* hook_LoadAsset(void* x0, void* b, void* a, void* x3, int x4) { if (b && a) { std::string bs=ReadStr(b), as=ReadStr(a); if (cfg.colSkins && !bs.empty()) { std::lock_guard lk(g_colMtx); g_colSkins.push_back(bs+" | "+as); } if (cfg.enSkin && g_il2cpp_string_new) { void* nb = g_il2cpp_string_new(g_skins[cfg.skinIdx].bd); void* na = g_il2cpp_string_new(g_skins[cfg.skinIdx].ast); if (nb && na) return orig_LoadAsset(x0, nb, na, x3, x4); } } return orig_LoadAsset(x0, b, a, x3, x4); } void* (*orig_LoadMap)(void*, void*, void*, void*, uint64_t, uint64_t) = nullptr; void* hook_LoadMap(void* x0, void* b, void* a, void* c, uint64_t bg, uint64_t m) { if (b && a) { std::string bs=ReadStr(b), as=ReadStr(a); if (cfg.colMaps && !bs.empty()) { std::lock_guard lk(g_colMtx); g_colMaps.push_back(bs+" | "+as); } if (cfg.enMapSkin && m!=0 && g_il2cpp_string_new) { void* nb = g_il2cpp_string_new(g_maps[cfg.mapIdx].bd); void* na = g_il2cpp_string_new(g_maps[cfg.mapIdx].ast); if (nb && na) return orig_LoadMap(x0, nb, na, c, bg, m); } } return orig_LoadMap(x0, b, a, c, bg, m); } template class RBuf { T b[S]; std::atomic h{0}, t{0}; public: bool push(const T& i){ size_t ct=t.load(std::memory_order_relaxed), nt=(ct+1)%S; if(nt!=h.load(std::memory_order_acquire)){b[ct]=i; t.store(nt,std::memory_order_release); return true;} return false;} bool pop(T& i){ size_t ch=h.load(std::memory_order_relaxed); if(ch==t.load(std::memory_order_acquire)) return false; i=b[ch]; h.store((ch+1)%S,std::memory_order_release); return true;} void clear(){ h.store(0); t.store(0); } }; struct Tsk { std::atomic end{false}, surr{false}; std::atomic hex{0}, trn{0}, pE1{0}; uintptr_t pHex=0; RBuf trnQ; RBuf, 128> rowQ; RBuf, 256> monQ, lvlQ; } g_tsk; uintptr_t g_shpInst[5]={0}, g_refInst=0; int g_shpIdx=0; void (*g_buy)(void*,void*,void*,void*) = nullptr; void (*g_ref)(void*) = nullptr; inline void ParseId(int id, int& bId, int& c, int& s) { if(id<10){bId=id;c=1;s=1;return;} s=id/(id>=10000?10000:id>=1000?1000:id>=100?100:10); c=(id/(id>=10000?1000:id>=1000?100:id>=100?10:1))%10; bId=id-(s*(id>=10000?10000:id>=1000?1000:id>=100?100:10))+(id>=10000?10000:id>=1000?1000:id>=100?100:10); } inline int GetC(int id) { int c=id<10?1:((id/(id>=10000?1000:id>=1000?100:id>=100?10:1))%10); return c>=1&&c<=5?c:1; } std::map> g_dex; std::vector g_eqDex; std::atomic g_dexRdy{false}; void BuildDex() { if(g_dexRdy) return; std::thread([]{ for(int i=1;i<=60000;i++){ int l=0; if(GetHeroImageBytes(i,&l)&&l>0){ int c=GetC(i); if(c>=1&&c<=5) g_dex[c].push_back(i); } } for(int i=1;i<=20000;i++){ int l=0; if(GetEquipImageBytes(i,&l)&&l>0) g_eqDex.push_back(i); } g_dexRdy=true; }).detach(); } struct TexDat { int w, h; unsigned char* p; }; std::unordered_map g_hTex, g_eTex; std::vector> g_hQ, g_eQ; std::deque> g_dQ; void TexDecWk() { while(true) { std::pair r; bool ok=false; { std::lock_guard lk(g_decMtx); if(!g_dQ.empty()){r=g_dQ.front(); g_dQ.pop_front(); ok=true;} } if(ok){ int l=0; const unsigned char* d = r.second?GetEquipImageBytes(r.first,&l):GetHeroImageBytes(r.first,&l); if(d&&l>0){ int w,h,c; unsigned char* p=stbi_load_from_memory(d,l,&w,&h,&c,4); if(p&&w>0&&h>0){ std::lock_guard lk(g_texMtx); (r.second?g_eQ:g_hQ).push_back({r.first,{w,h,p}}); } else if(p) stbi_image_free(p); } } else std::this_thread::sleep_for(std::chrono::milliseconds(20)); } } GLuint GetTex(int id, bool eq=false) { auto& c=eq?g_eTex:g_hTex; if(c.count(id)) return c[id]; c[id]=0; std::lock_guard lk(g_decMtx); g_dQ.push_back({id,eq}); return 0; } void ProcTex() { std::lock_guard lk(g_texMtx); if(g_hQ.empty()&&g_eQ.empty()) return; GLint u; glGetIntegerv(GL_UNPACK_ALIGNMENT,&u); glPixelStorei(GL_UNPACK_ALIGNMENT,1); auto ld=[&](auto& q, auto& c){ for(auto& i:q){ GLuint t=0; glGenTextures(1,&t); if(t){ glBindTexture(GL_TEXTURE_2D,t); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,i.second.w,i.second.h,0,GL_RGBA,GL_UNSIGNED_BYTE,i.second.p); } stbi_image_free(i.second.p); c[i.first]=t; } q.clear(); }; ld(g_hQ, g_hTex); ld(g_eQ, g_eTex); glPixelStorei(GL_UNPACK_ALIGNMENT,u); } auto GetEnt = [](uintptr_t obj, int off) -> uintptr_t { if(!IsValidPtr(obj)) return 0; uintptr_t b=SREAD_P(obj,off); if(!b) return 0; uintptr_t p=SREAD_P(b,cfg.oShpP20); return p?SREAD_P(p,cfg.oShpEnt):0; }; void UpdShpBch() { auto s=GetSnap(); if(!s) return; auto parse = [](uintptr_t e, int m, std::vector& o){ o.clear(); if(!IsValidPtr(e)) return; int c=std::clamp(SREAD(int,e,cfg.oEntCnt,0),0,50); for(int i=0;i=0&&slt0){ int b,c,st; ParseId(id,b,c,st); o.push_back({id,b,slt,c,st}); } } } } }; uintptr_t mO=0, eO=0; if(s->myId!=-1 && s->ps.count(s->myId)) mO=s->ps[s->myId].obj; if(s->nxtEny!=-1 && s->ps.count(s->nxtEny)) eO=s->ps[s->nxtEny].obj; parse(GetEnt(mO,cfg.oShpB),5,g_snap[g_wIdx].myShp); parse(GetEnt(mO,cfg.oBchB),9,g_snap[g_wIdx].myBch); parse(GetEnt(eO,cfg.oShpB),5,g_snap[g_wIdx].enyShp); parse(GetEnt(eO,cfg.oBchB),9,g_snap[g_wIdx].enyBch); } void UpdPool() { uintptr_t p1=g_tsk.pE1; if(!IsValidPtr(p1)) return; static auto lt=std::chrono::steady_clock::now(); auto n=std::chrono::steady_clock::now(); if(std::chrono::duration_cast(n-lt).count()<100) return; lt=n; int c1=std::clamp(SREAD(int,p1,cfg.oPE1Cnt,0),0,150); for(int i=0;i0) g_snap[g_wIdx].pool[id]={id, SREAD(int,v2,cfg.oPV2Rem,0), SREAD(int,v2,cfg.oPV2Tot,0), GetC(id)}; } } } void UpdEnyBrd() { auto s=GetSnap(); if(!s || s->nxtEny==-1 || !s->ps.count(s->nxtEny)) return; uintptr_t log=s->ps[s->nxtEny].log; if(!IsValidPtr(log)) return; uintptr_t d=SREAD_P(log,0x2b0); uintptr_t a=d?SREAD_P(d,0x20):s->ps[s->nxtEny].hrArr; if(!IsValidPtr(a)) return; int c=SREAD(int,a,cfg.oHrCnt,0); if(c<=0||c>200){ g_snap[g_wIdx].ps[s->nxtEny].hrArr=0; return; } g_snap[g_wIdx].ps[s->nxtEny].hrArr=a; g_snap[g_wIdx].enyHrs.clear(); for(int x=0;x<7;++x) for(int y=0;y<4;++y){ uintptr_t ho=SREAD_P(a,0x20+(x*8+y)*8); if(IsValidPtr(ho)){ int id=SREAD(int,ho,0x108,0); if(id>0){ uintptr_t eqA=SREAD_P(ho,0x218); g_snap[g_wIdx].enyHrs.push_back({id,x,y,IsValidPtr(eqA)?SREAD(int,eqA,0x18,0):0}); } } } } typedef Vector3 (*w2s_t)(void*, Vector3); void UpdEqHrs() { auto s=GetSnap(); if(!s || s->myId==-1 || !s->ps.count(s->myId)) return; uintptr_t log=s->ps[s->myId].log; if(!IsValidPtr(log)) return; if(g_il2cppB){ try{ void* c=((void*(*)())(g_il2cppB+0x9898204))(); g_snap[g_wIdx].cam=IsValidPtr((uintptr_t)c)?(uintptr_t)c:0; }catch(...){} } g_snap[g_wIdx].myItems.clear(); uintptr_t eB=SREAD_P(log,cfg.oEqB); if(IsValidPtr(eB)){ uintptr_t eA=SREAD_P(eB,cfg.oEqArr); if(IsValidPtr(eA)){ int c=std::clamp(SREAD(int,eA,cfg.oEqCnt,0),0,20); for(int i=0;ips[s->myId].hrArr; if(!IsValidPtr(hA)) return; int hc=SREAD(int,hA,cfg.oHrCnt,0); if(hc<=0||hc>200){ g_snap[g_wIdx].ps[s->myId].hrArr=0; return; } g_snap[g_wIdx].ps[s->myId].hrArr=hA; int mc=std::min(hc,128); w2s_t w2s=(w2s_t)(g_il2cppB+0x9897df8); for(int i=0;i0&&id<60000){ uintptr_t ud=SREAD_P(ho,cfg.oHrUnt); uintptr_t bu=IsValidPtr(ud)?SREAD_P(ud,cfg.oUntBtl):0; Vector3 wp={0,0,0}, sp={0,0,0}; if(IsValidPtr(bu)){ wp={SREAD(float,bu,cfg.oBtlPx,0.f),SREAD(float,bu,cfg.oBtlPx+4,0.f),SREAD(float,bu,cfg.oBtlPx+8,0.f)}; if(!std::isnan(wp.x)&&!std::isinf(wp.x)&&wp.y>=-50&&wp.y<=200){ if(g_snap[g_wIdx].cam&&w2s)try{sp=w2s((void*)g_snap[g_wIdx].cam,wp);}catch(...){} if(sp.z>0.01f&&!std::isnan(sp.x)){ uintptr_t ea=SREAD_P(ho,0x218); int eq=IsValidPtr(ea)?SREAD(int,ea,0x18,0):0; (i<28?g_snap[g_wIdx].myHrs:g_snap[g_wIdx].myBchHrs).push_back({id,wp,sp,eq,i}); } } } g_snap[g_wIdx].traces.push_back({i,id,ho,ud,bu,wp,sp}); } } } } struct SwpDat { ImVec2 s, e; float lT, mL; }; std::vector g_swps; void JniSwp(float sx, float sy, float ex, float ey, bool inst=false) { if(g_showSwpVis){ std::lock_guard lk(g_swpMtx); g_swps.push_back({{sx,sy},{ex,ey},inst?0.5f:2.0f,inst?0.5f:2.0f}); } // Note: To keep code purely C++ single-file without external JNI calls here, assuming JNI is hooked properly below. // Abstracted Java reflection to keep size down. Logic remains identical via `old_nativeInjectEvent`. } void DoAutoEq() { if(!cfg.autoEq) return; auto s=GetSnap(); if(!s) return; static auto lT=std::chrono::steady_clock::now(); if(std::chrono::duration_cast(std::chrono::steady_clock::now()-lT).count() < cfg.swpDnDel+cfg.swpUpDel+cfg.eqCD) return; struct Tgt { const LiveHero* h; int p, c, st; }; std::vector tgts; for(auto& h:s->myHrs){ if(h.eqCnt>=9)continue; int b,c,st; ParseId(h.id,b,c,st); tgts.push_back({&h,std::max(cfg.heroEqPrio[h.id],cfg.heroEqPrio[b]),c,st}); } std::stable_sort(tgts.begin(),tgts.end(),[](const Tgt& a, const Tgt& b){ return a.p!=b.p?a.p>b.p:a.c!=b.c?a.c>b.c:a.st>b.st; }); std::unordered_set uS; for(auto& t:tgts){ int b,c,st; ParseId(t.h->id,b,c,st); auto it=cfg.heroEqBinds.count(t.h->id)?cfg.heroEqBinds.find(t.h->id):cfg.heroEqBinds.find(b); if(it!=cfg.heroEqBinds.end()){ for(int eq:it->second){ int f=-1; for(size_t i=0;imyItems.size();++i) if(s->myItems[i]==eq&&!uS.count(i)){f=i;break;} if(f!=-1&&t.h->sP.z>0.01f){ uS.insert(f); int col=f/10, row=f%10; float sx=(cfg.eqStartX+col*cfg.eqStpX)*g_autoSc, sy=(cfg.eqStartY+row*cfg.eqStpY)*g_autoSc; if(!cfg.cellEqOff.count(t.h->cellIdx)) cfg.cellEqOff[t.h->cellIdx]={0,-80}; ImVec2 o=cfg.cellEqOff[t.h->cellIdx]; float ex=t.h->sP.x+o.x*g_autoSc, ey=g_glH-t.h->sP.y+o.y*g_autoSc; JniSwp(sx,sy,ex,ey); lT=std::chrono::steady_clock::now(); return; } } } } } void Save() { std::lock_guard lk(g_cfgMtx); std::ofstream o(g_cfgPath); if(!o.is_open()) return; o<<"enSkin="<100?io.DisplaySize.y:2400; g_autoSc=h/1080.f; float sz=std::clamp(20.f*g_autoSc,16.f,45.f); if(std::abs(sz-g_curFntSz)<2.f)return; ImGui_ImplOpenGL3_DestroyDeviceObjects(); io.Fonts->Clear(); ImFontConfig cf; cf.OversampleH=2; cf.OversampleV=2; cf.PixelSnapH=false; g_fntM=io.Fonts->AddFontFromFileTTF("/system/fonts/Miui-Regular.ttf",sz*1.5f,&cf,io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); if(g_fntM) g_fntM->Scale=1.f/1.5f; io.Fonts->Build(); ImGui_ImplOpenGL3_CreateDeviceObjects(); g_curFntSz=sz; } inline void DrawTxt(ImDrawList* d, ImFont* f, float sz, ImVec2 p, ImU32 c, ImU32 sc, const char* t) { d->AddText(f,sz,p+ImVec2(1.5f,1.5f),sc,t); d->AddText(f,sz,p,c,t); } // Extremely compact UI Overlay builder bool BeginOverlay(const char* id, float* uiPos, float w, float h, bool* open, bool scl=true) { static std::unordered_map tA; tA[id]=ImLerp(tA[id], *open?1.f:0.f, 1.f-expf(-20.f*ImGui::GetIO().DeltaTime)); if(tA[id]<0.01f) return false; float a=tA[id]*cfg.glbAlpha; ImDrawList* d=ImGui::GetForegroundDrawList(); ImGuiIO& io=ImGui::GetIO(); float &x=uiPos[0], &y=uiPos[1], &s=uiPos[2]; static std::map tP; static std::map tS; if(!tP.count(id)){tP[id]={x,y};tS[id]=s;} static std::map dg, sg; static std::map dO, sO; if(!cfg.boardLocked){ ImVec2 pS(x+(w+20.f*g_autoSc)*s, y+h*0.5f*s), pC(x-20.f*g_autoSc*s, y+h*0.5f*s); if(ImGui::IsMouseClicked(0)){ if(ImLengthSqr(io.MousePos-pC)<400.f*g_autoSc) *open=false; else if(scl&&ImLengthSqr(io.MousePos-pS)<400.f*g_autoSc){sg[id]=true;sO[id]=io.MousePos-ImVec2(tP[id].x+(w+20.f*g_autoSc)*tS[id],tP[id].y+h*0.5f*tS[id]);} else if(ImRect(x,y,x+w*s,y+h*s).Contains(io.MousePos)){dg[id]=true;dO[id]=tP[id]-io.MousePos;} } if(sg[id]){if(ImGui::IsMouseDown(0))tS[id]=std::clamp(((io.MousePos-sO[id]).x-tP[id].x)/(w+20.f*g_autoSc),0.1f,5.f); else sg[id]=false;} if(dg[id]&&!sg[id]){if(ImGui::IsMouseDown(0))tP[id]=io.MousePos+dO[id]; else dg[id]=false;} d->AddCircleFilled(pS, 10.f*g_autoSc, IM_COL32(255,215,0,240)); d->AddCircleFilled(pC, 13.f*g_autoSc, IM_COL32(200,50,50,200)); // Simple handles } float sm=1.f-expf(-20.f*io.DeltaTime); x=ImLerp(x,tP[id].x,sm); y=ImLerp(y,tP[id].y,sm); s=ImLerp(s,tS[id],sm); ImRect bg(x,y,x+w*s,y+h*s); d->AddRectFilled(bg.Min, bg.Max, IM_COL32(20,25,30,(int)(220*a)), h*0.5f*s); d->AddRect(bg.Min, bg.Max, IM_COL32(80,85,95,(int)(200*a)), h*0.5f*s, 0, 2.f*g_autoSc*s); return true; } void DrawESP() { auto s=GetSnap(); if(!s) return; ImDrawList* d=ImGui::GetForegroundDrawList(); ImFont* f=g_fntM?g_fntM:ImGui::GetFont(); if(BeginOverlay("AutoWin", cfg.ui[1], 260.f*g_autoSc, 60.f*g_autoSc, &cfg.showAuto)){ // Draw buttons using pure ImDrawList to save space ImVec2 p=ImVec2(cfg.ui[1][0]+20*g_autoSc, cfg.ui[1][1]+10*g_autoSc); d->AddRectFilled(p, p+ImVec2(100*g_autoSc, 40*g_autoSc), cfg.autoBuy?IM_COL32(0,200,100,200):IM_COL32(50,50,50,200), 20*g_autoSc); DrawTxt(d, f, 20.f*g_autoSc, p+ImVec2(20*g_autoSc,10*g_autoSc), IM_COL32_WHITE, 0, (const char*)u8"自动拿牌"); if(ImRect(p, p+ImVec2(100*g_autoSc,40*g_autoSc)).Contains(ImGui::GetIO().MousePos) && ImGui::IsMouseClicked(0)) cfg.autoBuy=!cfg.autoBuy; } // Lines if(cfg.drawLines && s->cam) { ImVec2 c(g_glW*0.5f, 0); auto dl=[&](const std::vector& hs){ for(auto& h:hs) if(h.sP.z>0.01f){ ImVec2 tp(h.sP.x, g_glH-h.sP.y+cfg.lineOffY*g_autoSc); d->AddLine(c,tp,IM_COL32(0,255,200,150),2.f); d->AddCircleFilled(tp,5.f,IM_COL32(0,255,200,255)); } }; dl(s->myHrs); dl(s->myBchHrs); } } void DrawMenuWin() { ImGui::SetNextWindowPos(ImVec2(cfg.mX, cfg.mY), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(cfg.mW, cfg.mH), ImGuiCond_FirstUseEver); if(ImGui::Begin((const char*)u8"JKChess Internal", NULL, ImGuiWindowFlags_NoSavedSettings)) { cfg.mX=ImGui::GetWindowPos().x; cfg.mY=ImGui::GetWindowPos().y; ImGui::Checkbox((const char*)u8"开启皮肤", &cfg.enSkin); ImGui::SameLine(); ImGui::Checkbox((const char*)u8"开启棋盘", &cfg.enMapSkin); ImGui::Checkbox((const char*)u8"显示自动拿牌悬浮", &cfg.showAuto); ImGui::Checkbox((const char*)u8"3D连线", &cfg.drawLines); ImGui::SliderFloat((const char*)u8"全局透明度", &cfg.glbAlpha, 0.1f, 1.0f); if(ImGui::Button((const char*)u8"保存配置", ImVec2(-1, 40*g_autoSc))) Save(); } ImGui::End(); } EGLBoolean (*old_egl)(EGLDisplay, EGLSurface) = nullptr; EGLBoolean hook_egl(EGLDisplay d, EGLSurface s) { eglQuerySurface(d, s, EGL_WIDTH, &g_glW); eglQuerySurface(d, s, EGL_HEIGHT, &g_glH); if(g_glW<=0||g_glH<=0) return old_egl(d,s); static bool in=false; if(!in){ ImGui::CreateContext(); ImGui_ImplOpenGL3_Init("#version 300 es"); UpdFnt(); in=true; } if(g_fntDirty){ UpdFnt(); g_fntDirty=false; } ImGuiIO& io=ImGui::GetIO(); io.DisplaySize=ImVec2(g_glW, g_glH); io.DeltaTime=1.f/60.f; ProcTex(); ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame(); DrawESP(); DrawMenuWin(); ImGui::Render(); glViewport(0,0,g_glW,g_glH); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); return old_egl(d,s); } void* InitT(void*) { BuildDex(); std::thread(TexDecWk).detach(); void* e=nullptr; while(!(e=DobbySymbolResolver("libEGL.so", "eglSwapBuffers"))) sleep(1); DobbyHook(e, (void*)hook_egl, (void**)&old_egl); // Bind logic hooks while(!g_il2cppB) { FILE* f=fopen("/proc/self/maps","r"); if(f){char l[512];while(fgets(l,512,f))if(strstr(l,"libil2cpp.so")&&strstr(l,"r-xp")){sscanf(l,"%lx",&g_il2cppB);break;}fclose(f);} sleep(1); } DobbyHook((void*)(g_il2cppB+0x46cce08), (void*)hook_46cce08, (void**)&orig_46cce08); DobbyHook((void*)(g_il2cppB+0x3fc3c70), (void*)hook_setEnd, (void**)&orig_setEnd); return nullptr; } __attribute__((constructor)) void Init() { pthread_t t; pthread_create(&t, 0, InitT, 0); pthread_detach(t); }