组队窗"接受"按钮 是怎么找出来的 / 运行时自判定写法 热血江湖 YGOnline.exe · 2026-09-28 · 槽1256 / 左+952 右+960 ================================================================ 一、重要澄清:"左=接受"是推断,不是验证 ---------------------------------------------------------------- 组队窗的关键偏移是活体扫出来的(实打实): - 组队窗口槽 = 1256(0x4E8,InterParty) - 左按钮 = 窗口对象 + 952(0x3B8,坐标 85,178,18x60) - 右按钮 = 窗口对象 + 960(0x3C0,坐标 156,178,18x60) - 两个进程(pid 16060 / 2436)偏移和坐标一字不差 → 偏移"固定"成立 但"左=接受 / 右=拒绝"这个【语义】是我推的,不是验的: 交易窗和组队窗用的是同一套对话框模板(三个竖条按钮坐标都是 85/119/156,18x60), 交易窗左=確認(接受方向)、右=取消(拒绝方向),我【类推】组队窗也左接受右拒绝。 ⚠ 这个类推可能反:万一组队窗把按钮含义反过来排(左拒绝、右接受),代码就点反了。 结论:按钮上到底写"接受"还是"拒绝",光看偏移推断不出来,必须去读它实际显示的文字。 ================================================================ 二、按钮文字从哪来(已查证) ---------------------------------------------------------------- - 在 exe 里搜 接受/拒絕/確認/取消 的 Big5 明文 → 0 命中(exe 不含按钮文字)。 - 控件ID(按钮对象+0x0C)每次进程都变(6700/6703、7034/7037…),且 ≠ ybmsg 消息表序号 (查 [6700]=“比武台 就緒31”、[7034]=乱码,证明控件ID 不是消息序号)。 - 所以按钮文字是运行时从 ybmsg.cfg 加载、以【指针】形式挂在按钮对象里的, 正确做法是读按钮对象里"指向文字的指针",再比对文字内容。 ================================================================ 三、最准的一次性验证法:CE Lua 探针 ---------------------------------------------------------------- 让游戏弹出一个组队邀请,把下面这段贴进 CE 的 Lua Engine (Memory View → Tools → Lua Engine)运行,输出直接打出左/右按钮各自显示的文字。 local WORDS = { ["接受"]="\xB1\xB5\xA8\xFC", ["拒絕"]="\xA9\xDA\xB5\xB4", ["確認"]="\xBD\x54\xBB\x7B", ["確定"]="\xBD\x54\xA9\x77", ["取消"]="\xA8\xFA\xAE\xF8", ["同意"]="\xA6\x50\xB7\x4E", ["忽略"]="\xA9\xBF\xB2\xA4", ["關閉"]="\xC3\xF6\xB3\xAC", } local function readStr(a,n) local ok,t=pcall(readBytes,a,n) if not ok or type(t)~='table' then return '' end local s='' for i=1,#t do s=s..string.char(t[i]%256) end return s end local function contains(s,pat) return string.find(s,pat,1,true)~=nil end local IFM=readInteger(0x0188C61C) local w=readInteger(IFM+1256) if not w or w<65536 then print('组队窗未打开'); return end local L=readInteger(w+0x3B8); local R=readInteger(w+0x3C0) for _,info in ipairs({{'左(+0x3B8)',L},{'右(+0x3C0)',R}}) do local lbl,btn=info[1],info[2] print('\n### '..lbl..' 按钮对象='..tostring(btn)) if not btn or btn<65536 then print(' (空)'); goto skip end for off=0,0x300,4 do local p=readInteger(btn+off) if p and p>65536 and p<0x7F000000 then local s=readStr(p,48) for name,pat in pairs(WORDS) do if contains(s,pat) then print(' +0x'..string.format('%03X',off)..' -> '..name..' 原文='..s:sub(1,24)); break end end end end ::skip:: end 读出来哪边显示"接受/確認/同意/確定",哪边就是接受键。 这次实测结果应写进常量/记忆,以后不要再靠类推。 ================================================================ 四、推荐:让代码自己判定(运行时自判定,不靠假设) ---------------------------------------------------------------- 下面子程序当场读左/右两个按钮的文字、匹配接受类关键字,自动返回接受键的控件ID。 版本怎么平移、按钮怎么排,都不会点反。 .版本 2 .子程序 取组队接受按钮ID, 整数型, , 自动判定左/右哪个是"接受",返回它的控件ID;都读不到返回 0 .参数 窗口对象, 整数型 .局部变量 左, 整数型 .局部变量 右, 整数型 左 = 内存_读整数型 (全局_进程句柄, 窗口对象 + 952) 右 = 内存_读整数型 (全局_进程句柄, 窗口对象 + 960) .如果真 (左 ≤ 65536 或 右 ≤ 65536) 返回 (0) .如果真结束 .如果 (按钮文字是接受 (左)) 返回 (内存_读整数型 (全局_进程句柄, 左 + 12)) .否则如果 (按钮文字是拒绝 (左)) 返回 (内存_读整数型 (全局_进程句柄, 右 + 12)) .否则如果 (按钮文字是接受 (右)) 返回 (内存_读整数型 (全局_进程句柄, 右 + 12)) .否则 返回 (内存_读整数型 (全局_进程句柄, 左 + 12)) .如果结束 .子程序 按钮文字是接受, 逻辑型 .参数 按钮对象, 整数型 .局部变量 前4字节, 字节集 .局部变量 i, 整数型 .计次循环首 (192, i) 前4字节 = 取字节集左边 (内存_读字节集 (全局_进程句柄, 内存_读整数型 (全局_进程句柄, 按钮对象 + (i - 1) × 4), 4), 4) .如果真 (前4字节 = 机器码到字节集 (“B1B5A8FC”) 或 前4字节 = 机器码到字节集 (“BD54BB7B”) 或 前4字节 = 机器码到字节集 (“BD54A977”) 或 前4字节 = 机器码到字节集 (“A650B74E”)) 返回 (真) .如果真结束 .计次循环尾 () 返回 (假) .子程序 按钮文字是拒绝, 逻辑型 .参数 按钮对象, 整数型 .局部变量 前4字节, 字节集 .局部变量 i, 整数型 .计次循环首 (192, i) 前4字节 = 取字节集左边 (内存_读字节集 (全局_进程句柄, 内存_读整数型 (全局_进程句柄, 按钮对象 + (i - 1) × 4), 4), 4) .如果真 (前4字节 = 机器码到字节集 (“A9DAB5B4”) 或 前4字节 = 机器码到字节集 (“A8FAAEF8”) 或 前4字节 = 机器码到字节集 (“A9BFB2A4”) 或 前4字节 = 机器码到字节集 (“C3F6B3AC”)) 返回 (真) .如果真结束 .计次循环尾 () 返回 (假) (扫描的是按钮对象里【指向文字的指针】;Big5 接受类词:接受=B1B5A8FC、確認=BD54BB7B、確定=BD54A977、同意=A650B74E; 拒绝类词:拒絕=A9DAB5B4、取消=A8FAAEF8、忽略=A9BFB2A4、關閉=C3F6B3AC) ================================================================ 五、自动处理组队_带闸门(改用自判定,点接受不再靠假设) ---------------------------------------------------------------- .版本 2 .子程序 自动处理组队_带闸门 .局部变量 接口管理, 整数型 .局部变量 窗口对象, 整数型 .局部变量 接受ID, 整数型 接口管理 = 内存_读整数型 (全局_进程句柄, #IFManager基址) .如果真 (接口管理 ≤ 65536) 返回 () .如果真结束 .如果真 (全局_组队已处理 = 真) 返回 () .如果真结束 窗口对象 = 内存_读整数型 (全局_进程句柄, 接口管理 + #窗口槽位表.组队) .如果真 (窗口对象 ≤ 65536) 返回 () .如果真结束 .如果真 (内存_读整数型 (全局_进程句柄, 窗口对象 + 窗口面板偏移 (窗口对象)) + 64 ≠ 1) 返回 () .如果真结束 接受ID = 取组队接受按钮ID (窗口对象) .如果真 (接受ID ≤ 0) 返回 () .如果真结束 按钮点击call (接受ID) 全局_组队已处理 = 真 (窗口消失自动复位全局_组队已处理 的逻辑放主循环"窗口不存在"分支里,见自动处理组队_0928.txt)