feat(autotest): 按 zt 回调号自动应答 G.q1wd
- 解码到 LoadDependencies(zt) 后取 X,延迟 300ms 回 G.q1wd(X)(与真实抓包 c2s_0001 逐字节一致) - 大厅连接保持打开,避免 digest 会话被提前释放 - 实测:链路密钥唯一命中、zt 容器解码、G.q1wd 已被中继识别并转发
This commit is contained in:
1 parent
b2deca31be
commit
4ee63a78c9
1 file changed
+22
-19
@@ -19,7 +19,7 @@ import Net.Protocol.Entry
|
||||
import Net.Protocol.EntryEvent
|
||||
import Net.Protocol.S2cDecoder
|
||||
import Net.Protocol.SpaceFrame
|
||||
import Net.Protocol.XorCipher
|
||||
import Net.Protocol.ZtPayload
|
||||
|
||||
// ws 包的客户端(可自定义握手头;Node 内置 WebSocket 不能改 User-Agent)
|
||||
// 用 module.require 动态取构造器,避开 CommonJS/UMD 的 import 形态差异
|
||||
@@ -81,8 +81,7 @@ object AutoTest {
|
||||
var PendingDigest: ByteArray? = null
|
||||
var AssignedSpace: Long? = null
|
||||
var SpaceTarget = 0L
|
||||
var C2sCipher: XorCipher? = null
|
||||
var ObjectDataSent = false
|
||||
val PendingReplies = ArrayList<Int>()
|
||||
val SpaceAliases = HashMap<Int, Pair<Long, Long>>()
|
||||
|
||||
println("TankiOffline 自动测试:大厅=$LobbyUrl 空间=$SpaceUrl(请求空间 $WantSpace,超时 ${TimeoutMs}ms)")
|
||||
@@ -112,6 +111,12 @@ object AutoTest {
|
||||
println(" ⚠ methodId=${Rec.MethodId} 回编码不一致")
|
||||
}
|
||||
if (Rec.MethodId in Containers) S.Containers++
|
||||
// LoadDependencies(zt) 带回调号 X → 客户端必须回 G.q1wd(X),服务端才会继续下发 pt
|
||||
val V = Rec.Value
|
||||
if (Rec.MethodId == 3216143066888387731L && V is ZtPayload) {
|
||||
PendingReplies.add(V.X)
|
||||
println(" ↳ 排入自动应答 G.q1wd(X=${V.X})")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,17 +165,6 @@ object AutoTest {
|
||||
S.Messages++
|
||||
val Bytes = js("new Int8Array(Data)") as ByteArray
|
||||
val Bodies = Decoder.Feed(Bytes) { Line -> println(" $Line") }
|
||||
// 第一条空间帧到达(此时密钥已知)后再发 G.q1wd;太早发服务端会直接关连接。
|
||||
// 之后的上行必须用 c2s 方向的同一密钥(密钥表再 ^87)。
|
||||
val K = Decoder.Key
|
||||
if (IsSpace && !ObjectDataSent && K != null) {
|
||||
val C = XorCipher(K, true)
|
||||
C2sCipher = C
|
||||
val Req = C.Apply(Entry.BuildObjectDataRequest(SpaceTarget))
|
||||
SendBytes(Req)
|
||||
ObjectDataSent = true
|
||||
println("→ [空间] G.q1wd(1)(已加密,K=$K)")
|
||||
}
|
||||
for (B in Bodies) {
|
||||
S.Frames++
|
||||
if (IsSpace) {
|
||||
@@ -201,14 +195,23 @@ object AutoTest {
|
||||
}
|
||||
}
|
||||
if (Reconnect && PendingDigest != null) {
|
||||
println("→ 关闭大厅连接,改连空间服务器")
|
||||
try {
|
||||
Ws.close()
|
||||
} catch (_: Throwable) {
|
||||
}
|
||||
// 注意:**不要关大厅连接**。digest 与会话绑定,关掉大厅连接后再进空间,
|
||||
// 服务端只推首帧就会正常关闭(实测 code=1000)。让大厅连接闲置即可。
|
||||
println("→ 保持大厅连接,另开空间连接")
|
||||
Open(SpaceUrl, true)
|
||||
}
|
||||
}
|
||||
// 本批空间帧解完后,把待回的回调号发出(c2s 方向实测全程明文,见抓包 c2s_0001..)
|
||||
// 真实抓包里 G.q1wd 在 s2c_0000 之后约 300ms 才发,这里给一点处理间隔
|
||||
if (IsSpace && PendingReplies.isNotEmpty()) {
|
||||
while (PendingReplies.isNotEmpty()) {
|
||||
val X = PendingReplies.removeAt(0)
|
||||
SetTimeout({
|
||||
SendBytes(Entry.BuildObjectDataRequest(SpaceTarget, X))
|
||||
println("→ [空间] G.q1wd($X)(明文)")
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val OnError: (dynamic, dynamic) -> Unit = { _, _ -> println("✗ WebSocket 错误($Url)") }
|
||||
|
||||
Reference in new issue
Block a user