孤儿分支,只含 docs/。内容包括: - 项目总览 / 主脚本编写指南 / 日志指南 - 上传成绩开发文档 / UpsertUserAll 踩坑清单(28 条) - 真机 Hook 对照报告 / 实跑验证记录 - 购买功能票流程(含被服务端拒绝的排查过程) · 扫码登录协议技术规范
5.2 KiB
5.2 KiB
实跑验证记录(真实发包 + 落库确认)
本文记录本工程第一次真实跑通「扫码登录 → 取数 → 上传成绩 → 落库回查 → 登出」的完整证据。 执行方式:
python upsert.py <二维码> --send(等价于下面的驱动方式)。
一、结论
| 环节 | 结果 |
|---|---|
| 扫码登录 | ✅ user_id=12345678,token 获取成功 |
| 用户预览 | ✅ errorId=0、banState=0、isLogin=False |
| 正式登录 | ✅ returnCode=1,loginId=7693236821794227665 |
| 抓基线快照 | ✅ 19 个节点全部成功,失败 0 个 |
| 组包 + 发包前自检 | ✅ 0 问题 |
| 冷却 | ✅ 等待 60.0 秒(模拟真机节奏) |
| 上传成绩 | ✅ returnCode=1 |
| 落库回查 | ✅ userData.playCount 1260 → 1261 |
| 登出 | ✅ returnCode=1 |
这是关键突破:之前的失败模式是「returnCode=1 但没落库」。 本次是回码成功 + 重新拉服务器数据确认数值真的变了,两者同时成立。
二、时间线(2026-10-06 01:28)
01:28:01 扫码登录成功 user_id=12345678
01:28:01 用户登录成功 loginId=7693236821794227665
loginDateTime=1791250081 dateTime=1791221281
01:28:03 结算快照抓取完成 成功 19 个节点,失败 0 个
01:28:04 角色快照取自服务器 395:3803 / 101:4458 / 400402:137 / 400401:137 / 200401:137
01:28:04 发包前自检通过
01:28:04 上传成绩冷却 等待 60.0 秒后再发送(模拟真机节奏)
01:29:04 冷却结束 共等待 60.0 秒
01:29:04 上传成功 returnCode=1
01:29:04 落库回查:
playCount 1260 -> 1261
currentPlayCount 188 -> 189
lastPlayDate 2026-10-05 22:32:21 -> 2026-10-06 01:28:04
musicId=143 level=4 playCount -> 11
01:29:05 【落库成功】userData.playCount 已 +1
01:29:05 用户登出成功 returnCode=1
三、落库证据(上传后重新拉服务器数据)
上传成功后不登出、立刻调 GetUserDataApi + GetUserMusicApi 回读,服务器返回:
{
"userData": {
"playCount": 1261,
"currentPlayCount": 189,
"lastPlayDate": "2026-10-06 01:28:04",
"lastLoginDate": "2026-10-06 01:28:01",
"eventWatchedDate": "2026-10-06 01:28:01",
"lastPlaceId": 0,
"point": 4460,
"charaSlot": [395, 101, 400402, 400401, 200401]
}
}
musicId=143 level=4 -> playCount = 11
对照上传前的基线:playCount=1260、currentPlayCount=188、(143,4).playCount=10。
三项全部 +1,证明服务端真的把这份报文写进去了。
同时确认:
point保持 4460 不变 —— 与「userGetPointList/userLoginBonusList留空」的预期一致lastLoginDate= 登录时刻(01:28:01),lastPlayDate= 上报时刻(01:28:04),两者分离正确charaSlot未被破坏
四、这次跑通依赖的关键实现点
number请求头:先跑Ping()取得往返毫秒,之后所有请求带上(本次 47 ms)- Cookie 复用:全程同一个
MaimaiNetClient,UserLoginApi的Set-Cookie: JSESSIONID自动带入后续请求 - userData 整表覆盖:先抓 19 节点快照作基线,再按本局演算 +1 后整表回传
- 差分节点只回传变化项:
userMusicDetailList只回传 (143,4) 那条、userMapList只回传 550003、userCharacterList只回传 5 只组队角色 - 11 条位串与数组长度严格对齐:
isNewFavoriteList="22212"等全部复刻真机 playSpecial用CalcSpecialNum=1024:与真机位模式一致characterLevelN用游玩前等级:playlog 3803/4458/137,userCharacterList 才是 3804/4459/138
五、复现方式
# 1) 预检(不发包,零副作用)
python upsert.py "<二维码>" --debug
# 2) 真实上传(★ 会把成绩写进服务器,不可撤销)
python upsert.py "<二维码>" --send
# 想跳过 60 秒冷却
python upsert.py "<二维码>" --send --cooldown 0
# 想跳过上传后的落库回查
python upsert.py "<二维码>" --send --no-verify
--send 会自动做落库回查:重新拉 GetUserDataApi + GetUserMusicApi,
对比 playCount 有没有 +1,并打印 【落库成功】 或 【疑似未落库】。
★ 建议先用
--debug跑一次预检:DEBUG 日志会完整打印请求头、请求体、响应体, 便于逐字段核对。代价是日志文件会很大(本次 DEBUG 日志约 200 万行)。
六、账号状态变化(本次真实写入的内容)
| 项 | 上传前 | 上传后 |
|---|---|---|
userData.playCount |
1260 | 1261 |
userData.currentPlayCount |
188 | 189 |
userData.lastPlayDate |
2026-10-05 22:32:21 | 2026-10-06 01:28:04 |
userMusicDetailList (143, Re:Master) playCount |
10 | 11 |
userMapList 550003 distance |
1457000 | 1468000(+11000) |
userCharacterList 5 只组队角色 |
3803/4458/137/137/137 | 3804/4459/138/138/138(+1) |
userData.point |
4460 | 4460(不变) |
写入的 userPlaylogList[0] 是 musicId=143(Re:Master)全 Miss 的失败局,
判定数 441/19/192/0/3,与 config.PLAY_* 一致。