回退混淆
This commit is contained in:
parent
2791d75490
commit
30d3d0999b
@ -0,0 +1,67 @@
|
||||
# 001 MemberCiv MemoryPack formatter 被混淆
|
||||
|
||||
- 代表 Issue:`b76a639f1ed68b9682abfadd03a1c69e`
|
||||
- 类型:`InvalidOperationException`
|
||||
- 当前版本次数:5119;同族合计:5200
|
||||
- 代表设备:`02-50-e2-57-ef-bc`
|
||||
- 代表样本:发生 `2026-05-29 19:44:27`,上报 `19:49:09`
|
||||
|
||||
## 现象
|
||||
|
||||
CrashSight 报:
|
||||
|
||||
```text
|
||||
Type implements IMemoryPackFormatterRegister but can not found RegisterFormatter. Type: fxl
|
||||
```
|
||||
|
||||
解混淆结果:
|
||||
|
||||
```text
|
||||
fxl = RuntimeData.MemberCiv
|
||||
RuntimeData.MemberCiv::RegisterFormatter() -> moz
|
||||
en.cpk = TH1_Logic.MatchConfig.MatchConfigManager.LoadMatchLevelData()
|
||||
RuntimeData.MapConfig.gvo = RuntimeData.MapConfig.CheckMapConfigChanged()
|
||||
```
|
||||
|
||||
## 前置链路
|
||||
|
||||
同设备最近上报显示,同一启动会话中先出现 `MemberCiv` formatter 注册失败,随后多个 Issue 被拆分上报:
|
||||
|
||||
- `8dc15e2856f92a990e26f50b07e1bd1f`:`EventManager Publish<UpdateUIOutsideMultiplayRoomSetting>` 包装的 `MemoryPackSerializationException`
|
||||
- `93317bed3bc828790e1be710e9fc7831` / `01b3ddf1405bd4bd47c2d3e5bc85747f`:同一个 `InvalidOperationException`
|
||||
- `b76a639f1ed68b9682abfadd03a1c69e`:最终高频刷出的 `InvalidOperationException`
|
||||
|
||||
最早业务入口在启动阶段:
|
||||
|
||||
```text
|
||||
Main.Start
|
||||
MatchConfigManager.Init
|
||||
MatchConfigManager.LoadMatchLevelData
|
||||
MemoryPackSerializer.Deserialize<MatchLevelData>
|
||||
MapConfig.Deserialize
|
||||
List<MemberCiv>.Deserialize
|
||||
MemberCiv RegisterFormatter missing
|
||||
```
|
||||
|
||||
之后在多人房间刷新阶段继续触发:
|
||||
|
||||
```text
|
||||
MapConfig.CheckMapConfigChanged
|
||||
MemoryPackSerializer.Serialize(MapConfig)
|
||||
List<MemberCiv>.Serialize
|
||||
MemberCiv RegisterFormatter missing
|
||||
```
|
||||
|
||||
## 源码位置
|
||||
|
||||
- `Unity/Assets/Scripts/TH1_Data/MapData.cs:905`:`MemberCiv`
|
||||
- `Unity/Assets/Scripts/TH1_Data/MapData.cs:921`:`RegisterFormatter`
|
||||
- `Unity/Assets/Scripts/TH1_Logic/MatchConfig/MatchConfigManager.cs:50`:`LoadMatchLevelData`
|
||||
- `Unity/Assets/Scripts/TH1_Data/MapData.cs:838`:`CheckMapConfigChanged`
|
||||
|
||||
## 根因
|
||||
|
||||
`MemberCiv` 使用 `[MemoryPackable(GenerateType.NoGenerate)]` 和手写 formatter。MemoryPack 运行时通过固定方法名 `RegisterFormatter` 注册 formatter,但 0.7.2 的 OPS 映射显示该方法被重命名为 `moz`。因此运行时找不到注册入口。
|
||||
|
||||
建议给 `MemberCiv` 或至少 `RegisterFormatter` 加混淆排除,并确认构建后 OPS 映射不再改名。
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
# 002 多人房间 UI 空引用链
|
||||
|
||||
- 代表 Issue:`d8a063f8bcbc06d36e8d722839a88bf1`
|
||||
- 同族 Issue:`17500e7928b92cb03088006333cb2436`, `4e0504e171679341e10b8508ed43e470`, `85a8a206d18e54098a20b278e8a97a32`, `35f02a6e9fbd5bdb156210cadd9f613b`, `632adc9d542a5b6ca862164dd8392df4`, `be87c0557f8597c99f803003fbd192c7`
|
||||
- 当前版本次数:72
|
||||
- 代表设备:`7c-10-c9-3e-f4-7a`
|
||||
|
||||
## 现象
|
||||
|
||||
空引用集中在多人房间:
|
||||
|
||||
```text
|
||||
UIOutsideMultiplayView.ChangeRoomSeatCount
|
||||
UIOutsideMultiplayView.ReconcileRoomMembers
|
||||
UIOutsideMultiplayView.SetMapConfig
|
||||
UIOutsideMultiplayView.SetRoomInfoMember
|
||||
UIOutsideMultiplayView.RefreshRoomInfo
|
||||
```
|
||||
|
||||
解混淆结果:
|
||||
|
||||
```text
|
||||
lxl = ChangeRoomSeatCount(int)
|
||||
lxt = ReconcileRoomMembers()
|
||||
lzd = SetMapConfig(bool)
|
||||
lze = OnGameModeOptionClickedInternal(...)
|
||||
bhw = SetRoomInfoMember()
|
||||
bhv = RefreshRoomInfo()
|
||||
```
|
||||
|
||||
## 前置链路
|
||||
|
||||
同设备最近上报显示,最近样本启动于 `2026-05-29 19:57:47`:
|
||||
|
||||
- `19:57:48`:先报 `地图数据反序列化失败,可能是版本不兼容: fxl is failed in provider at creating formatter.`
|
||||
- `19:58:37`:再报 `UIOutsideMultiplayView.ReconcileRoomMembers()` 空引用
|
||||
- `19:58:39`:用户点击席位变化后报 `ChangeRoomSeatCount(int)` 空引用
|
||||
|
||||
这说明 UI 空引用是 `MemberCiv` formatter 问题打坏初始 `MapConfig`/房间席位状态后的级联症状,不是首因。
|
||||
|
||||
## 源码位置
|
||||
|
||||
- `Unity/Assets/Scripts/TH1_Logic/Core/Main.cs:160`:`MapConfig = MapData.GetMatchConfig(); if null GetMatchConfig(2)`
|
||||
- `Unity/Assets/Scripts/TH1_Data/MapData.cs:2259`:本地 `match_config.dat` 反序列化失败后返回 null
|
||||
- `Unity/Assets/Scripts/TH1_UI/View/Outside/UIOutsideMultiplayView.cs:807`:`ReconcileRoomMembers`
|
||||
- `Unity/Assets/Scripts/TH1_UI/View/Outside/UIOutsideMultiplayView.cs:711`:`ChangeRoomSeatCount`
|
||||
- `Unity/Assets/Scripts/TH1_UI/View/Outside/UIOutsideMultiplayView.cs:1548`:`SetMapConfig`
|
||||
|
||||
## 建议
|
||||
|
||||
先修 `MemberCiv.RegisterFormatter` 混淆。随后给多人房间入口增加防御:`Main.Instance.MapConfig == null` 时不要进入房间设置刷新/席位变更,回退默认配置或显示初始化失败提示,避免根因残留时继续刷空引用。
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
# 003 Steamworks 未初始化仍刷新大厅
|
||||
|
||||
- 代表 Issue:`341f705a3c788ba90fbf37396a4c9470`
|
||||
- 同族 Issue:`4e05127a1634bef7000f599ad35388bf`, `93c9ce84e1edba72583b2e7607f7bf7b`
|
||||
- 当前版本次数:3
|
||||
- 当前版本影响设备:1
|
||||
- 代表设备:`84-a9-38-89-71-cc`
|
||||
|
||||
## 现象
|
||||
|
||||
0.7.2 只有 1 次直接 `InvalidOperationException`,另外 2 次是 UnityLogError 包装的同一异常:
|
||||
|
||||
```text
|
||||
Steamworks is not initialized.
|
||||
Steamworks.InteropHelp.TestIfAvailableClient
|
||||
SteamMatchmaking.AddRequestLobbyListDistanceFilter
|
||||
SteamLobbyManager.SearchPublicLobbies
|
||||
UIOutsideMultiplayView.OnRefreshLobbyClicked
|
||||
```
|
||||
|
||||
解混淆结果:
|
||||
|
||||
```text
|
||||
bag.jdo = SteamLobbyManager.SearchPublicLobbies(...)
|
||||
dio = UIOutsideMultiplayView.OnRefreshLobbyClicked()
|
||||
bei = UIOutsideMultiplayView.SetNoRoom()
|
||||
geh = UIOutsideMultiplayView.SetContent(ShowUIOutsideMultiplay)
|
||||
```
|
||||
|
||||
## 前置链路
|
||||
|
||||
同设备最近上报显示,同一启动会话:
|
||||
|
||||
- `19:26:44`:`ShowUIOutsideMultiplay` 打开联机界面时触发刷新大厅
|
||||
- `19:26:45`:离开房间/无房间状态又触发刷新大厅
|
||||
- `19:26:50`:直接记录 `Steamworks is not initialized`
|
||||
|
||||
这些都发生在运行 9 秒内,说明 Steam 初始化尚未完成或不可用时,UI 已经调用大厅搜索。
|
||||
|
||||
## 源码位置
|
||||
|
||||
- `Unity/Assets/Scripts/TH1_UI/View/Outside/UIOutsideMultiplayView.cs:1936`:`OnRefreshLobbyClicked` 直接 `_lobby.SearchPublicLobbies()`
|
||||
- `Unity/Assets/Scripts/TH1_UI/View/Outside/UIOutsideMultiplayView.cs:352`:其他路径已有 `_lobby.IsInitialized()` 防护
|
||||
- `Unity/Assets/Scripts/TH1_Logic/Steam/SteamLobbyManager.cs:1151`:`SearchPublicLobbies` 直接调用 Steam Matchmaking API
|
||||
|
||||
## 建议
|
||||
|
||||
在 `OnRefreshLobbyClicked` 和 `SearchPublicLobbies` 两层都加初始化保护:未初始化时不要调用 Steam Matchmaking,并通过现有联网提示/大厅提示反馈给 UI。这个问题和 `MemberCiv` 混淆无关,优先级低于 5200 次的主因。
|
||||
|
||||
28
MD/CrashSight_2026-05-29_0.7.2_1day/index.md
Normal file
28
MD/CrashSight_2026-05-29_0.7.2_1day/index.md
Normal file
@ -0,0 +1,28 @@
|
||||
# CrashSight 0.7.2 阻断报错分析
|
||||
|
||||
- 捕获时间:2026-05-29 20:20~20:30 UTC+8
|
||||
- 筛选范围:`0.7.2`,错误分析,ERROR,未处理/处理中,`start=0/10/20`
|
||||
- 列表总数:30 个 Issue,当前版本累计 5275 次
|
||||
- 分类:30 个 blocking,0 个纯 logerror
|
||||
- 原始抓取:`Temp/CrashSight/Daily_2026-05-29/errors_0.7.2_status0_2_ERROR.json`
|
||||
|
||||
## 结论
|
||||
|
||||
当前新版本的大量阻断并不是 30 个独立问题,主要是 3 个阻断家族。
|
||||
|
||||
| 家族 | Issue 数 | 当前版本次数 | 源头 |
|
||||
|---|---:|---:|---|
|
||||
| MemberCiv MemoryPack formatter 被混淆 | 20 | 5200 | `RuntimeData.MemberCiv::RegisterFormatter()` 被 OPS 混淆成 `moz`,MemoryPack 反射找不到固定方法名 |
|
||||
| 多人房间 UI 空引用 | 7 | 72 | 同设备前置先发生 `MapConfig`/`MemberCiv` 反序列化失败,导致 `Main.Instance.MapConfig`/房间席位状态异常后继续刷新 UI |
|
||||
| Steam 未初始化仍刷新大厅 | 3 | 3 | `UIOutsideMultiplayView.OnRefreshLobbyClicked()` 未判断 `_lobby.IsInitialized()`,直接调用 Steam Matchmaking |
|
||||
|
||||
## 最高优先级
|
||||
|
||||
先修 `MemberCiv` 的混淆保留。这个单点导致 `MatchLevelData` 和本地 `match_config.dat` 的 `MapConfig.MultiCivs` 反序列化失败,并级联出 20 个 MemoryPack Issue 与 7 个多人房间 UI 空引用。
|
||||
|
||||
## 报告
|
||||
|
||||
- [001 MemberCiv MemoryPack formatter](blocking/001_memberciv_memorypack_formatter.md)
|
||||
- [002 UIOutsideMultiplayView null chain](blocking/002_multiplay_ui_null_chain.md)
|
||||
- [003 Steamworks not initialized](blocking/003_steam_not_initialized.md)
|
||||
|
||||
6
MD/CrashSight_2026-05-29_0.7.2_1day/logerror_summary.md
Normal file
6
MD/CrashSight_2026-05-29_0.7.2_1day/logerror_summary.md
Normal file
@ -0,0 +1,6 @@
|
||||
# LogError Summary
|
||||
|
||||
当前筛选下 30 个 Issue 全部包含真实异常或被 `LogSystem.LogError` 包装的异常栈,因此本次没有纯诊断型 `logerror`。
|
||||
|
||||
同设备最近上报中看到的 `CompleteExecute Player 不一致`、`Wrong With FragmentCityConnectExpUp` 等属于另一个问题集合,不在当前 `0.7.2` ERROR 列表 30 条主集内,本次未展开归因。
|
||||
|
||||
33
MD/CrashSight_2026-05-29_0.7.2_1day/report_manifest.json
Normal file
33
MD/CrashSight_2026-05-29_0.7.2_1day/report_manifest.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"date": "2026-05-29",
|
||||
"filter": {
|
||||
"version": "0.7.2",
|
||||
"status": "0,2",
|
||||
"exceptionCategoryList": "ERROR",
|
||||
"starts": [0, 10, 20]
|
||||
},
|
||||
"totalIssues": 30,
|
||||
"blockingIssues": 30,
|
||||
"logerrorIssues": 0,
|
||||
"currentVersionOccurrences": 5275,
|
||||
"families": [
|
||||
{
|
||||
"id": "memberciv-memorypack-formatter",
|
||||
"issueCount": 20,
|
||||
"occurrences": 5200,
|
||||
"rootCause": "RuntimeData.MemberCiv::RegisterFormatter was obfuscated to moz, so MemoryPack could not find the required RegisterFormatter method by reflection."
|
||||
},
|
||||
{
|
||||
"id": "multiplay-ui-null-chain",
|
||||
"issueCount": 7,
|
||||
"occurrences": 72,
|
||||
"rootCause": "UIOutsideMultiplayView null references are preceded by MapConfig/MemberCiv MemoryPack failures in the same device sessions."
|
||||
},
|
||||
{
|
||||
"id": "steam-not-initialized",
|
||||
"issueCount": 3,
|
||||
"occurrences": 3,
|
||||
"rootCause": "Multiplayer UI refresh calls SearchPublicLobbies before Steamworks is initialized."
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -902,12 +902,9 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
|
||||
[MemoryPackable(GenerateType.NoGenerate)]
|
||||
public partial class MemberCiv : IMemoryPackable<MemberCiv>
|
||||
[MemoryPackable]
|
||||
public partial class MemberCiv
|
||||
{
|
||||
private const byte CurrentSerializedMemberCount = 9;
|
||||
private const byte LegacySerializedMemberCountWithoutTeam = 8;
|
||||
|
||||
public ulong MemberId;
|
||||
public uint PlayerId;
|
||||
public uint CivId;
|
||||
@ -917,87 +914,6 @@ namespace RuntimeData
|
||||
public int TeamId;
|
||||
public bool IsAI;
|
||||
public bool IsCivFixed;
|
||||
|
||||
public static void RegisterFormatter()
|
||||
{
|
||||
MemoryPackFormatterProvider.Register(new MemberCivFormatter());
|
||||
}
|
||||
|
||||
public static void Serialize(ref MemoryPackWriter writer, ref MemberCiv value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNullObjectHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteObjectHeader(CurrentSerializedMemberCount);
|
||||
writer.WriteUnmanaged(value.MemberId);
|
||||
writer.WriteUnmanaged(value.PlayerId);
|
||||
writer.WriteUnmanaged(value.CivId);
|
||||
writer.WriteUnmanaged(value.ForceId);
|
||||
writer.WriteUnmanaged(value.IsReady);
|
||||
writer.WriteUnmanaged(value.Index);
|
||||
writer.WriteUnmanaged(value.TeamId);
|
||||
writer.WriteUnmanaged(value.IsAI);
|
||||
writer.WriteUnmanaged(value.IsCivFixed);
|
||||
}
|
||||
|
||||
public static void Deserialize(ref MemoryPackReader reader, ref MemberCiv value)
|
||||
{
|
||||
if (!reader.TryReadObjectHeader(out var memberCount))
|
||||
{
|
||||
value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (memberCount != CurrentSerializedMemberCount
|
||||
&& memberCount != LegacySerializedMemberCountWithoutTeam)
|
||||
{
|
||||
MemoryPackSerializationException.ThrowInvalidPropertyCount(
|
||||
typeof(MemberCiv),
|
||||
CurrentSerializedMemberCount,
|
||||
memberCount);
|
||||
}
|
||||
|
||||
value ??= new MemberCiv();
|
||||
value.MemberId = reader.ReadUnmanaged<ulong>();
|
||||
value.PlayerId = reader.ReadUnmanaged<uint>();
|
||||
value.CivId = reader.ReadUnmanaged<uint>();
|
||||
value.ForceId = reader.ReadUnmanaged<uint>();
|
||||
value.IsReady = reader.ReadUnmanaged<bool>();
|
||||
value.Index = reader.ReadUnmanaged<int>();
|
||||
if (memberCount == LegacySerializedMemberCountWithoutTeam)
|
||||
{
|
||||
value.TeamId = GetLegacyDefaultTeamId(value.Index);
|
||||
value.IsAI = reader.ReadUnmanaged<bool>();
|
||||
value.IsCivFixed = reader.ReadUnmanaged<bool>();
|
||||
}
|
||||
else
|
||||
{
|
||||
value.TeamId = Math.Max(MapConfig.NoTeamId, reader.ReadUnmanaged<int>());
|
||||
value.IsAI = reader.ReadUnmanaged<bool>();
|
||||
value.IsCivFixed = reader.ReadUnmanaged<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetLegacyDefaultTeamId(int index)
|
||||
{
|
||||
return Math.Max(MapConfig.NoTeamId + 1, index + 1);
|
||||
}
|
||||
|
||||
private sealed class MemberCivFormatter : MemoryPackFormatter<MemberCiv>
|
||||
{
|
||||
public override void Serialize(ref MemoryPackWriter writer, ref MemberCiv value)
|
||||
{
|
||||
MemberCiv.Serialize(ref writer, ref value);
|
||||
}
|
||||
|
||||
public override void Deserialize(ref MemoryPackReader reader, ref MemberCiv value)
|
||||
{
|
||||
MemberCiv.Deserialize(ref reader, ref value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -159,6 +159,8 @@ namespace TH1_Logic.Core
|
||||
// 构造初始化 MapConfig
|
||||
MapConfig = MapData.GetMatchConfig();
|
||||
if (MapConfig == null) MapConfig = MatchConfigManager.Instance.GetMatchConfig(2);
|
||||
if (MapConfig == null) MapConfig = new MapConfig();
|
||||
|
||||
ConfirmMap = new PlayerConfirmMap();
|
||||
|
||||
// 模型暂时不需要
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user