feat(session): 解析 Pt 容器为物品目录,未覆盖项从 30029 降到 2203
This commit is contained in:
1 parent
f29ad2caaa
commit
ee7504000f
4 files changed
+331
-2
No files matched your search
@@ -501,6 +501,24 @@
|
|||||||
(`ju`/`Su`/`Eu`/`Iu`,对应 `BuyableCC.buyable`/`currencyId`、`ItemCategoryCC.category` 等)
|
(`ju`/`Su`/`Eu`/`Iu`,对应 `BuyableCC.buyable`/`currencyId`、`ItemCategoryCC.category` 等)
|
||||||
是 module_85196 的内部函数、不导出,18334 也不直接读 CC 槽位,
|
是 module_85196 的内部函数、不导出,18334 也不直接读 CC 槽位,
|
||||||
说明转换经 DI 服务接口完成;下一步用别名表追该接口的实现方法。
|
说明转换经 DI 服务接口完成;下一步用别名表追该接口的实现方法。
|
||||||
|
- 物品目录(`App/Session/ItemCatalog.kt`):
|
||||||
|
- 结论修正:抓包里这 30029 条未覆盖 Pt 项**不是用户状态**,而是静态物品表
|
||||||
|
(1371 个物品对象 + 515 个装置对象),原包也不把它放进 Redux,而是由服务按需读取。
|
||||||
|
- 容器形态(`names/model_registry.json` + 抓包实测):`pt.Items` 按 `Id == 0` 的对象标记分组,
|
||||||
|
标记项的值就是 ObjectId;组内按 modelId 建索引。物品组通常是
|
||||||
|
`CountableItemCC, ItemPropertiesCC, ItemSaleByKitCC, BuyableCC, TimePeriodModelCC,
|
||||||
|
ItemModelCC, ItemRarityCC, DescriptionModelCC, ItemCategoryCC, PremiumItemCC,
|
||||||
|
ItemViewCategoryCC, DescriptionMediaCC, VisibleCC`;装置组换成
|
||||||
|
`DevicePropertiesCC + TemporaryItemCC`。
|
||||||
|
- `CC → GarageItemObject` / `GarageDeviceObject` 的字段顺序取自 module_18334 的
|
||||||
|
`S$`(物品)与 `gct`(装置)的构造函数实参,token → 模型类由跨模块别名表反查,逐条登记在文件头。
|
||||||
|
- `SessionRouter` 在 Pt 分支先调 `Catalog.Ingest`,被目录吸收的项不再计入未覆盖:
|
||||||
|
抓包实测 **物品 1399 / 装置 516 / 吸收 27826 项**,未覆盖从 30029 降到 2203
|
||||||
|
(余下主要是 methodId 级未覆盖、`0` 对象标记、以及 ResistancesCC/DurationCC 等非物品对象)。
|
||||||
|
自检同时断言目录非空,并打印名称样本(如 `史诗幸运礼盒`、`紧凑型油箱`)验证字段映射。
|
||||||
|
- 下一步:用户拥有的物品列表来自 GarageCC 的引用字段(`itemsOnDepot` / `itemsOnMarket` /
|
||||||
|
`mountedItems`)与模型命令流;等这部分抓包/命令解码补齐后,用目录把 id 解析成
|
||||||
|
`GarageItemObject` 再派发 `SetItemsOnDepot` / `SetItemsOnMarket` / `SetMountedItems`。
|
||||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||||
`launchParams` 是纯透传(`(pass-through)`,无 reducer),已把字段收口为 `Map<String, String>`。
|
`launchParams` 是纯透传(`(pass-through)`,无 reducer),已把字段收口为 `Map<String, String>`。
|
||||||
|
|||||||
@@ -0,0 +1,261 @@
|
|||||||
|
// ItemCatalog.kt —— 车库 / 商店物品目录(Pt 容器 → GarageItemObject / GarageDeviceObject)
|
||||||
|
//
|
||||||
|
// 为什么单列一个「目录」而不是 Redux 切片:
|
||||||
|
// · 抓包里最大的 Pt 容器是**静态物品表**(1371 个物品对象 + 515 个装置对象),
|
||||||
|
// 不是用户拥有的物品列表;原包也不把它放状态层,而是由服务按需读取。
|
||||||
|
// · 原包的「CC → GarageItemObject」转换在 module_18334 的 `S$`(物品)与 `gct`(装置)里,
|
||||||
|
// 逐个从对象上下文取子模型:`Gr(n, Z(token))`。token → 模型类的对应关系见下表的注释。
|
||||||
|
//
|
||||||
|
// 容器形态(names/model_registry.json + 抓包实测):
|
||||||
|
// Pt.Items = [0(对象标记,value 是 ObjectId), 模型1, 模型2, …, 0(下一个对象), …]
|
||||||
|
// 每个对象组里模型顺序不固定,按 modelId 建索引即可;组边界 = Id == 0 的项。
|
||||||
|
// 物品组的模型集合(实测):
|
||||||
|
// CountableItemCC, ItemPropertiesCC, ItemSaleByKitCC, BuyableCC,
|
||||||
|
// TimePeriodModelCC, ItemModelCC, ItemRarityCC, DescriptionModelCC,
|
||||||
|
// ItemCategoryCC, PremiumItemCC, ItemViewCategoryCC, DescriptionMediaCC, VisibleCC
|
||||||
|
// 装置组在前述集合上换成 DevicePropertiesCC + TemporaryItemCC。
|
||||||
|
//
|
||||||
|
// 字段对应(module_18334 的 `S$`,new GarageItemObject(...) 的实参顺序):
|
||||||
|
// id←对象标记 | description←DescriptionModelCC | item←ItemModelCC
|
||||||
|
// isPremium←PremiumItemCC.PremiumItem | itemCategory←ItemCategoryCC.Category
|
||||||
|
// itemViewCategory←ItemViewCategoryCC.Category | buyable←BuyableCC.Buyable
|
||||||
|
// availableForAll←AvailableForAllCC | discount←DiscountCC | timePeriod←TimePeriodModelCC
|
||||||
|
// modification←ModificationCC(baseItemId=Field1, level=ModificationIndex)
|
||||||
|
// properties←ItemPropertiesCC | devices←ItemDevicesCC | count←CountableItemCC.Field1
|
||||||
|
// kit←GarageKitCC | countable←CountableItemCC 是否存在 | mountIndex←调用点下标(目录里为 0)
|
||||||
|
// availableSkins←AvailableSkinsCC | availableShotSkins←AvailableShotSkinsCC
|
||||||
|
// mountedSkin←MountedSkinCC(834829861153964627) | mountedShotSkin←MountedSkinCC(905970599512839002)
|
||||||
|
// skinPreview←SkinPreviewCC | grouped←GroupedCC | rarity←ItemRarityCC.Rarity
|
||||||
|
// resistanceBackgroundImg←ResistanceBackgroundCC | visible←VisibleCC.Visible
|
||||||
|
// descriptionMedia←DescriptionMediaCC | saleByKitItems←ItemSaleByKitCC
|
||||||
|
// isSellingForCoin/Crystal/Ruby 在原包传 `Ct`(未提供),这里保持 null。
|
||||||
|
//
|
||||||
|
// 装置字段对应(`gct`,new GarageDeviceObject(...)):
|
||||||
|
// id←对象标记 | baseItemId←容器级 ModificationCC.Field1(组里没有则 0)
|
||||||
|
// temporaryItemCC←TemporaryItemCC | description←DescriptionModelCC | item←ItemModelCC
|
||||||
|
// isPremium←PremiumItemCC | itemCategory←ItemCategoryCC | itemViewCategory←ItemViewCategoryCC
|
||||||
|
// buyable←BuyableCC | discount←DiscountCC | timePeriod←TimePeriodModelCC
|
||||||
|
// deviceProperty←DevicePropertiesCC | rarity←ItemRarityCC | visible←VisibleCC
|
||||||
|
// descriptionMedia←DescriptionMediaCC
|
||||||
|
package App.Session
|
||||||
|
|
||||||
|
import App.State.GarageDeviceObject
|
||||||
|
import App.State.GarageItemModification
|
||||||
|
import App.State.GarageItemObject
|
||||||
|
import Net.Generated.AvailableForAllCC
|
||||||
|
import Net.Generated.AvailableShotSkinsCC
|
||||||
|
import Net.Generated.AvailableSkinsCC
|
||||||
|
import Net.Generated.BuyableCC
|
||||||
|
import Net.Generated.CountableItemCC
|
||||||
|
import Net.Generated.DescriptionMediaCC
|
||||||
|
import Net.Generated.DescriptionModelCC
|
||||||
|
import Net.Generated.DevicePropertiesCC
|
||||||
|
import Net.Generated.DiscountCC
|
||||||
|
import Net.Generated.GarageKitCC
|
||||||
|
import Net.Generated.GroupedCC
|
||||||
|
import Net.Generated.ItemCategoryCC
|
||||||
|
import Net.Generated.ItemDevicesCC
|
||||||
|
import Net.Generated.ItemModelCC
|
||||||
|
import Net.Generated.ItemPropertiesCC
|
||||||
|
import Net.Generated.ItemRarityCC
|
||||||
|
import Net.Generated.ItemSaleByKitCC
|
||||||
|
import Net.Generated.ItemViewCategoryCC
|
||||||
|
import Net.Generated.ModificationCC
|
||||||
|
import Net.Generated.MountedSkinCC
|
||||||
|
import Net.Generated.PremiumItemCC
|
||||||
|
import Net.Generated.ResistanceBackgroundCC
|
||||||
|
import Net.Generated.SkinPreviewCC
|
||||||
|
import Net.Generated.TemporaryItemCC
|
||||||
|
import Net.Generated.TimePeriodModelCC
|
||||||
|
import Net.Generated.VisibleCC
|
||||||
|
import Net.Protocol.PtPayload
|
||||||
|
|
||||||
|
/** 目录模型的 modelId(来源:names/model_registry.json)。 */
|
||||||
|
object CatalogModelIds {
|
||||||
|
const val CountableItem = 120961863156462946L
|
||||||
|
const val ItemProperties = 4245000165576407500L
|
||||||
|
const val ItemSaleByKit = 4309274349580876968L
|
||||||
|
const val Buyable = 2769268442698022653L
|
||||||
|
const val TimePeriod = 8032192927455575509L
|
||||||
|
const val ItemModel = 3438505192580052999L
|
||||||
|
const val ItemRarity = 658797348514407988L
|
||||||
|
const val DescriptionModel = 3935107155251354407L
|
||||||
|
const val ItemCategory = 2114179554921095892L
|
||||||
|
const val PremiumItem = 1139677084511624062L
|
||||||
|
const val ItemViewCategory = 6117306895090150422L
|
||||||
|
const val DescriptionMedia = 5952355564848177159L
|
||||||
|
const val Visible = 5738770490413536673L
|
||||||
|
|
||||||
|
const val AvailableForAll = 6589716392600418185L
|
||||||
|
const val Discount = 2951667042968033849L
|
||||||
|
const val Modification = 2494628067134376039L
|
||||||
|
const val UpgradeParams = 4743567393313674375L
|
||||||
|
const val ItemDevices = 7391892068905080676L
|
||||||
|
const val GarageKit = 5219530271535770658L
|
||||||
|
const val AvailableSkins = 5207857306014573244L
|
||||||
|
const val AvailableShotSkins = 1164458258646872337L
|
||||||
|
const val MountedSkin = 834829861153964627L
|
||||||
|
const val MountedShotSkin = 905970599512839002L
|
||||||
|
const val SkinPreview = 6680653332718076818L
|
||||||
|
const val Grouped = 1865478986390468300L
|
||||||
|
const val ResistanceBackground = 6628468327090974523L
|
||||||
|
|
||||||
|
const val DeviceProperties = 7640081207058999117L
|
||||||
|
const val TemporaryItem = 3893855999545616334L
|
||||||
|
|
||||||
|
/** 物品组只要出现其中任意一个模型,就按物品目录处理。 */
|
||||||
|
val ItemGroupMarkers: Set<Long> = setOf(
|
||||||
|
ItemModel, ItemCategory, Buyable, DescriptionModel, TimePeriod, ItemRarity,
|
||||||
|
PremiumItem, ItemViewCategory,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态物品目录:`Pt` 容器里按「对象」分组后,把 CC 组合成 `GarageItemObject` / `GarageDeviceObject`。
|
||||||
|
*
|
||||||
|
* 同一个 modelId 可能随对象重复出现(每个对象一份),所以目录以对象 id 为键。
|
||||||
|
*/
|
||||||
|
class ItemCatalog {
|
||||||
|
|
||||||
|
val Items: MutableMap<Long, GarageItemObject> = LinkedHashMap()
|
||||||
|
val Devices: MutableMap<Long, GarageDeviceObject> = LinkedHashMap()
|
||||||
|
|
||||||
|
/** 被识别并吸收的 Pt 项数。 */
|
||||||
|
var ConsumedItems: Int = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
/** 已识别的对象组数(物品 + 装置)。 */
|
||||||
|
var Groups: Int = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
/** 不是目录的对象组数(例如车库配置对象:PassToShopCC / TemperatureCC …)。 */
|
||||||
|
var SkippedGroups: Int = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
/** 组里既不是物品也不是装置的模型名,用于诊断未识别目录。 */
|
||||||
|
val SkippedModels: MutableMap<String, Int> = LinkedHashMap()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试吸收一个 Pt 容器。
|
||||||
|
*
|
||||||
|
* @return 与 `Payload.Items` 等长的「已吸收」标记;完全不是目录容器时返回 null。
|
||||||
|
*/
|
||||||
|
fun Ingest(Payload: PtPayload): BooleanArray? {
|
||||||
|
val Raw = Payload.Items
|
||||||
|
if (Raw.isEmpty()) return null
|
||||||
|
val Consumed = BooleanArray(Raw.size)
|
||||||
|
var Any = false
|
||||||
|
|
||||||
|
var Start = -1
|
||||||
|
fun Flush(Begin: Int, End: Int) {
|
||||||
|
if (Begin < 0) return
|
||||||
|
val Zero = Raw[Begin].Value as? Long
|
||||||
|
val Models = HashMap<Long, Any>(16)
|
||||||
|
var I = Begin + 1
|
||||||
|
while (I < End) {
|
||||||
|
val Id = Raw[I].Id
|
||||||
|
if (Id != 0L) Models[Id] = Raw[I].Value
|
||||||
|
I++
|
||||||
|
}
|
||||||
|
if (Models.isEmpty()) return
|
||||||
|
val ObjectId = Zero ?: 0L
|
||||||
|
val IsDevice = Models.containsKey(CatalogModelIds.DeviceProperties) ||
|
||||||
|
Models.containsKey(CatalogModelIds.TemporaryItem)
|
||||||
|
val IsItem = CatalogModelIds.ItemGroupMarkers.any { Models.containsKey(it) }
|
||||||
|
if (IsDevice) {
|
||||||
|
Devices[ObjectId] = MakeDevice(ObjectId, Models)
|
||||||
|
Mark(Consumed, Begin, End)
|
||||||
|
Groups++
|
||||||
|
Any = true
|
||||||
|
} else if (IsItem) {
|
||||||
|
Items[ObjectId] = MakeItem(ObjectId, Models)
|
||||||
|
Mark(Consumed, Begin, End)
|
||||||
|
Groups++
|
||||||
|
Any = true
|
||||||
|
} else {
|
||||||
|
SkippedGroups++
|
||||||
|
for (Name in Models.keys) {
|
||||||
|
val Text = App.State.ModelNamesByModelId[Name] ?: Name.toString()
|
||||||
|
SkippedModels[Text] = (SkippedModels[Text] ?: 0) + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (I in Raw.indices) {
|
||||||
|
if (Raw[I].Id != 0L) continue
|
||||||
|
if (Start >= 0) Flush(Start, I)
|
||||||
|
Start = I
|
||||||
|
}
|
||||||
|
if (Start >= 0) Flush(Start, Raw.size)
|
||||||
|
if (!Any) return null
|
||||||
|
ConsumedItems += Consumed.count { it }
|
||||||
|
return Consumed
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Mark(Consumed: BooleanArray, Start: Int, End: Int) {
|
||||||
|
for (I in Start until End) Consumed[I] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MakeItem(Id: Long, Models: Map<Long, Any>): GarageItemObject {
|
||||||
|
val Modification = Models[CatalogModelIds.Modification] as? ModificationCC
|
||||||
|
val Countable = Models[CatalogModelIds.CountableItem] as? CountableItemCC
|
||||||
|
return GarageItemObject(
|
||||||
|
id = Id,
|
||||||
|
description = Models[CatalogModelIds.DescriptionModel],
|
||||||
|
item = Models[CatalogModelIds.ItemModel],
|
||||||
|
isPremium = (Models[CatalogModelIds.PremiumItem] as? PremiumItemCC)?.PremiumItem ?: false,
|
||||||
|
itemCategory = (Models[CatalogModelIds.ItemCategory] as? ItemCategoryCC)?.Category ?: 0,
|
||||||
|
itemViewCategory = (Models[CatalogModelIds.ItemViewCategory] as? ItemViewCategoryCC)?.Category ?: 0,
|
||||||
|
buyable = (Models[CatalogModelIds.Buyable] as? BuyableCC)?.Buyable ?: false,
|
||||||
|
availableForAll = (Models[CatalogModelIds.AvailableForAll] as? AvailableForAllCC)?.AvailableForAll ?: false,
|
||||||
|
discount = Models[CatalogModelIds.Discount],
|
||||||
|
timePeriod = Models[CatalogModelIds.TimePeriod],
|
||||||
|
modification = Modification?.let {
|
||||||
|
GarageItemModification(vcf_1 = it.Field1, xcf_1 = it.ModificationIndex.toInt())
|
||||||
|
},
|
||||||
|
properties = Models[CatalogModelIds.ItemProperties],
|
||||||
|
upgradeableParams = null,
|
||||||
|
devices = Models[CatalogModelIds.ItemDevices],
|
||||||
|
count = Countable?.Field1 ?: 0,
|
||||||
|
kit = Models[CatalogModelIds.GarageKit] as? GarageKitCC,
|
||||||
|
countable = Countable != null,
|
||||||
|
mountIndex = 0,
|
||||||
|
availableSkins = Models[CatalogModelIds.AvailableSkins] as? AvailableSkinsCC,
|
||||||
|
availableShotSkins = Models[CatalogModelIds.AvailableShotSkins] as? AvailableShotSkinsCC,
|
||||||
|
mountedSkin = Models[CatalogModelIds.MountedSkin] as? MountedSkinCC,
|
||||||
|
mountedShotSkin = Models[CatalogModelIds.MountedShotSkin] as? MountedSkinCC,
|
||||||
|
skinPreview = Models[CatalogModelIds.SkinPreview] as? SkinPreviewCC,
|
||||||
|
grouped = Models[CatalogModelIds.Grouped] as? GroupedCC,
|
||||||
|
rarity = (Models[CatalogModelIds.ItemRarity] as? ItemRarityCC)?.Rarity,
|
||||||
|
favorite = false,
|
||||||
|
isSellingForCoin = null,
|
||||||
|
isSellingForCrystal = null,
|
||||||
|
isSellingForRuby = null,
|
||||||
|
resistanceBackgroundImg = Models[CatalogModelIds.ResistanceBackground] as? ResistanceBackgroundCC,
|
||||||
|
visible = (Models[CatalogModelIds.Visible] as? VisibleCC)?.Visible ?: true,
|
||||||
|
descriptionMedia = Models[CatalogModelIds.DescriptionMedia] as? DescriptionMediaCC,
|
||||||
|
saleByKitItems = Models[CatalogModelIds.ItemSaleByKit] as? ItemSaleByKitCC,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MakeDevice(Id: Long, Models: Map<Long, Any>): GarageDeviceObject {
|
||||||
|
val Modification = Models[CatalogModelIds.Modification] as? ModificationCC
|
||||||
|
return GarageDeviceObject(
|
||||||
|
id = Id,
|
||||||
|
baseItemId = Modification?.Field1 ?: 0L,
|
||||||
|
temporaryItemCC = Models[CatalogModelIds.TemporaryItem] as? TemporaryItemCC,
|
||||||
|
description = Models[CatalogModelIds.DescriptionModel],
|
||||||
|
item = Models[CatalogModelIds.ItemModel],
|
||||||
|
isPremium = (Models[CatalogModelIds.PremiumItem] as? PremiumItemCC)?.PremiumItem ?: false,
|
||||||
|
itemCategory = (Models[CatalogModelIds.ItemCategory] as? ItemCategoryCC)?.Category ?: 0,
|
||||||
|
itemViewCategory = (Models[CatalogModelIds.ItemViewCategory] as? ItemViewCategoryCC)?.Category ?: 0,
|
||||||
|
buyable = (Models[CatalogModelIds.Buyable] as? BuyableCC)?.Buyable ?: false,
|
||||||
|
discount = Models[CatalogModelIds.Discount],
|
||||||
|
timePeriod = Models[CatalogModelIds.TimePeriod],
|
||||||
|
deviceProperty = Models[CatalogModelIds.DeviceProperties] as? DevicePropertiesCC,
|
||||||
|
rarity = (Models[CatalogModelIds.ItemRarity] as? ItemRarityCC)?.Rarity,
|
||||||
|
visible = (Models[CatalogModelIds.Visible] as? VisibleCC)?.Visible ?: true,
|
||||||
|
descriptionMedia = Models[CatalogModelIds.DescriptionMedia] as? DescriptionMediaCC,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,6 +78,10 @@ object SessionCheck {
|
|||||||
var Bad = 0
|
var Bad = 0
|
||||||
var HeaderErrors = 0
|
var HeaderErrors = 0
|
||||||
var Errors = 0
|
var Errors = 0
|
||||||
|
var PtRecords = 0
|
||||||
|
var PtItems = 0
|
||||||
|
var PtMaxItems = 0
|
||||||
|
val PtSample = ArrayList<String>()
|
||||||
val Methods = LinkedHashMap<Long, Int>()
|
val Methods = LinkedHashMap<Long, Int>()
|
||||||
|
|
||||||
for (Path in Files) {
|
for (Path in Files) {
|
||||||
@@ -95,11 +99,47 @@ object SessionCheck {
|
|||||||
for (R in List) {
|
for (R in List) {
|
||||||
Methods[R.MethodId] = (Methods[R.MethodId] ?: 0) + 1
|
Methods[R.MethodId] = (Methods[R.MethodId] ?: 0) + 1
|
||||||
if (R.Payload.contentEquals(R.Reencoded)) Ok++ else Bad++
|
if (R.Payload.contentEquals(R.Reencoded)) Ok++ else Bad++
|
||||||
|
val V = R.Value
|
||||||
|
if (V is Net.Protocol.PtPayload) {
|
||||||
|
PtRecords++
|
||||||
|
PtItems += V.Items.size
|
||||||
|
if (V.Items.size > PtMaxItems) PtMaxItems = V.Items.size
|
||||||
|
if (PtSample.size < 3) {
|
||||||
|
PtSample.add(
|
||||||
|
"obj=${V.Objects.size},items=${V.Items.size},ids=" +
|
||||||
|
V.Items.take(16).joinToString(",") { it.Id.toString() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Router.RouteAll(List)
|
Router.RouteAll(List)
|
||||||
}
|
}
|
||||||
|
|
||||||
println("文件 $Frames|记录 $Records|回编码一致 $Ok|不一致 $Bad|记录头截断 $HeaderErrors|其它错误 $Errors|别名表=${Session.AliasCount}")
|
println("文件 $Frames|记录 $Records|回编码一致 $Ok|不一致 $Bad|记录头截断 $HeaderErrors|其它错误 $Errors|别名表=${Session.AliasCount}")
|
||||||
|
println("Pt 容器 $PtRecords 条|项 $PtItems|单条最多 $PtMaxItems")
|
||||||
|
for (S in PtSample) println(" pt 样本:$S")
|
||||||
|
println(
|
||||||
|
"目录:物品 ${Router.Catalog.Items.size}|装置 ${Router.Catalog.Devices.size}" +
|
||||||
|
"|吸收项 ${Router.Cataloged}|跳过组 ${Router.Catalog.SkippedGroups}"
|
||||||
|
)
|
||||||
|
if (Router.Catalog.SkippedModels.isNotEmpty()) {
|
||||||
|
val TopSkip = Router.Catalog.SkippedModels.entries.sortedByDescending { it.value }.take(6)
|
||||||
|
println("目录跳过模型:" + TopSkip.joinToString(",") { "${it.key}×${it.value}" })
|
||||||
|
}
|
||||||
|
for (S in Router.Catalog.Items.values.take(3)) {
|
||||||
|
val D = S.description as? Net.Generated.DescriptionModelCC
|
||||||
|
println(
|
||||||
|
" 物品样本:id=${S.id}|name=${D?.Name}|category=${S.itemCategory}|view=${S.itemViewCategory}" +
|
||||||
|
"|premium=${S.isPremium}|count=${S.count}|rarity=${S.rarity}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for (S in Router.Catalog.Devices.values.take(2)) {
|
||||||
|
val D = S.description as? Net.Generated.DescriptionModelCC
|
||||||
|
println(
|
||||||
|
" 装置样本:id=${S.id}|base=${S.baseItemId}|name=${D?.Name}" +
|
||||||
|
"|category=${S.itemCategory}|rarity=${S.rarity}"
|
||||||
|
)
|
||||||
|
}
|
||||||
println("路由:已派发 ${Router.Applied}|未覆盖 ${Router.Unmapped}|失败 ${Router.Failed}|用户=${Router.Store.State.User.Uid}|屏幕=${Router.Store.State.Screen.Current}")
|
println("路由:已派发 ${Router.Applied}|未覆盖 ${Router.Unmapped}|失败 ${Router.Failed}|用户=${Router.Store.State.User.Uid}|屏幕=${Router.Store.State.Screen.Current}")
|
||||||
val TopModels = Router.UnmappedModels.entries.sortedByDescending { it.value }.take(8)
|
val TopModels = Router.UnmappedModels.entries.sortedByDescending { it.value }.take(8)
|
||||||
if (TopModels.isNotEmpty()) {
|
if (TopModels.isNotEmpty()) {
|
||||||
@@ -114,7 +154,7 @@ object SessionCheck {
|
|||||||
println("高频 methodId:" + Top.joinToString(",") { "${it.key}×${it.value}" })
|
println("高频 methodId:" + Top.joinToString(",") { "${it.key}×${it.value}" })
|
||||||
}
|
}
|
||||||
// 抓包目录里混有入口/握手帧,解不出记录是正常现象;只要所有解出的记录都能回编码即可。
|
// 抓包目录里混有入口/握手帧,解不出记录是正常现象;只要所有解出的记录都能回编码即可。
|
||||||
val Passed = Bad == 0 && Records > 0
|
val Passed = Bad == 0 && Records > 0 && Router.Catalog.Items.isNotEmpty()
|
||||||
println(if (Passed) "结果:通过" else "结果:失败")
|
println(if (Passed) "结果:通过" else "结果:失败")
|
||||||
ExitSession(if (Passed) 0 else 1)
|
ExitSession(if (Passed) 0 else 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,13 @@ class SessionRouter(InitialState: RootState = RootState()) {
|
|||||||
|
|
||||||
val Store: ReduxStore<RootState> = ReduxStore(InitialState, ::ReduceRoot)
|
val Store: ReduxStore<RootState> = ReduxStore(InitialState, ::ReduceRoot)
|
||||||
|
|
||||||
|
/** 静态物品目录:吸收 Pt 容器里的物品 / 装置 CC 组,不进 Redux 状态。 */
|
||||||
|
val Catalog: ItemCatalog = ItemCatalog()
|
||||||
|
|
||||||
var Applied: Int = 0
|
var Applied: Int = 0
|
||||||
private set
|
private set
|
||||||
|
var Cataloged: Int = 0
|
||||||
|
private set
|
||||||
var Unmapped: Int = 0
|
var Unmapped: Int = 0
|
||||||
private set
|
private set
|
||||||
var Failed: Int = 0
|
var Failed: Int = 0
|
||||||
@@ -39,7 +44,12 @@ class SessionRouter(InitialState: RootState = RootState()) {
|
|||||||
val Value = Record.Value
|
val Value = Record.Value
|
||||||
if (Value is PtPayload) {
|
if (Value is PtPayload) {
|
||||||
var Last: Any? = null
|
var Last: Any? = null
|
||||||
for (Item in Value.Items) {
|
val Consumed = Catalog.Ingest(Value)
|
||||||
|
for ((Index, Item) in Value.Items.withIndex()) {
|
||||||
|
if (Consumed != null && Consumed[Index]) {
|
||||||
|
Cataloged++
|
||||||
|
continue
|
||||||
|
}
|
||||||
val MakeModel = DownlinkModelActions[Item.Id]
|
val MakeModel = DownlinkModelActions[Item.Id]
|
||||||
if (MakeModel == null) {
|
if (MakeModel == null) {
|
||||||
Unmapped++
|
Unmapped++
|
||||||
|
|||||||
Reference in new issue
Block a user