| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- """Precise launch: find the ready_start button's REAL clickable sub-element
- (the '启动' text node inside it), verify game context, click, and watch the
- Electron ipc 'openApp' via CDP console + process spawn.
- """
- import asyncio
- import base64
- import json
- import subprocess
- import time
- import httpx
- import websockets
- async def main():
- async with httpx.AsyncClient(timeout=5) as c:
- r = await c.get("http://127.0.0.1:9222/json/list")
- det = next((t for t in r.json() if "gameDetail" in t.get("url", "")), None)
- if not det:
- print("no gameDetail target")
- return 1
- async with websockets.connect(det["webSocketDebuggerUrl"], max_size=10**7) as ws:
- mid = 0
- async def ev(expr, wait=True):
- nonlocal mid
- mid += 1
- await ws.send(json.dumps({"id": mid, "method": "Runtime.evaluate",
- "params": {"expression": expr, "returnByValue": True}}))
- if not wait:
- return None
- while True:
- m = json.loads(await ws.recv())
- if m.get("id") == mid:
- return m.get("result", {}).get("result", {}).get("value")
- async def click(x, y):
- nonlocal mid
- mid += 1
- await ws.send(json.dumps({"id": mid, "method": "Input.dispatchMouseEvent",
- "params": {"type": "mousePressed", "x": x, "y": y, "button": "left", "clickCount": 1, "buttons": 1}}))
- await asyncio.sleep(0.07)
- mid += 1
- await ws.send(json.dumps({"id": mid, "method": "Input.dispatchMouseEvent",
- "params": {"type": "mouseReleased", "x": x, "y": y, "button": "left", "clickCount": 1, "buttons": 0}}))
- # drain
- while True:
- m = json.loads(await ws.recv())
- if m.get("id") == mid:
- return
- # 1. Full anatomy of ready_start and its children
- anatomy = await ev(r"""
- (function() {
- const btn = document.querySelector('.ready_start');
- if (!btn) return JSON.stringify({found: false});
- const r = btn.getBoundingClientRect();
- const kids = [];
- btn.querySelectorAll('*').forEach(k => {
- const kr = k.getBoundingClientRect();
- if (kr.width > 20) {
- kids.push({
- tag: k.tagName,
- cls: (k.className || '').toString().slice(0, 35),
- text: (k.innerText || '').trim().slice(0, 20),
- x: Math.round(kr.x + kr.width/2), y: Math.round(kr.y + kr.height/2),
- w: Math.round(kr.width), h: Math.round(kr.height)
- });
- }
- });
- // also check Vue handlers
- const vueKeys = Object.keys(btn).filter(k => k.startsWith('__vue') || k.startsWith('onclick') || k.includes('click'));
- return JSON.stringify({
- found: true,
- rect: {x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height)},
- cx: Math.round(r.x + r.width/2), cy: Math.round(r.y + r.height/2),
- fullText: (btn.innerText || '').replace(/\n/g, ' | ').slice(0, 80),
- kids: kids.slice(0, 12),
- handlers: vueKeys.slice(0, 5)
- }, null, 1);
- })()
- """)
- print("=== ready_start anatomy ===")
- print(anatomy)
- # 2. Hook the window.raw IPC bridge to observe openApp calls
- await ev(r"""
- (function() {
- if (window.__hookInstalled) return 'already';
- window.__hookInstalled = true;
- window.__ipcCalls = [];
- const raw = window.raw;
- if (raw && raw.openApp) {
- const orig = raw.openApp.bind(raw);
- raw.openApp = function(...args) {
- window.__ipcCalls.push({fn: 'openApp', args: JSON.stringify(args).slice(0, 200), t: Date.now()});
- return orig(...args);
- };
- return 'hooked window.raw.openApp';
- }
- return 'window.raw not found — hooks may differ';
- })()
- """)
- hook = await ev("window.__hookInstalled ? (window.__ipcCalls ? 'hook ready' : '?') : 'no'")
- print(f"\nIPC hook: {hook}")
- # 3. Click the CENTER of the button (or its main text child)
- a = json.loads(anatomy or "{}")
- if not a.get("found"):
- print("button not found!")
- return 1
- # prefer a child whose text contains 启动 or 上一次 — else button center
- target = None
- for k in a.get("kids", []):
- if "启动" in k["text"] or "上一次" in k["text"]:
- target = k
- break
- if not target:
- target = {"x": a["cx"], "y": a["cy"], "text": "(center)"}
- print(f"\nclicking child: '{target['text']}' @ ({target['x']},{target['y']})")
- await click(target["x"], target["y"])
- await asyncio.sleep(3)
- # 4. Did the IPC fire? Did anything change?
- calls = await ev("JSON.stringify(window.__ipcCalls || [])")
- print(f"\nopenApp IPC calls after click: {calls}")
- # 5. Fallback: call openApp DIRECTLY via the bridge (exactly what 启动 does)
- direct = await ev(r"""
- (function() {
- const raw = window.raw;
- if (!raw) return 'no raw bridge';
- // the game page knows the game id; find it in state
- const gid = 206923;
- const url = 'https://h5qfdt.996box.com/';
- if (raw.openApp) {
- const p = raw.openApp('cq', url);
- return 'direct openApp fired: cq + ' + url;
- }
- return 'raw.openApp missing';
- })()
- """)
- print(f"direct openApp: {direct}")
- # 6. monitor processes + traffic
- print("\n=== monitoring 180s ===")
- t0 = time.time()
- while time.time() - t0 < 180:
- await asyncio.sleep(5)
- el = int(time.time() - t0)
- try:
- out = subprocess.run(
- ["powershell", "-NoProfile", "-Command",
- "$p=(Get-Process | Where-Object {$_.Name -match '^cq'} | ForEach-Object {$_.Name+':'+$_.Id}) -join ',';"
- "$g=(netstat -ano | Select-String ':12000' | Measure-Object).Count;"
- "$c=(Get-Content 'D:\\传奇\\cq2_sdk\\real_login.jsonl' -ErrorAction SilentlyContinue | Measure-Object).Count;"
- "$p+'|'+$g+'|'+$c"],
- capture_output=True, text=True, timeout=8)
- parts = out.stdout.strip().split("|")
- procs, gw, cap = parts[0], parts[1] if len(parts) > 1 else "0", parts[2] if len(parts) > 2 else "0"
- except Exception:
- procs, gw, cap = "", "0", "0"
- flags = []
- if procs:
- flags.append(f"procs={procs}")
- if gw != "0":
- flags.append(f"gw={gw}")
- if cap != "0":
- flags.append(f"cap={cap}")
- print(f" t+{el:>3}s {' '.join(flags) or '...'}")
- if cap != "0" and int(cap) >= 2:
- print("\n*** TRAFFIC CAPTURED ***")
- await asyncio.sleep(20)
- return 0
- if procs and gw != "0" and el > 50:
- await asyncio.sleep(30)
- return 0
- return 1
- import sys
- sys.exit(asyncio.run(main()))
|