diag_heal.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. # -*- coding: utf-8 -*-
  2. """
  3. diag_heal.py —— 诊断喝药开关: 登录 → 连入角色 → 发送多种命令 → 打印所有返回帧
  4. """
  5. import argparse, os, sys, socket, struct, time, threading, re
  6. import requests as rq
  7. import urllib3
  8. urllib3.disable_warnings()
  9. HERE = os.path.dirname(os.path.abspath(__file__))
  10. sys.path.insert(0, HERE)
  11. import login_996pc as L
  12. import cq2_pure_enter as P
  13. from combat_bot import enter_game_gate_v2, log
  14. from encode6bitbuf_final import encode6, decode6
  15. ZONE_19 = 14504561
  16. def send_action(sock, sid, act, index, tail, body_extra=""):
  17. body = ('{"index":%d,"act":"%s","subid":1}' % (index, act)).encode() if not body_extra else body_extra.encode()
  18. sock.sendall(encode6(struct.pack("<9i", 0, 3199, 0, 0, 0, sid, 0, len(body), tail)) + body)
  19. log(f" → 已发 CS3199: act={act!r} index={index} tail={tail}")
  20. def recv_all(sock, wait=4.0):
  21. """收 wait 秒内所有帧并打印。"""
  22. t0 = time.time()
  23. sock.settimeout(2.0)
  24. full = b""
  25. while time.time() - t0 < wait:
  26. try:
  27. d = sock.recv(65536)
  28. if not d: break
  29. full += d
  30. except (socket.timeout, OSError):
  31. continue
  32. # 解析
  33. pos = 0
  34. frames = []
  35. while pos + 48 <= len(full):
  36. try:
  37. h = struct.unpack("<9i", decode6(full[pos:pos+48]))
  38. except Exception:
  39. pos += 1; continue
  40. blen = h[7]
  41. if blen < 0 or blen > 200000 or pos + 48 + blen > len(full): break
  42. body = full[pos+48:pos+48+blen]
  43. frames.append((h[1], body[:200])) # (mid, body预览)
  44. pos += 48 + blen
  45. return frames
  46. def main():
  47. ap = argparse.ArgumentParser()
  48. ap.add_argument("-u", "--user", default="longwu988")
  49. ap.add_argument("-p", "--password", default="Longwu1988")
  50. ap.add_argument("--zone", type=int, default=ZONE_19)
  51. ap.add_argument("--name", default="萌新4567")
  52. args = ap.parse_args()
  53. log(f"[1] 登录 {args.user} ...")
  54. s = rq.Session()
  55. j, _ = L.do_login(s, args.user, args.password)
  56. if j.get("code") != 200: raise SystemExit("登录失败")
  57. jwt = j["data"]["token"]
  58. uid = j["data"]["userInfo"]["id"]
  59. log(f" uid={uid}")
  60. log(f"[2] EnterGameClient(zone={args.zone}) ...")
  61. P.enter_game(s, jwt, args.zone)
  62. log(f"[3] 登录服握手...")
  63. key32 = sid = tkey = game_port = None
  64. for pt in [8061, 8041, 8021, 8001]:
  65. try:
  66. key32, sid, rname, tkey, game_port = P.login_gate(args.zone, jwt, args.name, pt, uid)
  67. if key32:
  68. log(f" 端口={pt} 角色={rname} 游戏端口={game_port}")
  69. break
  70. except Exception:
  71. continue
  72. if not key32: raise SystemExit("登录失败")
  73. log(f"[4] 连游戏服 (v2)...")
  74. g = enter_game_gate_v2(args.zone, rname, tkey, sid, game_port, uid)
  75. P.heartbeat_loop(g, sid, threading.Lock())
  76. log(f"[5] 等 SC658 (世界初始化)...")
  77. t0 = time.time()
  78. while time.time() - t0 < 10:
  79. try:
  80. d = g.recv(65536)
  81. if not d: break
  82. if b"SC658" in d or any(b"\x9a\x02" in d for b in [d]): # 658 hex = 0x292
  83. pass
  84. # 简单判断: 0x9a02 在 p3 不对, 改为按消息号查
  85. pos = 0
  86. while pos + 48 <= len(d):
  87. try:
  88. h = struct.unpack("<9i", decode6(d[pos:pos+48]))
  89. except: break
  90. if h[1] == 658:
  91. log(f" SC658 ✓ ({time.time()-t0:.1f}s)")
  92. break
  93. blen = h[7]
  94. if blen < 0 or blen > 200000 or pos+48+blen > len(d): break
  95. pos += 48 + blen
  96. else:
  97. continue
  98. break
  99. except (socket.timeout, OSError): continue
  100. # 不严格等 SC658, 直接继续
  101. time.sleep(2)
  102. log(f"\n[6] 尝试开启喝药...")
  103. log(f" --- 第 1 步: 打开面板 ---")
  104. send_action(g, sid, "@openmianban,23", 109, 900)
  105. frames = recv_all(g, wait=3.0)
  106. log(f" 收到 {len(frames)} 帧")
  107. for mid, body in frames[:10]:
  108. body_short = body[:80]
  109. log(f" mid={mid} body={body_short}")
  110. log(f"\n --- 第 2 步: 查询喝药状态 ---")
  111. send_action(g, sid, "@chiyao_kaiqi", 303, 901)
  112. frames = recv_all(g, wait=3.0)
  113. log(f" 收到 {len(frames)} 帧")
  114. state_found = None
  115. for mid, body in frames:
  116. body_short = body[:200]
  117. log(f" mid={mid} body={body_short}")
  118. if b"yd_cy1" in body:
  119. m = re.search(rb"id=yd_cy1[^}]*?but_([01])\.png", body, re.S)
  120. if m:
  121. state_found = "on" if m.group(1) == b"1" else "off"
  122. log(f" ★ 喝药状态: {state_found}")
  123. if state_found is None:
  124. log(f" ⚠️ 未找到 yd_cy1 状态指示器")
  125. log(f"\n --- 第 3 步: 发送切换命令 (期望开启) ---")
  126. send_action(g, sid, "@chiyao_kaiqi", 303, 902)
  127. frames = recv_all(g, wait=3.0)
  128. log(f" 收到 {len(frames)} 帧")
  129. for mid, body in frames[:5]:
  130. body_short = body[:200]
  131. log(f" mid={mid} body={body_short}")
  132. log(f"\n --- 第 4 步: 再次查询状态 ---")
  133. send_action(g, sid, "@chiyao_kaiqi", 303, 901)
  134. frames = recv_all(g, wait=3.0)
  135. state_found = None
  136. for mid, body in frames:
  137. if b"yd_cy1" in body:
  138. m = re.search(rb"id=yd_cy1[^}]*?but_([01])\.png", body, re.S)
  139. if m:
  140. state_found = "on" if m.group(1) == b"1" else "off"
  141. log(f" ★ 喝药状态: {state_found}")
  142. if state_found is None:
  143. log(f" ⚠️ 仍未找到 yd_cy1 状态指示器")
  144. log("\n[完成] 诊断结束 (Ctrl+C 退出)")
  145. try:
  146. while True: time.sleep(60)
  147. except KeyboardInterrupt:
  148. pass
  149. if __name__ == "__main__":
  150. main()