# -*- coding: utf-8 -*- """diag_npc_flow.py —— 等待图 NPC 交互全链路诊断(带原始帧落盘)。 目标: 弄清 zone19 等待图 CS1010 为何静默。抓: 1. 进世界后所有收帧号时序(找 SC55 任务推送) 2. NPC 的 SC10 原始帧头+body(recog/p1/p2/p3 全量) 3. 走近 NPC 后 CS1010 index 候选逐一试探, 记录每个的响应帧 """ import json import os import sys import time HERE = __file__.rsplit("/", 1)[0] sys.path.insert(0, HERE) import requests as rq import urllib3 urllib3.disable_warnings() import login_996pc as L import cq2_pure_enter as P from combat_bot import enter_game_gate_v2, send_init_frames, lo16, hi16, log from quest_bot3 import PushBot from encode6bitbuf_final import decode6 ZONE = 14504561 LOG_PATH = "/tmp/zone19_npc_diag.jsonl" out = open(LOG_PATH, "w", encoding="utf-8") def jdump(tag, **kw): rec = {"t": round(time.time(), 2), "tag": tag, **kw} out.write(json.dumps(rec, ensure_ascii=False) + "\n") out.flush() def main(): name = sys.argv[1] if len(sys.argv) > 1 else None s = rq.Session() j, _ = L.do_login(s, "longwu988", "Longwu1988") assert j.get("code") == 200, j.get("msg") jwt = j["data"]["token"] uid = str(j["data"]["userInfo"]["id"]) jdump("login", uid=uid) P.enter_game(s, jwt, ZONE) got = None for pt in (8041, 8021, 8061, 8001): try: r = P.login_gate(ZONE, jwt, name or "__probe__", pt, uid) if r[0]: got = r break except SystemExit as e: log(f" 端口{pt}: {e}") except Exception as e: log(f" 端口{pt}: {str(e)[:60]}") assert got, "登录服失败" key32, sid, rname, tkey, gp = got jdump("gate", role=rname, port=gp) g = enter_game_gate_v2(ZONE, rname, tkey, sid, gp, uid) bot = PushBot(g, sid, rname) P.heartbeat_loop(g, sid, bot.lock) # 收帧钩子: 全帧时序落盘 orig_dispatch = bot._dispatch def dispatch_trace(mid, recog, p1, p2, p3, body): jdump("sc", mid=mid, recog=recog, p1=p1, p2=p2, p3=p3, blen=len(body), body_head=body[:60].decode("utf-8", "replace")) return orig_dispatch(mid, recog, p1, p2, p3, body) bot._dispatch = dispatch_trace t0 = time.time() while time.time() - t0 < 12: bot.pump(0.3) if 658 in bot.frame_log: break jdump("world", sc658=658 in bot.frame_log, frames=bot.frame_log) send_init_frames(bot, uid) for _ in range(20): bot.pump(0.5) if bot.me["id"] and bot.me.get("mapname"): break jdump("born", map=bot.me.get("mapname"), x=bot.me["x"], y=bot.me["y"], uid=bot.me.get("uid"), frames_after_init=dict(bot.frame_log)) # 等任务推送 8s t0 = time.time() while time.time() - t0 < 8: bot.pump(0.3) bot.tick_step_ack() jdump("missions", missions=bot.missions, frame_log=dict(bot.frame_log)) # NPC 原始数据 for k, n in bot.npcs.items(): jdump("npc", key=k, aid=n["aid"], name=n["name"], index=n["index"], x=n["x"], y=n["y"]) # 走向 NPC (最多 40s) npc = bot.find_guide_npc() if npc: t_end = time.time() + 40 while time.time() < t_end and bot.alive: bot.pump(0.1) bot.tick_step_ack() _, arrived = bot.walk_step_toward(npc["x"], npc["y"], run=False) if arrived: break time.sleep(max(0.0, 0.547 - (time.time() - bot._last_step_t))) jdump("walk_done", x=bot.me["x"], y=bot.me["y"], npc_xy=(npc["x"], npc["y"])) # CS1010 候选逐一试探(带间隔, 记录响应) aid = npc["aid"] if npc else None for idx in (npc["index"] if npc else 35, lo16(0), 35, 34, 0): if idx is None: continue before = dict(bot.frame_log) bot.send(1010, 0, 0, 0, bot.sid, json.dumps( {"UserID": aid, "index": idx}, separators=(",", ":")).encode()) t0 = time.time() talk = None tele = bot.teleports while time.time() - t0 < 6: evs = bot.pump(0.3) bot.tick_step_ack() talk = next((e[1] for e in evs if e[0] == "npc_talk"), None) or talk if talk or bot.teleports > tele: break jdump("try1010", index=idx, talk=bool(talk), talk_body=(talk or {}).get("sMsg", "")[:300] if talk else None, teleported=bot.teleports > tele, new_frames={k: v for k, v in bot.frame_log.items() if k not in before or before[k] != v}) if talk: acts = bot.parse_sui_acts(talk.get("sMsg", "")) jdump("acts", acts=acts) break time.sleep(1.0) jdump("end", map=bot.me.get("mapname"), frames=dict(bot.frame_log)) g.close() log(f"诊断完成 → {LOG_PATH}") if __name__ == "__main__": main()