fix: 解歌的 isNewItemList 按主键回读再算,不再一律发 1
排查「发 11820 解歌不显示」时发现两处问题: - applyItemListPatch 的 isNewItemList 一直硬写全 '1'(新增),从没读服务器 已有行。真机 BuildListData 是按 (itemKind, itemId) 比对快照给 0/1 的, 重复解锁一首已存在的歌时服务器按插入冲突丢行,表现就是上传成功但没生效。 这和角色/地图/万花筒三处的处理不一致,现补齐。 - 新增 TitleApiService.getUserItems/getUserItemKeys。GetUserItemApi 是按 itemKind 分页的,首次 nextIndex 要按 itemKind * 1e10 编码 (PacketGetUserItem.cs:19),发 0 只会拿到空页。 - 解锁上传后回读复查,把「服务器没存这行道具」与「存了但曲目池不给进」分开报。 - 待解锁列表含 10000~19999 的 DX 曲时提示:Master/Re:Master 不像老曲那样 白送(IsUnlockMaster 里 id<10000 直接放过),必须显式带 itemKind 6/7。 需要说明:一首歌进不进选曲池由 NotesListManager.cs:70 决定 (IsOpenEvent(eventName) && !IsGameNgMusicId),事件窗口来自 GetGameEventApi、 曲目本体来自机台 Music.xml。11820 若卡在这一层,任何用户包都改不动, 复查那一步就是为了把这种情况和包的问题区分开。 README 补 isNew*List 语义、曲目可见性链路与 DX 段解锁规则三条说明。 删除因此不再被引用的 unlockMusicSuccess。
This commit is contained in:
1 parent
6438fb2171
commit
80df51c239
6 files changed
+213
-4
No files matched your search
@@ -530,6 +530,62 @@ class TitleApiService {
|
||||
);
|
||||
return UserKaleidxScopeBean.listFromResponse(json);
|
||||
}
|
||||
|
||||
/// 某一类道具的持有情况,对应 UserItemResponseVO。
|
||||
///
|
||||
/// `GetUserItemApi` 是**按 itemKind 分页**的:客户端
|
||||
/// `PacketGetUserItem.cs:19` 首次请求把 `nextIndex` 塞成
|
||||
/// `itemKind * 10000000000`(`ConstParameter.ItemKindConvert = 1e10`),
|
||||
/// 之后拿响应里的 `nextIndex` 续拉,直到它为 0。
|
||||
/// 直接发 `nextIndex: 0` 只会拿到空页,所以要照这个编码来。
|
||||
Future<List<Map<String, dynamic>>> getUserItems(
|
||||
int userId,
|
||||
int itemKind,
|
||||
) async {
|
||||
const apiName = 'GetUserItemApi';
|
||||
final all = <Map<String, dynamic>>[];
|
||||
var nextIndex = itemKind * 10000000000;
|
||||
var pages = 0;
|
||||
|
||||
do {
|
||||
final json = await _callApi(apiName, {
|
||||
'userId': userId,
|
||||
'nextIndex': nextIndex,
|
||||
}, userId);
|
||||
|
||||
final list = json['userItemList'];
|
||||
if (list is List) {
|
||||
all.addAll(list.whereType<Map<String, dynamic>>());
|
||||
}
|
||||
nextIndex = (json['nextIndex'] as num?)?.toInt() ?? 0;
|
||||
pages++;
|
||||
} while (nextIndex != 0 && pages < 40);
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
/// 一次读多个 itemKind,返回 `'kind:itemId'` 的键集合。
|
||||
///
|
||||
/// 用于给 `isNewItemList` 判每一位是 '1'(服务器没有这行、插入)
|
||||
/// 还是 '0'(已有、更新)——`VOExtensions.BuildListData:274` 的
|
||||
/// userItemList 主键是 (itemKind, itemId) 二元组。
|
||||
Future<Set<String>> getUserItemKeys(
|
||||
int userId,
|
||||
Iterable<int> itemKinds,
|
||||
) async {
|
||||
final keys = <String>{};
|
||||
await Future.wait([
|
||||
for (final kind in itemKinds.toSet())
|
||||
getUserItems(userId, kind).then((rows) {
|
||||
for (final row in rows) {
|
||||
final id = (row['itemId'] as num?)?.toInt();
|
||||
if (id == null) continue;
|
||||
keys.add('$kind:$id');
|
||||
}
|
||||
}),
|
||||
]);
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
class _RandomHelper {
|
||||
|
||||
Reference in new issue
Block a user