环境
- AquaMai: v1.9.8-ge80a59d
- 游戏: maimai DX 1.70(BUDDiES PLUS)
- MelonLoader: 0.6.4
- 连的是线上服,
GetUserDataApi 下发的 userData 里 charaSlot / charaLockSlot 长度不一致
现象
2026-09-19 14:01:41,玩家打完一局,GameOver 结束返回标题(AdvertiseProcess.OnStart)时崩溃,弹出 AquaMai Crash Handler:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Manager.UserDatas.UserDetail.Initialize () [0x00131] in <24f6a64f2eeb42d4b6f9ae17d637d569>:0
at Manager.UserData.Initialize () [0x0005e] in <24f6a64f2eeb42d4b6f9ae17d637d569>:0
at (wrapper dynamic-method) Process.AdvertiseProcess.DMD<Process.AdvertiseProcess::OnStart>(Process.AdvertiseProcess)
at Manager.ProcessManager.Update () [0x00032] in <24f6a64f2eeb42d4b6f9ae17d637d569>:0
同一档案 13:58:49 登录时有大量被 SanitizeUserData 修正的记录,说明该账号在服务器侧的数据本身就不完整:
[13:58:49] [SanitizeUserData] Set value of invalid int32 field iconId from 0 to 1
[13:58:49] [SanitizeUserData] Set value of invalid int32 field plateId from 0 to 1
[13:58:49] [SanitizeUserData] Set value of invalid int32 field titleId from 0 to 1
[13:58:49] [SanitizeUserData] Set value of invalid int32 field partnerId from 0 to 1
[13:58:49] [SanitizeUserData] Set value of invalid int32 field frameId from 0 to 1
[13:58:49] [SanitizeUserData] Set value of invalid int32 field selectMapId from 0 to 1
[13:58:51] [SanitizeUserData] Set value of invalid int32 field selectMusicId from null to 0
根因(反编译 Assembly-CSharp 确认)
Manager.UserDatas.UserDetail.Initialize()(无参重载,重置来宾状态)里:
for (int i = 0; i < this.CharaSlot.Length; i++)
{
this.CharaSlot[i] = 0;
this.CharaLockSlot[i] = 0; // IL_0133:按 CharaSlot 的长度写 CharaLockSlot
}
循环边界只取 CharaSlot.Length,循环体却同时写 CharaLockSlot[i]。而 Net.VO.Mai2.VOExtensions.Export() 把服务器返回的 charaSlot / charaLockSlot 原样拷入 UserDetail,没有任何长度校验。
SanitizeUserData.OnUserDataResponse 目前会把 charaSlot 无条件补齐/截断到 5 个,但没有同步处理 charaLockSlot。当服务器下发的 charaLockSlot 少于 5 个(或为空数组)时,两边就出现 5 vs N 的长度差:游戏内流程不会立刻出错,但一返回标题重置用户数据就越界崩溃。
建议修复
在 OnUserDataResponse 里处理 charaSlot 的同时,把 charaLockSlot 补齐/截断到相同长度,例如:
var charaLockSlot = GetArrayOrSetDefault(userData, "charaLockSlot");
while (charaLockSlot.Count < charaSlot.Count)
{
charaLockSlot.Add(new ProxyNumber(0));
}
userData["charaLockSlot"] = ToProxyArray(charaLockSlot.Take(charaSlot.Count));
临时规避
我先用一个 MelonLoader 小 mod 兜底(Harmony postfix UserDetail.set_CharaLockSlot + prefix UserDetail.Initialize,保证 CharaLockSlot.Length >= max(5, CharaSlot.Length)),加载后不再复现,退出与数据上传均正常。
完整崩溃日志(Errorlog/20260919140141.log)
Index was outside the bounds of the array.
ProcessManager Dump
Num Pri Name State
0 10 Process.CommonProcess Update
1 20 Process.GameOverProcess Released
2 20 Process.AdvertiseProcess Start
3 50 FadeProcess Update
4 51 Process.GenericProcess Update
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Manager.UserDatas.UserDetail.Initialize () [0x00131] in <24f6a64f2eeb42d4b6f9ae17d637d569>:0
at Manager.UserData.Initialize () [0x0005e] in <24f6a64f2eeb42d4b6f9ae17d637d569>:0
at (wrapper dynamic-method) Process.AdvertiseProcess.DMD<Process.AdvertiseProcess::OnStart>(Process.AdvertiseProcess)
at Manager.ProcessManager.Update () [0x00032] in <24f6a64f2eeb42d4b6f9ae17d637d569>:0
Monitor List
AdvertiseProcess(Clone)
AdvertiseProcess(Clone)
GameOverProcess(Clone)
GameOverProcess(Clone)
CommonProcess(Clone)
CommonProcess(Clone)
GenericProcess(Clone)
GenericProcess(Clone)
AdvertiseProcess
0总结算界面 prefab
Process
环境
GetUserDataApi下发的userData里charaSlot/charaLockSlot长度不一致现象
2026-09-19 14:01:41,玩家打完一局,GameOver 结束返回标题(AdvertiseProcess.OnStart)时崩溃,弹出 AquaMai Crash Handler:
同一档案 13:58:49 登录时有大量被 SanitizeUserData 修正的记录,说明该账号在服务器侧的数据本身就不完整:
根因(反编译 Assembly-CSharp 确认)
Manager.UserDatas.UserDetail.Initialize()(无参重载,重置来宾状态)里:循环边界只取
CharaSlot.Length,循环体却同时写CharaLockSlot[i]。而Net.VO.Mai2.VOExtensions.Export()把服务器返回的charaSlot/charaLockSlot原样拷入UserDetail,没有任何长度校验。SanitizeUserData.OnUserDataResponse目前会把charaSlot无条件补齐/截断到 5 个,但没有同步处理charaLockSlot。当服务器下发的charaLockSlot少于 5 个(或为空数组)时,两边就出现 5 vs N 的长度差:游戏内流程不会立刻出错,但一返回标题重置用户数据就越界崩溃。建议修复
在
OnUserDataResponse里处理charaSlot的同时,把charaLockSlot补齐/截断到相同长度,例如:临时规避
我先用一个 MelonLoader 小 mod 兜底(Harmony postfix
UserDetail.set_CharaLockSlot+ prefixUserDetail.Initialize,保证CharaLockSlot.Length >= max(5, CharaSlot.Length)),加载后不再复现,退出与数据上传均正常。完整崩溃日志(Errorlog/20260919140141.log)