匹配?
虽然电脑版 mc 好像不是开源的,但是手机版是(YGOMobile-cn-ko-en)。可以从源代码中发现匹配页面其实是一个网页 https://mycard.world/mobile/ygopro/lobby。
用 mitmproxy 抓了一下包。当点击“竞技匹配”的时候,实际上是发送了一条匹配请求:
1 | POST https://sapi.moecube.com:444/ygopro/match?arena=athletic&locale=zh-CN HTTP/2.0 |
当匹配成功时,返回 JSON 格式的 response:
1 | { |
取消匹配?
很有趣的是,在匹配过程中,即使点击“取消”,也不会发送任何请求。
这意味着,即使用户取消了匹配,其账号仍然在账号池等待匹配,在匹配成功后依然会收到 POST 请求的 response,只是客户端不对其进行处理,不加入房间。
这很好的解释了为什么经常会有排到人却发现对面不进房的情况,其实是对面点了取消。
那么,如果我点击多次“竞技匹配”,会发生什么呢?我进行了测试:
在前一次请求未返回的情况下再次请求,前一次请求会返回 409 错误,终止上一次匹配;
1 | HTTP/2.0 409 Conflict |
在已经匹配成功的情况下再次请求,如果没有进入上个房间,则重新进行匹配;
如果已经进入房间,则再次匹配会立即返回相同的密码。
娱乐匹配?
我曾经错点“娱乐匹配”后立即取消,再点击“竞技匹配”,结果匹配成功后,我进入了一个娱乐匹配房。
实际上,娱乐匹配和竞技匹配的请求方式类似:
1 | POST https://sapi.moecube.com:444/ygopro/match?arena=entertain&locale=zh-CN HTTP/2.0 |
但如果先进行一次娱乐匹配,再进行一次竞技匹配,这次竞技匹配并不会让未完成的娱乐匹配 409。
此时如果娱乐匹配先完成,也会让客户端直接进入房间。
算是一个 Bug 吧!
我应该点击取消吗?
由上可知,正常情况下,不应该点击“取消”。因为如果在点击“取消”后,重新点击“匹配”前匹配成功,那么又需要重新匹配一次,浪费时间,同时也会让你排到的人在房间里面浪费 30 秒。
但很多人会有这样的体感:匹配了很久都排不到,点取消重新排一下很快就进去了。
这就涉及另一个问题,就是 mc 对帐号进行匹配的逻辑是未知的。很难说主动触发 409,重新加入匹配池会对匹配结果产生怎样的影响。。。这个只有能看到那部分源代码的人才能知道了!
客户端怎么知道打完了?
注意到我们结束对战之后客户端会弹一个窗口显示对战结果。这个是怎么实现的呢?
通过抓包我也明白了其实现:当匹配页面获得焦点时,会发送以下两个请求:
1 | GET https://sapi.moecube.com:444/ygopro/arena/user HTTP/2.0 |
如果 history 的结果为 304,即没有新的记录,则说明还没有结束:
1 | HTTP/2.0 304 Not Modified |
否则用返回的内容生成对战结果。
user 的返回结果则不难推测,是用于更新显示的排位成绩的。