From ebd1fdddaad182ef740b22b0ce6800cb142917f6 Mon Sep 17 00:00:00 2001 From: chuxue Date: Fri, 25 Sep 2026 23:06:37 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20UpsertUserAll=20=E5=9B=A0=20playSpecial?= =?UTF-8?q?=20=E8=B6=8A=E7=95=8C=E8=A2=AB=E6=9C=8D=E5=8A=A1=E5=99=A8=20500?= =?UTF-8?q?=20=E6=8B=92=E7=BB=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit calcRandom() 移植的是 C# 里声明为 int 的 32 位比特反转,`<<=` 溢出按二进制 补码环绕,结果恒为合法 signed int32(高位被置起时为负)。Dart 的 int 是 64 位 且被反转值恒正,于是约一半概率产出 [2^31, 2^32) 的正数(如 3212134032),超出 UserGamePlaylog.playSpecial 的 int 声明,服务器整个 body 反序列化失败返回 HTTP 500,表现为解锁歌曲/获取收藏品不可用。按 C# 位模式重解释为 signed 32 位。 同时补上 userPlaylogList 缺少的 extBool3(UserPlaylog.cs:337 声明的 bool)。 --- lib/services/title_api_service.dart | 6 +++++- lib/services/user_all_payload_builder.dart | 1 + test/calc_random_test.dart | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 test/calc_random_test.dart diff --git a/lib/services/title_api_service.dart b/lib/services/title_api_service.dart index b2530bd..17fdc7b 100644 --- a/lib/services/title_api_service.dart +++ b/lib/services/title_api_service.dart @@ -222,7 +222,11 @@ class TitleApiService { num3 += n % 2; n >>= 1; } - return num3; + // 原版 num5 是 C# 的 int,`<<=` 溢出按二进制补码环绕,所以结果恒为合法的 + // signed int32(高位被置起时是负数)。Dart 的 int 是 64 位且 n 恒为正, + // 不重解释就会产出 >2^31 的正数,超出 UserGamePlaylog.playSpecial 的 int + // 声明,服务器反序列化失败直接返回 HTTP 500。 + return num3.toSigned(32); } String _normalizeUrl(String url) { diff --git a/lib/services/user_all_payload_builder.dart b/lib/services/user_all_payload_builder.dart index e673cc7..06ccf9b 100644 --- a/lib/services/user_all_payload_builder.dart +++ b/lib/services/user_all_payload_builder.dart @@ -260,6 +260,7 @@ class UserAllPayloadBuilder { 'extNum4': 0, 'extBool1': false, 'extBool2': false, + 'extBool3': false, }; for (var i = 0; i < 5; i++) { playlog['characterId${i + 1}'] = paddedCharaSlot[i]; diff --git a/test/calc_random_test.dart b/test/calc_random_test.dart new file mode 100644 index 0000000..1cb512f --- /dev/null +++ b/test/calc_random_test.dart @@ -0,0 +1,15 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:ichino/services/title_api_service.dart'; + +void main() { + // UserGamePlaylog.playSpecial 在客户端里声明为 int(int32)。越界会让服务器 + // 反序列化失败并返回 HTTP 500,而旧实现有约一半概率越界。 + test('calcRandom 恒在 int32 范围内', () { + const min = -2147483648; + const max = 2147483647; + for (var i = 0; i < 20000; i++) { + final v = TitleApiService.calcRandom(); + expect(v, inInclusiveRange(min, max), reason: '第 $i 次采样得到 $v'); + } + }); +}