diag_npc_flow.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. # -*- coding: utf-8 -*-
  2. """diag_npc_flow.py —— 等待图 NPC 交互全链路诊断(带原始帧落盘)。
  3. 目标: 弄清 zone19 等待图 CS1010 为何静默。抓:
  4. 1. 进世界后所有收帧号时序(找 SC55 任务推送)
  5. 2. NPC 的 SC10 原始帧头+body(recog/p1/p2/p3 全量)
  6. 3. 走近 NPC 后 CS1010 index 候选逐一试探, 记录每个的响应帧
  7. """
  8. import json
  9. import os
  10. import sys
  11. import time
  12. HERE = __file__.rsplit("/", 1)[0]
  13. sys.path.insert(0, HERE)
  14. import requests as rq
  15. import urllib3
  16. urllib3.disable_warnings()
  17. import login_996pc as L
  18. import cq2_pure_enter as P
  19. from combat_bot import enter_game_gate_v2, send_init_frames, lo16, hi16, log
  20. from quest_bot3 import PushBot
  21. from encode6bitbuf_final import decode6
  22. ZONE = 14504561
  23. LOG_PATH = "/tmp/zone19_npc_diag.jsonl"
  24. out = open(LOG_PATH, "w", encoding="utf-8")
  25. def jdump(tag, **kw):
  26. rec = {"t": round(time.time(), 2), "tag": tag, **kw}
  27. out.write(json.dumps(rec, ensure_ascii=False) + "\n")
  28. out.flush()
  29. def main():
  30. name = sys.argv[1] if len(sys.argv) > 1 else None
  31. s = rq.Session()
  32. j, _ = L.do_login(s, "longwu988", "Longwu1988")
  33. assert j.get("code") == 200, j.get("msg")
  34. jwt = j["data"]["token"]
  35. uid = str(j["data"]["userInfo"]["id"])
  36. jdump("login", uid=uid)
  37. P.enter_game(s, jwt, ZONE)
  38. got = None
  39. for pt in (8041, 8021, 8061, 8001):
  40. try:
  41. r = P.login_gate(ZONE, jwt, name or "__probe__", pt, uid)
  42. if r[0]:
  43. got = r
  44. break
  45. except SystemExit as e:
  46. log(f" 端口{pt}: {e}")
  47. except Exception as e:
  48. log(f" 端口{pt}: {str(e)[:60]}")
  49. assert got, "登录服失败"
  50. key32, sid, rname, tkey, gp = got
  51. jdump("gate", role=rname, port=gp)
  52. g = enter_game_gate_v2(ZONE, rname, tkey, sid, gp, uid)
  53. bot = PushBot(g, sid, rname)
  54. P.heartbeat_loop(g, sid, bot.lock)
  55. # 收帧钩子: 全帧时序落盘
  56. orig_dispatch = bot._dispatch
  57. def dispatch_trace(mid, recog, p1, p2, p3, body):
  58. jdump("sc", mid=mid, recog=recog, p1=p1, p2=p2, p3=p3,
  59. blen=len(body), body_head=body[:60].decode("utf-8", "replace"))
  60. return orig_dispatch(mid, recog, p1, p2, p3, body)
  61. bot._dispatch = dispatch_trace
  62. t0 = time.time()
  63. while time.time() - t0 < 12:
  64. bot.pump(0.3)
  65. if 658 in bot.frame_log:
  66. break
  67. jdump("world", sc658=658 in bot.frame_log, frames=bot.frame_log)
  68. send_init_frames(bot, uid)
  69. for _ in range(20):
  70. bot.pump(0.5)
  71. if bot.me["id"] and bot.me.get("mapname"):
  72. break
  73. jdump("born", map=bot.me.get("mapname"), x=bot.me["x"], y=bot.me["y"],
  74. uid=bot.me.get("uid"), frames_after_init=dict(bot.frame_log))
  75. # 等任务推送 8s
  76. t0 = time.time()
  77. while time.time() - t0 < 8:
  78. bot.pump(0.3)
  79. bot.tick_step_ack()
  80. jdump("missions", missions=bot.missions, frame_log=dict(bot.frame_log))
  81. # NPC 原始数据
  82. for k, n in bot.npcs.items():
  83. jdump("npc", key=k, aid=n["aid"], name=n["name"], index=n["index"],
  84. x=n["x"], y=n["y"])
  85. # 走向 NPC (最多 40s)
  86. npc = bot.find_guide_npc()
  87. if npc:
  88. t_end = time.time() + 40
  89. while time.time() < t_end and bot.alive:
  90. bot.pump(0.1)
  91. bot.tick_step_ack()
  92. _, arrived = bot.walk_step_toward(npc["x"], npc["y"], run=False)
  93. if arrived:
  94. break
  95. time.sleep(max(0.0, 0.547 - (time.time() - bot._last_step_t)))
  96. jdump("walk_done", x=bot.me["x"], y=bot.me["y"],
  97. npc_xy=(npc["x"], npc["y"]))
  98. # CS1010 候选逐一试探(带间隔, 记录响应)
  99. aid = npc["aid"] if npc else None
  100. for idx in (npc["index"] if npc else 35, lo16(0), 35, 34, 0):
  101. if idx is None:
  102. continue
  103. before = dict(bot.frame_log)
  104. bot.send(1010, 0, 0, 0, bot.sid, json.dumps(
  105. {"UserID": aid, "index": idx}, separators=(",", ":")).encode())
  106. t0 = time.time()
  107. talk = None
  108. tele = bot.teleports
  109. while time.time() - t0 < 6:
  110. evs = bot.pump(0.3)
  111. bot.tick_step_ack()
  112. talk = next((e[1] for e in evs if e[0] == "npc_talk"), None) or talk
  113. if talk or bot.teleports > tele:
  114. break
  115. jdump("try1010", index=idx, talk=bool(talk),
  116. talk_body=(talk or {}).get("sMsg", "")[:300] if talk else None,
  117. teleported=bot.teleports > tele,
  118. new_frames={k: v for k, v in bot.frame_log.items()
  119. if k not in before or before[k] != v})
  120. if talk:
  121. acts = bot.parse_sui_acts(talk.get("sMsg", ""))
  122. jdump("acts", acts=acts)
  123. break
  124. time.sleep(1.0)
  125. jdump("end", map=bot.me.get("mapname"), frames=dict(bot.frame_log))
  126. g.close()
  127. log(f"诊断完成 → {LOG_PATH}")
  128. if __name__ == "__main__":
  129. main()