feat(state): 迁移 garage 切片(31 字段 / 60 分支)
This commit is contained in:
1 parent
f66f431670
commit
3c0ed0a998
14 files changed
+3366
-153
No files matched your search
@@ -143,7 +143,7 @@
|
||||
`names/root_wiring.json` + `TankiOffline/.../App/State/RootState.kt`、`RootWiring.kt`。
|
||||
- 根状态 `z6`(`TOState`)的 **89 个槽位**全部入表;字段顺序取 `toString`,槽位取构造函数 `<名>_1`。
|
||||
- 根 reducer `k6` 的逐切片委派记全:reducer 引用、委派表达式、顶层 `instanceof` 动作名。
|
||||
- 已迁移切片 **8/89**:
|
||||
- 已迁移切片 **9/89**:
|
||||
- `inviteState` → `aD` / `pD.er5`(`InviteReducer.kt`)
|
||||
- `loginByPassword` → `gD` / `MD.cr6`(`LoginReducer.kt`,含 `SetLogin`/`SetPassword` 把 status 打回 `NONE` 的原语义)
|
||||
- `twitchState` → `g9` / `y9.gta`(`TwitchReducer.kt`;`SetAccount` 是 Twitch 账号,不是 UID)
|
||||
@@ -164,9 +164,17 @@
|
||||
`ClearRewards` 清空 `rewards` / `shownRewards`,`ShownRewards` 是追加(原 `List.plus`)。
|
||||
补给箱类型用 `App.State.ContainerType`(`STANDARD/RARE/EPIC/LEGENDARY`,默认 `STANDARD`);
|
||||
无 `toString` 的 `mH/kH/zH/gH/CH/SH` 按效果定名(`SetTimeToGiveLootBox`/`SetPeriodOfGiveLootBox`/…)。
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 只归约上述八片,其余 **81 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 8/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **163 项全绿**,含 89 槽位完整性、八片一次归约互不串片、未迁移字段透传,
|
||||
- `garage` → `UB` / `hF`(`GarageReducer.kt`):31 字段;58 个 `instanceof` 臂,
|
||||
另加 `Xd(t, LF)`(`GarageInsertDeviceClientAndServer`,`LF` 是标记接口)与 `yd(t, Nu)`(`xU` 单例)两个非 `instanceof` 臂,**共 60 分支**。
|
||||
`PB`(`itemsByBase`)用 `GarageBaseItems`,`UF`(`baseItemIdToDevices`)与 `GarageDevice` 强类型;
|
||||
`aB` 的 `urb_1` = `modification.vcf_1 ?: id`、`trb_1` = `hasDeviceSale && owned`。
|
||||
`GarageLoaded` 按 depot/mounted/market/skins 重建物品表;`MU` 的 `krg` 是批量 `owned + mounted = true`(不是卸下);
|
||||
`dU`/`wU` 写整组 `mountedSkin`/`mountedShotSkin`;`GoTo` 仅在目标屏幕为 Garage 时复位 `currentCategory`。
|
||||
无 `toString` 的 25 个匿名类按效果定名(`rF`→`ResetGarage` … `FB`→`ClearWaitServerItemMount`);
|
||||
`FX`(Garage 屏幕)与 `UB`(状态类)已从动作表剔除并记入 `Markers`(`screen-id-class` / `state-class`)。
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 只归约上述九片,其余 **80 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 9/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **234 项全绿**,含 89 槽位完整性、九片一次归约互不串片、未迁移字段透传,
|
||||
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||
@@ -175,7 +183,7 @@
|
||||
`o1` → `ShowShopDiscountNotification`(`$_$.gl` 单例,由 module_18334 的 `Qx.qge` 派发;
|
||||
效果是把 `HomeScreen.shopDiscountNotification` 置 true,对应主菜单商店项的折扣提示);
|
||||
shop 的 17 个匿名类按 reducer 效果定名并登记(`Yut`→`ShopLoaded`、`F5`→`ResetShop` 等);
|
||||
screen 的 9 个、lootBoxes 的 6 个匿名类同样按效果定名并登记。
|
||||
screen 的 9 个、lootBoxes 的 6 个、garage 的 25 个匿名类同样按效果定名并登记。
|
||||
|
||||
### S4 引擎核心
|
||||
- 模块:32088(3D 数学)、92980(渲染)、61378(ECS)、55088(物理)、36659 + 71105(资源)、36734(音频)、3569(输入)
|
||||
|
||||
+189
-30
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generatedAt": "2026-10-23T04:19:26.216Z",
|
||||
"generatedAt": "2026-10-23T05:35:58.037Z",
|
||||
"module": "module_10032.js",
|
||||
"RootState": {
|
||||
"Class": "z6",
|
||||
@@ -14,7 +14,8 @@
|
||||
"localBattleUserState",
|
||||
"shop",
|
||||
"screen",
|
||||
"lootBoxes"
|
||||
"lootBoxes",
|
||||
"garage"
|
||||
],
|
||||
"AnonymousActions": [
|
||||
{
|
||||
@@ -215,6 +216,156 @@
|
||||
"Name": "SetIsBlockOpenButtons",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "isBlockOpenButtons = action.xrv_1(第 18 个构造参数)"
|
||||
},
|
||||
{
|
||||
"Local": "rF",
|
||||
"Name": "ResetGarage",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "devices = new UF()、upgradeCoolDownEndTimes = emptyMap()、upgradeItemInProcessingId = null"
|
||||
},
|
||||
{
|
||||
"Local": "EU",
|
||||
"Name": "SetGarageObject",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "garageObject = action.nrk_1"
|
||||
},
|
||||
{
|
||||
"Local": "RU",
|
||||
"Name": "SetItemsOnDepot",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "itemsOnDepot = action.rrk_1"
|
||||
},
|
||||
{
|
||||
"Local": "PU",
|
||||
"Name": "SetItemsOnMarket",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "itemsOnMarket = action.srk_1"
|
||||
},
|
||||
{
|
||||
"Local": "NU",
|
||||
"Name": "SetMountedItems",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "mountedItems = action.trk_1"
|
||||
},
|
||||
{
|
||||
"Local": "eF",
|
||||
"Name": "GarageLoaded",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "按 itemsOnDepot / mountedItems / itemsOnMarket / skinsItems 重建 items(PB),isLoaded = true"
|
||||
},
|
||||
{
|
||||
"Local": "VB",
|
||||
"Name": "SetGarageNotLoaded",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "isLoaded = false"
|
||||
},
|
||||
{
|
||||
"Local": "JB",
|
||||
"Name": "SelectGarageCategory",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "currentCategory = action.qri_1、currentItemId = null"
|
||||
},
|
||||
{
|
||||
"Local": "QU",
|
||||
"Name": "AddGarageItemCount",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "items.grg(item, copy(owned=true, count += action.trl_1, devicePreview = 改装等级对应项))"
|
||||
},
|
||||
{
|
||||
"Local": "SU",
|
||||
"Name": "GarageMountItem",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "items.jrg(action.lrk_1)(同 viewCategory 先卸下已装配项,再装配本项)"
|
||||
},
|
||||
{
|
||||
"Local": "iU",
|
||||
"Name": "GarageUnmountItem",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "items.mrg(action.crj_1)(mounted = false)"
|
||||
},
|
||||
{
|
||||
"Local": "MU",
|
||||
"Name": "GarageMountItems",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "items.krg(action.urk_1)(批量 mounted = true)"
|
||||
},
|
||||
{
|
||||
"Local": "dU",
|
||||
"Name": "SetMountedSkinForItems",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "items.qrg(action.vrj_1, action.wrj_1)(整组 mountedSkin = skinId)"
|
||||
},
|
||||
{
|
||||
"Local": "wU",
|
||||
"Name": "SetMountedShotSkinForItems",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "items.rrg(action.srj_1, action.trj_1)(整组 mountedShotSkin = skinId)"
|
||||
},
|
||||
{
|
||||
"Local": "aF",
|
||||
"Name": "SetNewItems",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "newItems = action.srm_1"
|
||||
},
|
||||
{
|
||||
"Local": "cF",
|
||||
"Name": "AddNewItem",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "newItems[itemId] += value(Set 并集)"
|
||||
},
|
||||
{
|
||||
"Local": "lF",
|
||||
"Name": "RemoveNewItem",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "newItems[itemId] -= value,空集则删键"
|
||||
},
|
||||
{
|
||||
"Local": "fF",
|
||||
"Name": "SetResistanceReadyToMount",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "resistanceReadyToMount = action.nrm_1"
|
||||
},
|
||||
{
|
||||
"Local": "bU",
|
||||
"Name": "ResetMountDelay",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "delayMountTimeMs = 0"
|
||||
},
|
||||
{
|
||||
"Local": "vF",
|
||||
"Name": "StartCooldownReduce",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "cooldownReduceEndTime = now + seconds*1000、timeToReduceUpdateInMin = action.mrm_1"
|
||||
},
|
||||
{
|
||||
"Local": "pF",
|
||||
"Name": "SetCooldownReduceEndTime",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "cooldownReduceEndTime = now + seconds*1000"
|
||||
},
|
||||
{
|
||||
"Local": "yU",
|
||||
"Name": "ShowGarageDiscountNotification",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "garageDiscountNotification = true"
|
||||
},
|
||||
{
|
||||
"Local": "WB",
|
||||
"Name": "HideVideoInDescription",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "showVideoInDescription = false"
|
||||
},
|
||||
{
|
||||
"Local": "OU",
|
||||
"Name": "RemoveWaitServerItemMount",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "waitServerItemMount 的给定键全部置 false"
|
||||
},
|
||||
{
|
||||
"Local": "FB",
|
||||
"Name": "ClearWaitServerItemMount",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "waitServerItemMount = emptyMap()"
|
||||
}
|
||||
],
|
||||
"Markers": [
|
||||
@@ -237,6 +388,16 @@
|
||||
"Local": "RX",
|
||||
"Kind": "screen-id-class",
|
||||
"Evidence": "屏幕标识类 System.Loader:`function RX(){ this.ysb_1=\"System.Loader\" }`,`PX()` 返回该单例,也是 WK.current 的默认值;GoTo 到它时不发 screen_show。"
|
||||
},
|
||||
{
|
||||
"Local": "FX",
|
||||
"Kind": "screen-id-class",
|
||||
"Evidence": "屏幕标识类 Garage:`function FX(t){ … this.irm_1 = t; this.jrm_1 = \"Garage\" }`,默认分类 `BB().sq5_1`;garage 的 GoTo 分支用它把 currentCategory 复位。"
|
||||
},
|
||||
{
|
||||
"Local": "UB",
|
||||
"Kind": "state-class",
|
||||
"Evidence": "garage 切片状态类:`function UB(…31 字段)`,toString 名 \"Garage(...)\";InitState 分支用 `h instanceof UB` 校验灌入状态,不是动作。"
|
||||
}
|
||||
],
|
||||
"Rows": [
|
||||
@@ -372,43 +533,22 @@
|
||||
"Reducer": "hF",
|
||||
"Delegate": "hF(t, n)",
|
||||
"Actions": [
|
||||
"?EU",
|
||||
"?FB",
|
||||
"?FX",
|
||||
"?JB",
|
||||
"?MU",
|
||||
"?NU",
|
||||
"?OU",
|
||||
"?PU",
|
||||
"?QU",
|
||||
"?RU",
|
||||
"?SU",
|
||||
"?VB",
|
||||
"?WB",
|
||||
"?aF",
|
||||
"?bU",
|
||||
"?cF",
|
||||
"?dU",
|
||||
"?eF",
|
||||
"?fF",
|
||||
"?iU",
|
||||
"?lF",
|
||||
"?pF",
|
||||
"?rF",
|
||||
"?vF",
|
||||
"?wU",
|
||||
"?yU",
|
||||
"AddGarageItemCount",
|
||||
"AddNewItem",
|
||||
"AddOverdriveDescription",
|
||||
"AddRelatedBazooka",
|
||||
"AddRelatedResistanceModule",
|
||||
"AddToFavoriteItem",
|
||||
"BuyProtectionSlot",
|
||||
"Garage",
|
||||
"ClearWaitServerItemMount",
|
||||
"GarageAddItemToDepot",
|
||||
"GarageApplyResistanceMount",
|
||||
"GarageBuyDevice",
|
||||
"GarageDeviceTrySetInfinityLifetime",
|
||||
"GarageDevicesLoadedAction",
|
||||
"GarageLoaded",
|
||||
"GarageMountItem",
|
||||
"GarageMountItems",
|
||||
"GarageRemoveDevice",
|
||||
"GarageRemoveDiscountForDevice",
|
||||
"GarageRemoveItemFromDepot",
|
||||
@@ -418,23 +558,42 @@
|
||||
"GarageSelectItem",
|
||||
"GarageSelectShotSkin",
|
||||
"GarageSelectSkin",
|
||||
"GarageUnmountItem",
|
||||
"GarageUpdateItemCount",
|
||||
"GarageUpgradeItemAction",
|
||||
"GarageUpgradeItemConfirm",
|
||||
"GarageUpgradeItemCoolDownFinished",
|
||||
"GarageUpgradeItemCoolDownStarted",
|
||||
"GoTo",
|
||||
"HideVideoInDescription",
|
||||
"InitState",
|
||||
"RemoveFromFavoriteItem",
|
||||
"RemoveFromSale",
|
||||
"RemoveNewItem",
|
||||
"RemoveWaitServerItemMount",
|
||||
"ResetGarage",
|
||||
"ResetMountDelay",
|
||||
"SelectGarageCategory",
|
||||
"SetCooldownReduceEndTime",
|
||||
"SetGarageNotLoaded",
|
||||
"SetGarageObject",
|
||||
"SetGarageSkinsAction",
|
||||
"SetItemRarity",
|
||||
"SetItemsOnDepot",
|
||||
"SetItemsOnMarket",
|
||||
"SetMountedItems",
|
||||
"SetMountedShotSkinForItems",
|
||||
"SetMountedSkinForItems",
|
||||
"SetNewItems",
|
||||
"SetResistanceReadyToMount",
|
||||
"SetRestrictionMount",
|
||||
"ShowGarageDiscountNotification",
|
||||
"StartCooldownReduce",
|
||||
"SwitchingRowsScroll",
|
||||
"UpdateDiscount"
|
||||
],
|
||||
"Default": "new UB()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "garagePreview",
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -574,6 +574,67 @@ const FieldTypeOverrides = new Map([
|
||||
['SetCurrentContainer.type', 'ContainerType'],
|
||||
['SelectCategory.containerCategory', 'ContainerType?'],
|
||||
['ShownRewards.rewards', 'List<ContainerGivenItem>'],
|
||||
// garage 切片:生成器从调用点只能给 Any?,但 reducer 里这些字段参与 Map 键/算术/子状态类型。
|
||||
// · 装备/物品 id 在运行时派发里都是 Long;count 是 Int。
|
||||
// · itemsByBase 的值是 iB(无 toString):Kotlin 侧自建 GarageBaseItems(Items + 派生字段)。
|
||||
// · baseItemIdToDevices 的值是 List<VF(GarageDevice)>。
|
||||
['GarageItem.id', 'Long'],
|
||||
['GarageItem.count', 'Int'],
|
||||
['GarageDevice.id', 'Long'],
|
||||
['GarageDevice.baseItemId', 'Long'],
|
||||
['GarageItem.modification', 'GarageItemModification?'],
|
||||
['GarageItem.upgradeableParams', 'UpgradableItemParams?'],
|
||||
['GarageItemsState.itemsByBase', 'Map<Long, GarageBaseItems>'],
|
||||
['Devices.baseItemIdToDevices', 'Map<Long, List<GarageDevice>>'],
|
||||
['GarageItemObject.id', 'Long'],
|
||||
['GarageItemObject.count', 'Int'],
|
||||
['GarageItemObject.itemCategory', 'Int'],
|
||||
['GarageItemObject.itemViewCategory', 'Int'],
|
||||
['GarageItemObject.isPremium', 'Boolean'],
|
||||
['GarageItemObject.buyable', 'Boolean'],
|
||||
['GarageItemObject.availableForAll', 'Boolean'],
|
||||
['GarageItemObject.modification', 'GarageItemModification?'],
|
||||
['GarageItemObject.upgradeableParams', 'UpgradableItemParams?'],
|
||||
['GarageItemObject.visible', 'Boolean'],
|
||||
['GarageDeviceObject.id', 'Long'],
|
||||
['GarageDeviceObject.baseItemId', 'Long'],
|
||||
['GarageDeviceObject.itemCategory', 'Int'],
|
||||
['GarageDeviceObject.itemViewCategory', 'Int'],
|
||||
['GarageDeviceObject.isPremium', 'Boolean'],
|
||||
['GarageDeviceObject.buyable', 'Boolean'],
|
||||
['GarageDeviceObject.visible', 'Boolean'],
|
||||
['GarageDevicesLoadedAction.mountedDevice', 'GarageDevice?'],
|
||||
['GarageSelectItem.itemId', 'Long'],
|
||||
['GarageAddItemToDepot.itemId', 'Long'],
|
||||
['GarageAddItemToDepot.count', 'Int'],
|
||||
['GarageRemoveItemFromDepot.item', 'GarageItemObject'],
|
||||
['GarageRemoveItemFromStore.itemId', 'Long'],
|
||||
['GarageUpdateItemCount.item', 'GarageItem'],
|
||||
['GarageUpdateItemCount.count', 'Int'],
|
||||
['GarageUpgradeItemAction.itemId', 'Long'],
|
||||
['GarageUpgradeItemCoolDownStarted.itemId', 'Long'],
|
||||
['GarageUpgradeItemCoolDownStarted.endTime', 'Long'],
|
||||
['GarageUpgradeItemCoolDownFinished.itemId', 'Long'],
|
||||
['GarageUpgradeItemCoolDownFinished.endTime', 'Long'],
|
||||
['GarageRemoveDevice.device', 'GarageDevice'],
|
||||
['GarageRemoveDevice.item', 'GarageItem'],
|
||||
['GarageInsertDeviceClientAndServer.device', 'GarageDevice'],
|
||||
['GarageInsertDeviceClientAndServer.item', 'GarageItem'],
|
||||
['GarageBuyDevice.device', 'GarageDevice'],
|
||||
['GarageBuyDevice.item', 'GarageItem'],
|
||||
['GarageDeviceTrySetInfinityLifetime.deviceId', 'Long'],
|
||||
['GarageApplyResistanceMount.resistance', 'GarageItem'],
|
||||
['GarageApplyResistanceMount.index', 'Int'],
|
||||
['GarageResistanceUnMount.resistance', 'Long'],
|
||||
['GarageSelectAlteration.alterationId', 'Long'],
|
||||
['GarageSelectSkin.skinId', 'Long'],
|
||||
['GarageSelectShotSkin.shotSkinId', 'Long'],
|
||||
['GarageRemoveDiscountForDevice.item', 'GarageItem'],
|
||||
['UpdateDiscount.item', 'GarageItem'],
|
||||
['RemoveFromSale.removeItems', 'Collection<Long>'],
|
||||
['AddToFavoriteItem.itemId', 'Long'],
|
||||
['RemoveFromFavoriteItem.itemId', 'Long'],
|
||||
['BuyProtectionSlot.slotToUnlock', 'Int'],
|
||||
]);
|
||||
|
||||
const Emitted = [];
|
||||
|
||||
@@ -75,13 +75,42 @@ const AnonymousActionNames = new Map([
|
||||
['gH', 'LootBoxOpeningFailed'],
|
||||
['CH', 'SetIsReopening'],
|
||||
['SH', 'SetIsBlockOpenButtons'],
|
||||
// garage 切片(UB / hF):没有 toString / 不在 action_inventory 的 25 个类。
|
||||
// 括号里是原 reducer 的效果;实现见 GarageReducer.kt。
|
||||
['rF', 'ResetGarage'],
|
||||
['EU', 'SetGarageObject'],
|
||||
['RU', 'SetItemsOnDepot'],
|
||||
['PU', 'SetItemsOnMarket'],
|
||||
['NU', 'SetMountedItems'],
|
||||
['eF', 'GarageLoaded'],
|
||||
['VB', 'SetGarageNotLoaded'],
|
||||
['JB', 'SelectGarageCategory'],
|
||||
['QU', 'AddGarageItemCount'],
|
||||
['SU', 'GarageMountItem'],
|
||||
['iU', 'GarageUnmountItem'],
|
||||
['MU', 'GarageMountItems'],
|
||||
['dU', 'SetMountedSkinForItems'],
|
||||
['wU', 'SetMountedShotSkinForItems'],
|
||||
['aF', 'SetNewItems'],
|
||||
['cF', 'AddNewItem'],
|
||||
['lF', 'RemoveNewItem'],
|
||||
['fF', 'SetResistanceReadyToMount'],
|
||||
['bU', 'ResetMountDelay'],
|
||||
['vF', 'StartCooldownReduce'],
|
||||
['pF', 'SetCooldownReduceEndTime'],
|
||||
['yU', 'ShowGarageDiscountNotification'],
|
||||
['WB', 'HideVideoInDescription'],
|
||||
['OU', 'RemoveWaitServerItemMount'],
|
||||
['FB', 'ClearWaitServerItemMount'],
|
||||
]);
|
||||
|
||||
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
||||
// 它们从 Actions 列表里剔除,改记到 root_wiring.json 的 Markers。
|
||||
const NonActionInstanceof = new Map([
|
||||
['LX', '屏幕标识类 Entrance:`function LX(){ this.gs5_1="Entrance" }`,`ld(LX).m()` 返回 "Entrance";GoTo 分支用它判断 analytics 事件是否 isModal。'],
|
||||
['RX', '屏幕标识类 System.Loader:`function RX(){ this.ysb_1="System.Loader" }`,`PX()` 返回该单例,也是 WK.current 的默认值;GoTo 到它时不发 screen_show。'],
|
||||
['LX', { Kind: 'screen-id-class', Evidence: '屏幕标识类 Entrance:`function LX(){ this.gs5_1="Entrance" }`,`ld(LX).m()` 返回 "Entrance";GoTo 分支用它判断 analytics 事件是否 isModal。' }],
|
||||
['RX', { Kind: 'screen-id-class', Evidence: '屏幕标识类 System.Loader:`function RX(){ this.ysb_1="System.Loader" }`,`PX()` 返回该单例,也是 WK.current 的默认值;GoTo 到它时不发 screen_show。' }],
|
||||
['FX', { Kind: 'screen-id-class', Evidence: '屏幕标识类 Garage:`function FX(t){ … this.irm_1 = t; this.jrm_1 = "Garage" }`,默认分类 `BB().sq5_1`;garage 的 GoTo 分支用它把 currentCategory 复位。' }],
|
||||
['UB', { Kind: 'state-class', Evidence: 'garage 切片状态类:`function UB(…31 字段)`,toString 名 "Garage(...)";InitState 分支用 `h instanceof UB` 校验灌入状态,不是动作。' }],
|
||||
]);
|
||||
|
||||
/** 动作局部类名 → 动作名;未收录的返回 null。 */
|
||||
@@ -441,6 +470,7 @@ const Migrated = {
|
||||
shop: { Type: 'ShopStateSlice', Reduce: 'ReduceShop' },
|
||||
screen: { Type: 'ScreenStateSlice', Reduce: 'ReduceScreen' },
|
||||
lootBoxes: { Type: 'LootBoxesStateSlice', Reduce: 'ReduceLootBoxes' },
|
||||
garage: { Type: 'GarageStateSlice', Reduce: 'ReduceGarage' },
|
||||
};
|
||||
|
||||
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
||||
@@ -505,6 +535,35 @@ const LootBoxesAnonymousEffects = {
|
||||
SH: 'isBlockOpenButtons = action.xrv_1(第 18 个构造参数)',
|
||||
};
|
||||
|
||||
// garage 切片(UB / hF):没有 toString / 不在 action_inventory 的类,按 reducer 分支效果定名。
|
||||
const GarageAnonymousEffects = {
|
||||
rF: 'devices = new UF()、upgradeCoolDownEndTimes = emptyMap()、upgradeItemInProcessingId = null',
|
||||
EU: 'garageObject = action.nrk_1',
|
||||
RU: 'itemsOnDepot = action.rrk_1',
|
||||
PU: 'itemsOnMarket = action.srk_1',
|
||||
NU: 'mountedItems = action.trk_1',
|
||||
eF: '按 itemsOnDepot / mountedItems / itemsOnMarket / skinsItems 重建 items(PB),isLoaded = true',
|
||||
VB: 'isLoaded = false',
|
||||
JB: 'currentCategory = action.qri_1、currentItemId = null',
|
||||
QU: 'items.grg(item, copy(owned=true, count += action.trl_1, devicePreview = 改装等级对应项))',
|
||||
SU: 'items.jrg(action.lrk_1)(同 viewCategory 先卸下已装配项,再装配本项)',
|
||||
iU: 'items.mrg(action.crj_1)(mounted = false)',
|
||||
MU: 'items.krg(action.urk_1)(批量 mounted = true)',
|
||||
dU: 'items.qrg(action.vrj_1, action.wrj_1)(整组 mountedSkin = skinId)',
|
||||
wU: 'items.rrg(action.srj_1, action.trj_1)(整组 mountedShotSkin = skinId)',
|
||||
aF: 'newItems = action.srm_1',
|
||||
cF: 'newItems[itemId] += value(Set 并集)',
|
||||
lF: 'newItems[itemId] -= value,空集则删键',
|
||||
fF: 'resistanceReadyToMount = action.nrm_1',
|
||||
bU: 'delayMountTimeMs = 0',
|
||||
vF: 'cooldownReduceEndTime = now + seconds*1000、timeToReduceUpdateInMin = action.mrm_1',
|
||||
pF: 'cooldownReduceEndTime = now + seconds*1000',
|
||||
yU: 'garageDiscountNotification = true',
|
||||
WB: 'showVideoInDescription = false',
|
||||
OU: 'waitServerItemMount 的给定键全部置 false',
|
||||
FB: 'waitServerItemMount = emptyMap()',
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(P, 'names', 'root_wiring.json'),
|
||||
JSON.stringify(
|
||||
@@ -539,6 +598,12 @@ fs.writeFileSync(
|
||||
DispatchedAt: '未在 action_trace_merged.json 中出现;按 reducer 分支效果定名',
|
||||
Effect,
|
||||
})),
|
||||
...Object.entries(GarageAnonymousEffects).map(([Local, Effect]) => ({
|
||||
Local,
|
||||
Name: AnonymousActionNames.get(Local),
|
||||
DispatchedAt: '未在 action_trace_merged.json 中出现;按 reducer 分支效果定名',
|
||||
Effect,
|
||||
})),
|
||||
],
|
||||
Markers: [
|
||||
{
|
||||
@@ -551,10 +616,10 @@ fs.writeFileSync(
|
||||
Kind: 'marker-action',
|
||||
Evidence: '`fd(x4, "", cd, Wm)`;根 reducer 的 `Xd(t, $4) || t instanceof x4` 同样走 U7+w3 快路径,本身无字段、无独立效果。',
|
||||
},
|
||||
...[...NonActionInstanceof].map(([Local, Evidence]) => ({
|
||||
...[...NonActionInstanceof].map(([Local, Info]) => ({
|
||||
Local,
|
||||
Kind: 'screen-id-class',
|
||||
Evidence,
|
||||
Kind: Info.Kind,
|
||||
Evidence: Info.Evidence,
|
||||
})),
|
||||
],
|
||||
Rows,
|
||||
|
||||
@@ -268,7 +268,24 @@ function KotlinName(Field) { return Field.charAt(0).toUpperCase() + Field.slice(
|
||||
function PlanSlice(Field) {
|
||||
const F = RootFields.find((X) => X.Field === Field);
|
||||
if (!F) throw new Error('根状态里没有字段 ' + Field);
|
||||
const A = Assignments.find((X) => new RegExp('\\bn\\.' + F.Slot + '\\b').test(X.Expr));
|
||||
// 委派有两种形状:
|
||||
// 1) 根 reducer 内联写 `n.<slot>`(多数切片,或 `n.<slot>.方法(t)`)
|
||||
// 2) 根 reducer 直接调用具名 reducer `hF(t, n)`,切片槽位只在 hF 体内出现(garage)
|
||||
// 第 2 种需要回查被调函数的函数体,确认它确实读写 `n.<slot>`。
|
||||
let A = Assignments.find((X) => new RegExp('\\bn\\.' + F.Slot + '\\b').test(X.Expr));
|
||||
let NamedReducer = null;
|
||||
if (!A) {
|
||||
for (const X of Assignments) {
|
||||
const Call = /^([A-Za-z0-9_$]+)\(t,\s*n\)$/.exec(X.Expr.replace(/\s+/g, ' ').trim());
|
||||
if (!Call || !Fns.has(Call[1])) continue;
|
||||
const Fn = Fns.get(Call[1]);
|
||||
if (new RegExp('\\bn\\.' + F.Slot + '\\b').test(T.slice(Fn.Body, Fn.End))) {
|
||||
A = X;
|
||||
NamedReducer = Call[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!A) throw new Error(Field + ' 在根 reducer 里找不到委派');
|
||||
|
||||
const Param = [...SlotOfParam.keys()].find((P2) => SlotOfParam.get(P2) === F.Slot);
|
||||
@@ -277,7 +294,7 @@ function PlanSlice(Field) {
|
||||
|
||||
const Info = {
|
||||
Field, Slot: F.Slot, Class: ClassName, ClassSource: DefaultOfParam.get(Param) || '',
|
||||
Params: [], Fields: [], CopyMethod: null, Branches: [], SubReducers: [], Counts: {}, Locals: {},
|
||||
NamedReducer, Params: [], Fields: [], CopyMethod: null, Branches: [], SubReducers: [], Counts: {}, Locals: {},
|
||||
Delegate: A.Expr.replace(/\s+/g, ' ').trim().slice(0, 400),
|
||||
};
|
||||
|
||||
@@ -302,31 +319,57 @@ function PlanSlice(Field) {
|
||||
}
|
||||
|
||||
const CopyName = (A.Expr.match(/\bn\.([A-Za-z0-9_$]+)\(/) || [])[1] || null;
|
||||
Info.CopyMethod = CopyName;
|
||||
if (CopyName && ClassName) {
|
||||
const M = Methods.find((X) => X.Obj === ClassName && X.Method === CopyName);
|
||||
// 具名 reducer 的副本方法只在函数体里(`o.hri(...)`),按「参数个数 == 字段数」锁定。
|
||||
let NamedBody = null;
|
||||
if (NamedReducer) {
|
||||
const Fn = Fns.get(NamedReducer);
|
||||
NamedBody = T.slice(Fn.Body, Fn.End);
|
||||
const ByArity = [];
|
||||
for (const M of NamedBody.matchAll(/\bo\.([A-Za-z0-9_$]+)\(/g)) {
|
||||
let O = M.index + M[0].length, D = 0, E = -1;
|
||||
for (let J = O; J < NamedBody.length; J++) {
|
||||
const C2 = NamedBody[J];
|
||||
if (C2 === '(') D++;
|
||||
else if (C2 === ')') { D--; if (D === 0) { E = J; break; } }
|
||||
}
|
||||
if (E < 0) continue;
|
||||
const N = SplitTop(NamedBody.slice(O, E)).length;
|
||||
ByArity.push({ Name: M[1], Count: N });
|
||||
}
|
||||
const Hit = ByArity.find((X) => X.Count === Info.Fields.length);
|
||||
Info.CopyMethod = Hit ? Hit.Name : (ByArity[0] || {}).Name || null;
|
||||
} else {
|
||||
Info.CopyMethod = CopyName;
|
||||
}
|
||||
const CopyMethodName = Info.CopyMethod;
|
||||
if (CopyMethodName && ClassName) {
|
||||
const M = Methods.find((X) => X.Obj === ClassName && X.Method === CopyMethodName);
|
||||
Info.CopyParamCount = M ? M.Params.split(',').map((S) => S.trim()).filter(Boolean).length : null;
|
||||
Info.CopyMatchesFields = Info.CopyParamCount === Info.Fields.length;
|
||||
}
|
||||
|
||||
// ---- 分支抽取:只处理内联 IIFE;具名 reducer 请用 gen_root_wiring 的证据表
|
||||
// ---- 分支抽取:内联 IIFE 或具名 reducer(`hF(t, n)`)
|
||||
const Expr = A.Expr;
|
||||
if (!/^\(function \(t, n\)/.test(Expr)) {
|
||||
let Body;
|
||||
if (NamedReducer) {
|
||||
Body = NamedBody;
|
||||
} else if (/^\(function \(t, n\)/.test(Expr)) {
|
||||
// IIFE 的 { 位置要对到全局源码:用 Pos 定位
|
||||
const Pos = T.indexOf(A.Expr, RootReducerFn.Body);
|
||||
const GlobalOpen = T.indexOf('{', T.indexOf('function', Pos));
|
||||
const GlobalClose = Pairs.get(GlobalOpen);
|
||||
Body = T.slice(GlobalOpen + 1, GlobalClose);
|
||||
} else {
|
||||
Info.Branches = [{ Guard: '(具名 reducer)', Locals: [], Kind: 'named', Expr: Expr.replace(/\s+/g, ' ').slice(0, 200) }];
|
||||
Info.Counts = { TotalInstanceof: null, TopLevelBranches: 1, SubReducerArms: 0 };
|
||||
return Info;
|
||||
}
|
||||
// IIFE 的 { 位置要对到全局源码:用 Pos 定位
|
||||
const Pos = T.indexOf(A.Expr, RootReducerFn.Body);
|
||||
const GlobalOpen = T.indexOf('{', T.indexOf('function', Pos));
|
||||
const GlobalClose = Pairs.get(GlobalOpen);
|
||||
const Body = T.slice(GlobalOpen + 1, GlobalClose);
|
||||
|
||||
function Decode(BranchExpr) {
|
||||
const E = BranchExpr.replace(/\s+/g, ' ').trim();
|
||||
const Fields = [];
|
||||
if (/^n$/.test(E)) return { Kind: 'noop', Changed: [] };
|
||||
const CopyCall = new RegExp('\\bn\\.' + (CopyName || 'qt6') + '\\(');
|
||||
const CopyCall = new RegExp('\\b(?:n|o)\\.' + (CopyMethodName || 'qt6') + '\\(');
|
||||
const M = CopyCall.exec(E);
|
||||
if (/new [A-Za-z0-9_$]+\(/.test(E) && !M) return { Kind: 'reset', Changed: [] };
|
||||
if (!M) return { Kind: 'conditional', Changed: [] };
|
||||
|
||||
@@ -268,66 +268,66 @@ object ActionCatalog {
|
||||
ActionMeta("ShowNotificationAlreadyInOutgoingFriends", ShowNotificationAlreadyInOutgoingFriends::class, listOf(ActionFieldMeta("uid", "Any?"), ActionFieldMeta("userId", "Any?"))),
|
||||
ActionMeta("ShowNotificationAcceptedLimitExceeded", ShowNotificationAcceptedLimitExceeded::class, listOf(ActionFieldMeta("uid", "Any?"), ActionFieldMeta("userId", "Any?"))),
|
||||
ActionMeta("Discount", Discount::class, listOf(ActionFieldMeta("itemId", "Any?"), ActionFieldMeta("discount", "Float"), ActionFieldMeta("timeLeft", "Any?"), ActionFieldMeta("timeStart", "Any?"), ActionFieldMeta("isBuyable", "Boolean"))),
|
||||
ActionMeta("UpdateDiscount", UpdateDiscount::class, listOf(ActionFieldMeta("item", "Any?"))),
|
||||
ActionMeta("GarageItem", GarageItem::class, listOf(ActionFieldMeta("id", "Any?"), ActionFieldMeta("name", "Any?"), ActionFieldMeta("category", "Int"), ActionFieldMeta("viewCategory", "Int"), ActionFieldMeta("priceWithoutDiscount", "Int"), ActionFieldMeta("description", "Any?"), ActionFieldMeta("descriptionMedia", "Any?"), ActionFieldMeta("preview", "Any?"), ActionFieldMeta("isPremium", "Any?"), ActionFieldMeta("owned", "Boolean"), ActionFieldMeta("mountable", "Any?"), ActionFieldMeta("mounted", "Boolean"), ActionFieldMeta("mountIndex", "Any?"), ActionFieldMeta("position", "Int"), ActionFieldMeta("minRank", "Int"), ActionFieldMeta("maxRank", "Int"), ActionFieldMeta("discount", "Any?"), ActionFieldMeta("modification", "Any?"), ActionFieldMeta("properties", "Any?"), ActionFieldMeta("upgradeableParams", "Any?"), ActionFieldMeta("count", "Any?"), ActionFieldMeta("kit", "Any?"), ActionFieldMeta("countable", "Any?"), ActionFieldMeta("hasDeviceSale", "Boolean"), ActionFieldMeta("devicesAvailable", "Boolean"), ActionFieldMeta("devicePreview", "Any?"), ActionFieldMeta("buyable", "Boolean"), ActionFieldMeta("availableForAll", "Boolean"), ActionFieldMeta("availableSkins", "Any?"), ActionFieldMeta("availableShotSkins", "Any?"), ActionFieldMeta("mountedSkin", "Any?"), ActionFieldMeta("mountedShotSkin", "Any?"), ActionFieldMeta("skinPreview", "Any?"), ActionFieldMeta("group", "Any?"), ActionFieldMeta("rarity", "Any?"), ActionFieldMeta("favorite", "Boolean"), ActionFieldMeta("resistanceBackgroundImg", "Any?"), ActionFieldMeta("visible", "Boolean"), ActionFieldMeta("secret", "Boolean"), ActionFieldMeta("saleByKitItems", "Any?"), ActionFieldMeta("isSellingForCoin", "Boolean"), ActionFieldMeta("isSellingForCrystal", "Boolean"), ActionFieldMeta("isSellingForRuby", "Boolean"), ActionFieldMeta("isSellingForMoney", "Boolean"), ActionFieldMeta("isSellingForADS", "Boolean"))),
|
||||
ActionMeta("UpdateDiscount", UpdateDiscount::class, listOf(ActionFieldMeta("item", "GarageItem"))),
|
||||
ActionMeta("GarageItem", GarageItem::class, listOf(ActionFieldMeta("id", "Long"), ActionFieldMeta("name", "Any?"), ActionFieldMeta("category", "Int"), ActionFieldMeta("viewCategory", "Int"), ActionFieldMeta("priceWithoutDiscount", "Int"), ActionFieldMeta("description", "Any?"), ActionFieldMeta("descriptionMedia", "Any?"), ActionFieldMeta("preview", "Any?"), ActionFieldMeta("isPremium", "Any?"), ActionFieldMeta("owned", "Boolean"), ActionFieldMeta("mountable", "Any?"), ActionFieldMeta("mounted", "Boolean"), ActionFieldMeta("mountIndex", "Any?"), ActionFieldMeta("position", "Int"), ActionFieldMeta("minRank", "Int"), ActionFieldMeta("maxRank", "Int"), ActionFieldMeta("discount", "Any?"), ActionFieldMeta("modification", "GarageItemModification?"), ActionFieldMeta("properties", "Any?"), ActionFieldMeta("upgradeableParams", "UpgradableItemParams?"), ActionFieldMeta("count", "Int"), ActionFieldMeta("kit", "Any?"), ActionFieldMeta("countable", "Any?"), ActionFieldMeta("hasDeviceSale", "Boolean"), ActionFieldMeta("devicesAvailable", "Boolean"), ActionFieldMeta("devicePreview", "Any?"), ActionFieldMeta("buyable", "Boolean"), ActionFieldMeta("availableForAll", "Boolean"), ActionFieldMeta("availableSkins", "Any?"), ActionFieldMeta("availableShotSkins", "Any?"), ActionFieldMeta("mountedSkin", "Any?"), ActionFieldMeta("mountedShotSkin", "Any?"), ActionFieldMeta("skinPreview", "Any?"), ActionFieldMeta("group", "Any?"), ActionFieldMeta("rarity", "Any?"), ActionFieldMeta("favorite", "Boolean"), ActionFieldMeta("resistanceBackgroundImg", "Any?"), ActionFieldMeta("visible", "Boolean"), ActionFieldMeta("secret", "Boolean"), ActionFieldMeta("saleByKitItems", "Any?"), ActionFieldMeta("isSellingForCoin", "Boolean"), ActionFieldMeta("isSellingForCrystal", "Boolean"), ActionFieldMeta("isSellingForRuby", "Boolean"), ActionFieldMeta("isSellingForMoney", "Boolean"), ActionFieldMeta("isSellingForADS", "Boolean"))),
|
||||
ActionMeta("ItemProperty", ItemProperty::class, listOf(ActionFieldMeta("params", "Any?"), ActionFieldMeta("value", "Any?"))),
|
||||
ActionMeta("Kit", Kit::class, listOf(ActionFieldMeta("items", "Any?"))),
|
||||
ActionMeta("GarageItemObject", GarageItemObject::class, listOf(ActionFieldMeta("id", "Any?"), ActionFieldMeta("description", "Any?"), ActionFieldMeta("item", "Any?"), ActionFieldMeta("isPremium", "Any?"), ActionFieldMeta("itemCategory", "Any?"), ActionFieldMeta("itemViewCategory", "Any?"), ActionFieldMeta("buyable", "Any?"), ActionFieldMeta("availableForAll", "Any?"), ActionFieldMeta("discount", "Any?"), ActionFieldMeta("timePeriod", "Any?"), ActionFieldMeta("modification", "Any?"), ActionFieldMeta("properties", "Any?"), ActionFieldMeta("upgradeableParams", "Any?"), ActionFieldMeta("devices", "Any?"), ActionFieldMeta("count", "Any?"), ActionFieldMeta("kit", "Any?"), ActionFieldMeta("countable", "Any?"), ActionFieldMeta("mountIndex", "Any?"), ActionFieldMeta("availableSkins", "Any?"), ActionFieldMeta("availableShotSkins", "Any?"), ActionFieldMeta("mountedSkin", "Any?"), ActionFieldMeta("mountedShotSkin", "Any?"), ActionFieldMeta("skinPreview", "Any?"), ActionFieldMeta("grouped", "Any?"), ActionFieldMeta("rarity", "Any?"), ActionFieldMeta("favorite", "Boolean"), ActionFieldMeta("isSellingForCoin", "Any?"), ActionFieldMeta("isSellingForCrystal", "Any?"), ActionFieldMeta("isSellingForRuby", "Any?"), ActionFieldMeta("resistanceBackgroundImg", "Any?"), ActionFieldMeta("visible", "Any?"), ActionFieldMeta("descriptionMedia", "Any?"), ActionFieldMeta("saleByKitItems", "Any?"))),
|
||||
ActionMeta("GarageItemObject", GarageItemObject::class, listOf(ActionFieldMeta("id", "Long"), ActionFieldMeta("description", "Any?"), ActionFieldMeta("item", "Any?"), ActionFieldMeta("isPremium", "Boolean"), ActionFieldMeta("itemCategory", "Int"), ActionFieldMeta("itemViewCategory", "Int"), ActionFieldMeta("buyable", "Boolean"), ActionFieldMeta("availableForAll", "Boolean"), ActionFieldMeta("discount", "Any?"), ActionFieldMeta("timePeriod", "Any?"), ActionFieldMeta("modification", "GarageItemModification?"), ActionFieldMeta("properties", "Any?"), ActionFieldMeta("upgradeableParams", "UpgradableItemParams?"), ActionFieldMeta("devices", "Any?"), ActionFieldMeta("count", "Int"), ActionFieldMeta("kit", "Any?"), ActionFieldMeta("countable", "Any?"), ActionFieldMeta("mountIndex", "Any?"), ActionFieldMeta("availableSkins", "Any?"), ActionFieldMeta("availableShotSkins", "Any?"), ActionFieldMeta("mountedSkin", "Any?"), ActionFieldMeta("mountedShotSkin", "Any?"), ActionFieldMeta("skinPreview", "Any?"), ActionFieldMeta("grouped", "Any?"), ActionFieldMeta("rarity", "Any?"), ActionFieldMeta("favorite", "Boolean"), ActionFieldMeta("isSellingForCoin", "Any?"), ActionFieldMeta("isSellingForCrystal", "Any?"), ActionFieldMeta("isSellingForRuby", "Any?"), ActionFieldMeta("resistanceBackgroundImg", "Any?"), ActionFieldMeta("visible", "Boolean"), ActionFieldMeta("descriptionMedia", "Any?"), ActionFieldMeta("saleByKitItems", "Any?"))),
|
||||
ActionMeta("KitItem", KitItem::class, listOf(ActionFieldMeta("id", "Any?"), ActionFieldMeta("count", "Int"), ActionFieldMeta("mount", "Boolean"))),
|
||||
ActionMeta("GarageItemsState", GarageItemsState::class, listOf(ActionFieldMeta("itemsByBase", "Any?"))),
|
||||
ActionMeta("GarageItemsState", GarageItemsState::class, listOf(ActionFieldMeta("itemsByBase", "Map<Long, GarageBaseItems>"))),
|
||||
ActionMeta("GarageObject", GarageObject::class, listOf(ActionFieldMeta("temperatureCC", "Any?"))),
|
||||
ActionMeta("Garage", Garage::class, listOf(ActionFieldMeta("itemsOnDepot", "Any?"), ActionFieldMeta("itemsOnMarket", "Any?"), ActionFieldMeta("mountedItems", "Any?"), ActionFieldMeta("skinsItems", "Any?"), ActionFieldMeta("items", "Any?"), ActionFieldMeta("devices", "Any?"), ActionFieldMeta("garageObject", "Any?"), ActionFieldMeta("isLoaded", "Boolean"), ActionFieldMeta("currentCategory", "Any?"), ActionFieldMeta("currentItemId", "Any?"), ActionFieldMeta("selectAlterationId", "Any?"), ActionFieldMeta("selectedSkinId", "Any?"), ActionFieldMeta("selectedShotSkinId", "Any?"), ActionFieldMeta("newItems", "Any?"), ActionFieldMeta("resistanceReadyToMount", "Any?"), ActionFieldMeta("delayMountTimeMs", "Any?"), ActionFieldMeta("cooldownReduceEndTime", "Any?"), ActionFieldMeta("timeToReduceUpdateInMin", "Any?"), ActionFieldMeta("currentRarity", "Any?"), ActionFieldMeta("purchaseOfUpgradesShopItemId", "Any?"), ActionFieldMeta("garageDiscountNotification", "Any?"), ActionFieldMeta("showVideoInDescription", "Any?"), ActionFieldMeta("unlockedProtectionSlots", "Any?"), ActionFieldMeta("pricesToUnlockSlot", "Any?"), ActionFieldMeta("numberRowsInPaintsUI", "Any?"), ActionFieldMeta("overdriveDescriptions", "Any?"), ActionFieldMeta("weaponToResistanceModule", "Any?"), ActionFieldMeta("waitServerItemMount", "Any?"), ActionFieldMeta("bazookaToSupply", "Any?"), ActionFieldMeta("upgradeCoolDownEndTimes", "Any?"), ActionFieldMeta("upgradeItemInProcessingId", "Any?"))),
|
||||
ActionMeta("AddItemToOrderProcessing", AddItemToOrderProcessing::class, listOf(ActionFieldMeta("itemId", "Any?"), ActionFieldMeta("onSuccess", "Any?"))),
|
||||
ActionMeta("RequestItem3DPart", RequestItem3DPart::class, listOf(ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("GarageUpgradeItemAction", GarageUpgradeItemAction::class, listOf(ActionFieldMeta("itemId", "Any?"), ActionFieldMeta("expectedPrice", "Any?"), ActionFieldMeta("currency", "Any?"))),
|
||||
ActionMeta("GarageSelectItem", GarageSelectItem::class, listOf(ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("GarageUpgradeItemAction", GarageUpgradeItemAction::class, listOf(ActionFieldMeta("itemId", "Long"), ActionFieldMeta("expectedPrice", "Any?"), ActionFieldMeta("currency", "Any?"))),
|
||||
ActionMeta("GarageSelectItem", GarageSelectItem::class, listOf(ActionFieldMeta("itemId", "Long"))),
|
||||
ActionMeta("GarageBuyResistanceModule", GarageBuyResistanceModule::class, listOf(ActionFieldMeta("resistance", "Any?"))),
|
||||
ActionMeta("GarageItemBought", GarageItemBought::class, listOf(ActionFieldMeta("item", "Any?"), ActionFieldMeta("count", "Int"), ActionFieldMeta("select", "Any?"))),
|
||||
ActionMeta("GarageItemMounted", GarageItemMounted::class, listOf(ActionFieldMeta("item", "Any?"), ActionFieldMeta("needServerMount", "Boolean"))),
|
||||
ActionMeta("GarageResistanceUnMount", GarageResistanceUnMount::class, listOf(ActionFieldMeta("resistance", "Any?"), ActionFieldMeta("needServerUnmount", "Boolean"))),
|
||||
ActionMeta("GarageResistanceUnMount", GarageResistanceUnMount::class, listOf(ActionFieldMeta("resistance", "Long"), ActionFieldMeta("needServerUnmount", "Boolean"))),
|
||||
ActionMeta("GarageResistanceMount", GarageResistanceMount::class, listOf(ActionFieldMeta("resistance", "Any?"), ActionFieldMeta("index", "Any?"))),
|
||||
ActionMeta("BuyProtectionSlot", BuyProtectionSlot::class, listOf(ActionFieldMeta("slotToUnlock", "Any?"))),
|
||||
ActionMeta("BuyProtectionSlot", BuyProtectionSlot::class, listOf(ActionFieldMeta("slotToUnlock", "Int"))),
|
||||
ActionMeta("SetItemRarity", SetItemRarity::class, listOf(ActionFieldMeta("rarity", "Any?"))),
|
||||
ActionMeta("SwitchingRowsScroll", SwitchingRowsScroll::class, listOf(ActionFieldMeta("numberRowsInPaintsUI", "Int"))),
|
||||
ActionMeta("BuyGarageKit", BuyGarageKit::class, listOf(ActionFieldMeta("item", "Any?"))),
|
||||
ActionMeta("GarageSelectAlteration", GarageSelectAlteration::class, listOf(ActionFieldMeta("alterationId", "Any?"))),
|
||||
ActionMeta("GarageSelectSkin", GarageSelectSkin::class, listOf(ActionFieldMeta("skinId", "Any?"))),
|
||||
ActionMeta("GarageSelectShotSkin", GarageSelectShotSkin::class, listOf(ActionFieldMeta("shotSkinId", "Any?"))),
|
||||
ActionMeta("GarageSelectAlteration", GarageSelectAlteration::class, listOf(ActionFieldMeta("alterationId", "Long"))),
|
||||
ActionMeta("GarageSelectSkin", GarageSelectSkin::class, listOf(ActionFieldMeta("skinId", "Long"))),
|
||||
ActionMeta("GarageSelectShotSkin", GarageSelectShotSkin::class, listOf(ActionFieldMeta("shotSkinId", "Long"))),
|
||||
ActionMeta("GarageLoadAvailableDevices", GarageLoadAvailableDevices::class, listOf(ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("RemoveFromFavoriteItem", RemoveFromFavoriteItem::class, listOf(ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("AddToFavoriteItem", AddToFavoriteItem::class, listOf(ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("RemoveFromFavoriteItem", RemoveFromFavoriteItem::class, listOf(ActionFieldMeta("itemId", "Long"))),
|
||||
ActionMeta("AddToFavoriteItem", AddToFavoriteItem::class, listOf(ActionFieldMeta("itemId", "Long"))),
|
||||
ActionMeta("GoToGarageAndSelectItem", GoToGarageAndSelectItem::class, listOf(ActionFieldMeta("category", "Int"), ActionFieldMeta("itemId", "Long"))),
|
||||
ActionMeta("AddRelatedBazooka", AddRelatedBazooka::class, listOf(ActionFieldMeta("bazookaId", "Long"), ActionFieldMeta("supplyId", "Long"))),
|
||||
ActionMeta("GarageUpgradeItemConfirm", GarageUpgradeItemConfirm::class, listOf(ActionFieldMeta("itemId", "Long"), ActionFieldMeta("level", "Int"))),
|
||||
ActionMeta("GarageDevicesLoadedAction", GarageDevicesLoadedAction::class, listOf(ActionFieldMeta("baseItemId", "Long"), ActionFieldMeta("devices", "List<GarageDeviceObject>"), ActionFieldMeta("mountedDevice", "List<String>?"))),
|
||||
ActionMeta("GarageDevicesLoadedAction", GarageDevicesLoadedAction::class, listOf(ActionFieldMeta("baseItemId", "Long"), ActionFieldMeta("devices", "List<GarageDeviceObject>"), ActionFieldMeta("mountedDevice", "GarageDevice?"))),
|
||||
ActionMeta("SetRestrictionMount", SetRestrictionMount::class, listOf(ActionFieldMeta("delayMs", "Int"))),
|
||||
ActionMeta("SetGarageSkinsAction", SetGarageSkinsAction::class, listOf(ActionFieldMeta("skins", "List<GarageItemObject>"))),
|
||||
ActionMeta("GarageRemoveItemFromStore", GarageRemoveItemFromStore::class, listOf(ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("GarageRemoveItemFromStore", GarageRemoveItemFromStore::class, listOf(ActionFieldMeta("itemId", "Long"))),
|
||||
ActionMeta("GarageUpdateDepotItem", GarageUpdateDepotItem::class, listOf(ActionFieldMeta("itemId", "Int"), ActionFieldMeta("count", "Int"))),
|
||||
ActionMeta("GarageApplyResistanceMount", GarageApplyResistanceMount::class, listOf(ActionFieldMeta("resistance", "Any?"), ActionFieldMeta("index", "Any?"), ActionFieldMeta("needServerMount", "Boolean"))),
|
||||
ActionMeta("GarageApplyResistanceMount", GarageApplyResistanceMount::class, listOf(ActionFieldMeta("resistance", "GarageItem"), ActionFieldMeta("index", "Int"), ActionFieldMeta("needServerMount", "Boolean"))),
|
||||
ActionMeta("GarageApplyResistanceMountOnBuy", GarageApplyResistanceMountOnBuy::class, listOf(ActionFieldMeta("resistance", "Any?"), ActionFieldMeta("index", "Any?"), ActionFieldMeta("currency", "Any?"))),
|
||||
ActionMeta("RemoveItemFromOrderProcessing", RemoveItemFromOrderProcessing::class, listOf(ActionFieldMeta("itemId", "Any?"), ActionFieldMeta("success", "Boolean"))),
|
||||
ActionMeta("AddOverdriveDescription", AddOverdriveDescription::class, listOf(ActionFieldMeta("itemId", "Long"), ActionFieldMeta("descriptionData", "OverdriveDescriptionData"))),
|
||||
ActionMeta("AddRelatedResistanceModule", AddRelatedResistanceModule::class, listOf(ActionFieldMeta("itemId", "Long"), ActionFieldMeta("resistanceModuleId", "Long"))),
|
||||
ActionMeta("GarageUpgradeItemCoolDownStarted", GarageUpgradeItemCoolDownStarted::class, listOf(ActionFieldMeta("itemId", "Any?"), ActionFieldMeta("endTime", "Any?"))),
|
||||
ActionMeta("GarageUpgradeItemCoolDownFinished", GarageUpgradeItemCoolDownFinished::class, listOf(ActionFieldMeta("itemId", "Any?"), ActionFieldMeta("endTime", "Any?"))),
|
||||
ActionMeta("RemoveFromSale", RemoveFromSale::class, listOf(ActionFieldMeta("removeItems", "Any?"))),
|
||||
ActionMeta("GarageUpdateItemCount", GarageUpdateItemCount::class, listOf(ActionFieldMeta("item", "Any?"), ActionFieldMeta("count", "Any?"))),
|
||||
ActionMeta("GarageRemoveItemFromDepot", GarageRemoveItemFromDepot::class, listOf(ActionFieldMeta("item", "Any?"))),
|
||||
ActionMeta("GarageAddItemToDepot", GarageAddItemToDepot::class, listOf(ActionFieldMeta("itemId", "Any?"), ActionFieldMeta("count", "Any?"))),
|
||||
ActionMeta("GarageUpgradeItemCoolDownStarted", GarageUpgradeItemCoolDownStarted::class, listOf(ActionFieldMeta("itemId", "Long"), ActionFieldMeta("endTime", "Long"))),
|
||||
ActionMeta("GarageUpgradeItemCoolDownFinished", GarageUpgradeItemCoolDownFinished::class, listOf(ActionFieldMeta("itemId", "Long"), ActionFieldMeta("endTime", "Long"))),
|
||||
ActionMeta("RemoveFromSale", RemoveFromSale::class, listOf(ActionFieldMeta("removeItems", "Collection<Long>"))),
|
||||
ActionMeta("GarageUpdateItemCount", GarageUpdateItemCount::class, listOf(ActionFieldMeta("item", "GarageItem"), ActionFieldMeta("count", "Int"))),
|
||||
ActionMeta("GarageRemoveItemFromDepot", GarageRemoveItemFromDepot::class, listOf(ActionFieldMeta("item", "GarageItemObject"))),
|
||||
ActionMeta("GarageAddItemToDepot", GarageAddItemToDepot::class, listOf(ActionFieldMeta("itemId", "Long"), ActionFieldMeta("count", "Int"))),
|
||||
ActionMeta("ItemPurchaseData", ItemPurchaseData::class, listOf(ActionFieldMeta("isAvailable", "Boolean"), ActionFieldMeta("item", "Any?"), ActionFieldMeta("amount", "Any?"), ActionFieldMeta("priceWithoutDiscount", "Any?"), ActionFieldMeta("priceWithDiscount", "Any?"), ActionFieldMeta("discountInPercent", "Any?"), ActionFieldMeta("discountEndTime", "Any?"), ActionFieldMeta("isSellingForCrystal", "Boolean"), ActionFieldMeta("isSellingForCoin", "Boolean"), ActionFieldMeta("isSellingForRuby", "Boolean"), ActionFieldMeta("isAvailableByCrystals", "Boolean"), ActionFieldMeta("isAvailableByCoins", "Boolean"), ActionFieldMeta("isAvailableByRubies", "Boolean"), ActionFieldMeta("isAvailableByRank", "Boolean"), ActionFieldMeta("minRank", "Any?"), ActionFieldMeta("isAvailableByPremium", "Boolean"))),
|
||||
ActionMeta("OverdriveDescriptionData", OverdriveDescriptionData::class, listOf(ActionFieldMeta("name", "Any?"), ActionFieldMeta("icon", "Any?"), ActionFieldMeta("description", "Any?"))),
|
||||
ActionMeta("GarageLoadDevicesIfNotLoaded", GarageLoadDevicesIfNotLoaded::class, listOf(ActionFieldMeta("item", "Any?"))),
|
||||
ActionMeta("GarageRemoveDevice", GarageRemoveDevice::class, listOf(ActionFieldMeta("device", "Any?"), ActionFieldMeta("item", "Any?"))),
|
||||
ActionMeta("GarageInsertDeviceClientAndServer", GarageInsertDeviceClientAndServer::class, listOf(ActionFieldMeta("device", "Any?"), ActionFieldMeta("item", "Any?"))),
|
||||
ActionMeta("GarageRemoveDevice", GarageRemoveDevice::class, listOf(ActionFieldMeta("device", "GarageDevice"), ActionFieldMeta("item", "GarageItem"))),
|
||||
ActionMeta("GarageInsertDeviceClientAndServer", GarageInsertDeviceClientAndServer::class, listOf(ActionFieldMeta("device", "GarageDevice"), ActionFieldMeta("item", "GarageItem"))),
|
||||
ActionMeta("GarageBuyAndInsertDevice", GarageBuyAndInsertDevice::class, listOf(ActionFieldMeta("device", "Any?"), ActionFieldMeta("price", "Any?"), ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("GarageBuyDevice", GarageBuyDevice::class, listOf(ActionFieldMeta("device", "Any?"), ActionFieldMeta("item", "Any?"), ActionFieldMeta("currency", "Any?"), ActionFieldMeta("mount", "Boolean"))),
|
||||
ActionMeta("GarageDeviceTrySetInfinityLifetime", GarageDeviceTrySetInfinityLifetime::class, listOf(ActionFieldMeta("deviceId", "Any?"))),
|
||||
ActionMeta("GarageRemoveDiscountForDevice", GarageRemoveDiscountForDevice::class, listOf(ActionFieldMeta("item", "Any?"))),
|
||||
ActionMeta("Devices", Devices::class, listOf(ActionFieldMeta("baseItemIdToDevices", "Any?"))),
|
||||
ActionMeta("GarageDevice", GarageDevice::class, listOf(ActionFieldMeta("id", "Any?"), ActionFieldMeta("baseItemId", "Any?"), ActionFieldMeta("installed", "Boolean"), ActionFieldMeta("name", "Any?"), ActionFieldMeta("category", "Int"), ActionFieldMeta("viewCategory", "Int"), ActionFieldMeta("priceWithoutDiscount", "Int"), ActionFieldMeta("description", "Any?"), ActionFieldMeta("descriptionMedia", "Any?"), ActionFieldMeta("previewImage", "Any?"), ActionFieldMeta("isPremium", "Boolean"), ActionFieldMeta("position", "Int"), ActionFieldMeta("minRank", "Int"), ActionFieldMeta("maxRank", "Int"), ActionFieldMeta("discount", "Int"), ActionFieldMeta("timeDiscountEnd", "Any?"), ActionFieldMeta("timeDiscountToStart", "Any?"), ActionFieldMeta("infinityLifetimeItem", "Boolean"), ActionFieldMeta("lifeTimeInSec", "Int"), ActionFieldMeta("property", "String"), ActionFieldMeta("properties", "Any?"), ActionFieldMeta("isSellingForCoin", "Boolean"), ActionFieldMeta("isSellingForCrystal", "Boolean"), ActionFieldMeta("isSellingForRuby", "Boolean"), ActionFieldMeta("isSellingForADS", "Boolean"), ActionFieldMeta("isSellingForMoney", "Boolean"), ActionFieldMeta("rarity", "Any?"), ActionFieldMeta("visible", "Boolean"), ActionFieldMeta("secret", "Boolean"), ActionFieldMeta("buyable", "Boolean"))),
|
||||
ActionMeta("GarageBuyDevice", GarageBuyDevice::class, listOf(ActionFieldMeta("device", "GarageDevice"), ActionFieldMeta("item", "GarageItem"), ActionFieldMeta("currency", "Any?"), ActionFieldMeta("mount", "Boolean"))),
|
||||
ActionMeta("GarageDeviceTrySetInfinityLifetime", GarageDeviceTrySetInfinityLifetime::class, listOf(ActionFieldMeta("deviceId", "Long"))),
|
||||
ActionMeta("GarageRemoveDiscountForDevice", GarageRemoveDiscountForDevice::class, listOf(ActionFieldMeta("item", "GarageItem"))),
|
||||
ActionMeta("Devices", Devices::class, listOf(ActionFieldMeta("baseItemIdToDevices", "Map<Long, List<GarageDevice>>"))),
|
||||
ActionMeta("GarageDevice", GarageDevice::class, listOf(ActionFieldMeta("id", "Long"), ActionFieldMeta("baseItemId", "Long"), ActionFieldMeta("installed", "Boolean"), ActionFieldMeta("name", "Any?"), ActionFieldMeta("category", "Int"), ActionFieldMeta("viewCategory", "Int"), ActionFieldMeta("priceWithoutDiscount", "Int"), ActionFieldMeta("description", "Any?"), ActionFieldMeta("descriptionMedia", "Any?"), ActionFieldMeta("previewImage", "Any?"), ActionFieldMeta("isPremium", "Boolean"), ActionFieldMeta("position", "Int"), ActionFieldMeta("minRank", "Int"), ActionFieldMeta("maxRank", "Int"), ActionFieldMeta("discount", "Int"), ActionFieldMeta("timeDiscountEnd", "Any?"), ActionFieldMeta("timeDiscountToStart", "Any?"), ActionFieldMeta("infinityLifetimeItem", "Boolean"), ActionFieldMeta("lifeTimeInSec", "Int"), ActionFieldMeta("property", "String"), ActionFieldMeta("properties", "Any?"), ActionFieldMeta("isSellingForCoin", "Boolean"), ActionFieldMeta("isSellingForCrystal", "Boolean"), ActionFieldMeta("isSellingForRuby", "Boolean"), ActionFieldMeta("isSellingForADS", "Boolean"), ActionFieldMeta("isSellingForMoney", "Boolean"), ActionFieldMeta("rarity", "Any?"), ActionFieldMeta("visible", "Boolean"), ActionFieldMeta("secret", "Boolean"), ActionFieldMeta("buyable", "Boolean"))),
|
||||
ActionMeta("DescriptionAlteration", DescriptionAlteration::class, listOf(ActionFieldMeta("description", "Any?"), ActionFieldMeta("property", "String"))),
|
||||
ActionMeta("GarageDeviceObject", GarageDeviceObject::class, listOf(ActionFieldMeta("id", "Any?"), ActionFieldMeta("baseItemId", "Any?"), ActionFieldMeta("temporaryItemCC", "Any?"), ActionFieldMeta("description", "Any?"), ActionFieldMeta("item", "Any?"), ActionFieldMeta("isPremium", "Any?"), ActionFieldMeta("itemCategory", "Any?"), ActionFieldMeta("itemViewCategory", "Any?"), ActionFieldMeta("buyable", "Any?"), ActionFieldMeta("discount", "Any?"), ActionFieldMeta("timePeriod", "Any?"), ActionFieldMeta("deviceProperty", "Any?"), ActionFieldMeta("rarity", "Any?"), ActionFieldMeta("visible", "Any?"), ActionFieldMeta("descriptionMedia", "Any?"))),
|
||||
ActionMeta("GarageDeviceObject", GarageDeviceObject::class, listOf(ActionFieldMeta("id", "Long"), ActionFieldMeta("baseItemId", "Long"), ActionFieldMeta("temporaryItemCC", "Any?"), ActionFieldMeta("description", "Any?"), ActionFieldMeta("item", "Any?"), ActionFieldMeta("isPremium", "Boolean"), ActionFieldMeta("itemCategory", "Int"), ActionFieldMeta("itemViewCategory", "Int"), ActionFieldMeta("buyable", "Boolean"), ActionFieldMeta("discount", "Any?"), ActionFieldMeta("timePeriod", "Any?"), ActionFieldMeta("deviceProperty", "Any?"), ActionFieldMeta("rarity", "Any?"), ActionFieldMeta("visible", "Boolean"), ActionFieldMeta("descriptionMedia", "Any?"))),
|
||||
ActionMeta("UpgradableItemParams", UpgradableItemParams::class, listOf(ActionFieldMeta("itemPropertyParams", "Any?"), ActionFieldMeta("properties", "Any?"), ActionFieldMeta("currentLevel", "Int"), ActionFieldMeta("upgradeParams", "Any?"), ActionFieldMeta("upgradeDiscount", "Int"), ActionFieldMeta("upgradeConfirmed", "Any?"))),
|
||||
ActionMeta("ItemPropertyParams", ItemPropertyParams::class, listOf(ActionFieldMeta("sortIndex", "Int"), ActionFieldMeta("name", "Any?"), ActionFieldMeta("properties", "Any?"), ActionFieldMeta("aggregationMode", "Any?"), ActionFieldMeta("multiplier", "Any?"), ActionFieldMeta("additiveShift", "Any?"), ActionFieldMeta("isKernelProperty", "Boolean"), ActionFieldMeta("unitName", "Any?"))),
|
||||
ActionMeta("GaragePreview", GaragePreview::class, listOf(ActionFieldMeta("isVisible", "Any?"), ActionFieldMeta("photoMode", "Any?"), ActionFieldMeta("needVisible", "Any?"), ActionFieldMeta("viewStyle", "Any?"), ActionFieldMeta("dynViewStyle", "Any?"), ActionFieldMeta("tankPreviewSettings", "Any?"), ActionFieldMeta("needShowDrone", "Any?"), ActionFieldMeta("params", "Any?"), ActionFieldMeta("hullData", "Any?"), ActionFieldMeta("weaponData", "Any?"), ActionFieldMeta("droneData", "Any?"), ActionFieldMeta("grenadeData", "Any?"), ActionFieldMeta("hasGrenades", "Any?"), ActionFieldMeta("hullEngineType", "Any?"), ActionFieldMeta("turretMechanism", "Any?"), ActionFieldMeta("paint", "Any?"), ActionFieldMeta("properties", "Any?"), ActionFieldMeta("captureScreenshotAction", "Any?"), ActionFieldMeta("captureVideoAction", "Any?"), ActionFieldMeta("item3dModelActionCache", "Any?"), ActionFieldMeta("requestedItems", "Any?"), ActionFieldMeta("expectedItemId", "Any?"))),
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// GarageModels.kt —— garage 切片里没有 toString 的嵌套模型(原 module_10032)
|
||||
//
|
||||
// 证据链:
|
||||
// · PB = GarageItemsState(`function PB(t){ this.or9_1 = t === cd ? ag() : t }`),
|
||||
// `or9_1` 是 Map<baseItemId, iB>。iB 没有 toString(`function iB(t){ this.xrb_1 = wm(t, QL(tB)) … }`),
|
||||
// 保存一组 aB(GarageItem) 并按首项派生出 owned/mounted/selected/position/… 等只读字段。
|
||||
// 这里保留 reducer 真正用到的部分:Items 列表 + Selected/HasOwned/HasMounted。
|
||||
// · aB 的派生字段:
|
||||
// urb_1 = modification?.vcf_1 ?: id (baseItemId,见 aB 构造 5342–5344)
|
||||
// trb_1 = hasDeviceSale && owned (见 aB 构造 5341)
|
||||
// GarageItem 由 gen_action_kt.js 生成,派生值用扩展函数计算。
|
||||
// · qra_1(modification)来自另一模块,只有 vcf_1(baseItemId) 与 xcf_1(level) 被本切片使用。
|
||||
package App.State
|
||||
|
||||
/** 原 `aB.qra_1`:改装/等级信息。字段名与运行时对象一致(vcf_1 / xcf_1)。 */
|
||||
data class GarageItemModification(
|
||||
val vcf_1: Long? = null,
|
||||
val xcf_1: Int = 0,
|
||||
)
|
||||
|
||||
/** 原 `iB`:同一个 baseItemId 下的一组 GarageItem。 */
|
||||
data class GarageBaseItems(
|
||||
val Items: List<GarageItem> = emptyList(),
|
||||
) {
|
||||
/** 原 `arc_1`:第一个已拥有项;没有则第一项。 */
|
||||
val Selected: GarageItem? get() = Items.firstOrNull { it.owned } ?: Items.firstOrNull()
|
||||
|
||||
/** 原 `yrb_1`:组内是否有已拥有项。 */
|
||||
val HasOwned: Boolean get() = Items.any { it.owned }
|
||||
|
||||
/** 原 `zrb_1`:组内是否有已装配项。 */
|
||||
val HasMounted: Boolean get() = Items.any { it.mounted }
|
||||
|
||||
/** 原 `iB.orc(i)`:按下标取项(原包直接 `g1(i)`,越界会抛)。 */
|
||||
fun At(Index: Int): GarageItem = Items[Index]
|
||||
|
||||
/** 原 `iB.krc(id, fn)`:按 id 替换一项。 */
|
||||
fun Replace(ItemId: Long, F: (GarageItem) -> GarageItem): GarageBaseItems =
|
||||
copy(Items = Items.map { if (it.id == ItemId) F(it) else it })
|
||||
|
||||
/** 原 `iB.lrc(fn)`:整组映射。 */
|
||||
fun MapAll(F: (GarageItem) -> GarageItem): GarageBaseItems =
|
||||
copy(Items = Items.map(F))
|
||||
}
|
||||
@@ -5,7 +5,7 @@ package App.State
|
||||
|
||||
import Core.Vector3
|
||||
|
||||
// 动作/状态类共 816 个,字段 2150 个(已定类型 511 个)
|
||||
// 动作/状态类共 816 个,字段 2150 个(已定类型 567 个)
|
||||
data class AnnouncementState(
|
||||
val isEnabled: Any?, // 仅 copy 转发(无类型信息)
|
||||
val modelLoaded: Any?, // 仅 copy 转发(无类型信息)
|
||||
@@ -1445,11 +1445,11 @@ data class Discount(
|
||||
)
|
||||
|
||||
data class UpdateDiscount(
|
||||
val item: Any?, // 调用点: HL(t).paq_1.dpv_1.yq5_1.rr9(t.gr9_1)
|
||||
val item: GarageItem, // override
|
||||
)
|
||||
|
||||
data class GarageItem(
|
||||
val id: Any?, // 调用点: h | t
|
||||
val id: Long, // override
|
||||
val name: Any?, // 调用点: c | n
|
||||
val category: Int, // dataflow
|
||||
val viewCategory: Int, // dataflow
|
||||
@@ -1466,10 +1466,10 @@ data class GarageItem(
|
||||
val minRank: Int, // dataflow
|
||||
val maxRank: Int, // dataflow
|
||||
val discount: Any?, // 调用点: y | w
|
||||
val modification: Any?, // 调用点: $ | d
|
||||
val modification: GarageItemModification?, // override
|
||||
val properties: Any?, // 调用点: R | g
|
||||
val upgradeableParams: Any?, // 调用点: M | m
|
||||
val count: Any?, // 调用点: O | k
|
||||
val upgradeableParams: UpgradableItemParams?, // override
|
||||
val count: Int, // override
|
||||
val kit: Any?, // 调用点: D | z
|
||||
val countable: Any?, // 调用点: L | b
|
||||
val hasDeviceSale: Boolean, // dataflow
|
||||
@@ -1506,21 +1506,21 @@ data class Kit(
|
||||
)
|
||||
|
||||
data class GarageItemObject(
|
||||
val id: Any?, // 调用点: t | o
|
||||
val id: Long, // override
|
||||
val description: Any?, // 调用点: n | _
|
||||
val item: Any?, // 调用点: i | h
|
||||
val isPremium: Any?, // 调用点: r | a
|
||||
val itemCategory: Any?, // 调用点: e | c
|
||||
val itemViewCategory: Any?, // 调用点: u | l
|
||||
val buyable: Any?, // 调用点: s | f
|
||||
val availableForAll: Any?, // 调用点: o | v
|
||||
val isPremium: Boolean, // override
|
||||
val itemCategory: Int, // override
|
||||
val itemViewCategory: Int, // override
|
||||
val buyable: Boolean, // override
|
||||
val availableForAll: Boolean, // override
|
||||
val discount: Any?, // 调用点: _ | w
|
||||
val timePeriod: Any?, // 调用点: h | k
|
||||
val modification: Any?, // 调用点: a | d
|
||||
val modification: GarageItemModification?, // override
|
||||
val properties: Any?, // 调用点: c | g
|
||||
val upgradeableParams: Any?, // 调用点: l | m
|
||||
val upgradeableParams: UpgradableItemParams?, // override
|
||||
val devices: Any?, // 调用点: f | z
|
||||
val count: Any?, // 调用点: v | y
|
||||
val count: Int, // override
|
||||
val kit: Any?, // 调用点: p | $
|
||||
val countable: Any?, // 调用点: w | x
|
||||
val mountIndex: Any?, // 调用点: d | i
|
||||
@@ -1536,7 +1536,7 @@ data class GarageItemObject(
|
||||
val isSellingForCrystal: Any?, // 调用点: j | Ct
|
||||
val isSellingForRuby: Any?, // 调用点: S | Ct
|
||||
val resistanceBackgroundImg: Any?, // 调用点: C | H
|
||||
val visible: Any?, // 调用点: E | W
|
||||
val visible: Boolean, // override
|
||||
val descriptionMedia: Any?, // 调用点: T | V
|
||||
val saleByKitItems: Any?, // 调用点: I | K
|
||||
)
|
||||
@@ -1548,7 +1548,7 @@ data class KitItem(
|
||||
)
|
||||
|
||||
data class GarageItemsState(
|
||||
val itemsByBase: Any?, // 调用点: cg(this.or9_1, Vd(i, new iB(e))) | cg(c, Vd(t.urb_1, l))
|
||||
val itemsByBase: Map<Long, GarageBaseItems>, // override
|
||||
)
|
||||
|
||||
data class GarageObject(
|
||||
@@ -1599,13 +1599,13 @@ data class RequestItem3DPart(
|
||||
)
|
||||
|
||||
data class GarageUpgradeItemAction(
|
||||
val itemId: Any?, // 调用点: n.us1_1.zr9_1 | n.us1_1.zr9_1
|
||||
val itemId: Long, // override
|
||||
val expectedPrice: Any?, // 调用点: n.ws1_1 | n.xs1_1
|
||||
val currency: Any?, // 调用点: rB() | uB()
|
||||
)
|
||||
|
||||
data class GarageSelectItem(
|
||||
val itemId: Any?, // 调用点: n.zr9_1 | n.zr9_1
|
||||
val itemId: Long, // override
|
||||
)
|
||||
|
||||
data class GarageBuyResistanceModule(
|
||||
@@ -1624,7 +1624,7 @@ data class GarageItemMounted(
|
||||
)
|
||||
|
||||
data class GarageResistanceUnMount(
|
||||
val resistance: Any?, // 调用点: k | f
|
||||
val resistance: Long, // override
|
||||
val needServerUnmount: Boolean, // callsite
|
||||
)
|
||||
|
||||
@@ -1634,7 +1634,7 @@ data class GarageResistanceMount(
|
||||
)
|
||||
|
||||
data class BuyProtectionSlot(
|
||||
val slotToUnlock: Any?, // 调用点: s
|
||||
val slotToUnlock: Int, // override
|
||||
)
|
||||
|
||||
data class SetItemRarity(
|
||||
@@ -1650,15 +1650,15 @@ data class BuyGarageKit(
|
||||
)
|
||||
|
||||
data class GarageSelectAlteration(
|
||||
val alterationId: Any?, // 调用点: n.arh_1 | n.arh_1
|
||||
val alterationId: Long, // override
|
||||
)
|
||||
|
||||
data class GarageSelectSkin(
|
||||
val skinId: Any?, // 调用点: n.zr9_1 | null
|
||||
val skinId: Long, // override
|
||||
)
|
||||
|
||||
data class GarageSelectShotSkin(
|
||||
val shotSkinId: Any?, // 调用点: n.zr9_1 | null
|
||||
val shotSkinId: Long, // override
|
||||
)
|
||||
|
||||
data class GarageLoadAvailableDevices(
|
||||
@@ -1666,11 +1666,11 @@ data class GarageLoadAvailableDevices(
|
||||
)
|
||||
|
||||
data class RemoveFromFavoriteItem(
|
||||
val itemId: Any?, // 调用点: _
|
||||
val itemId: Long, // override
|
||||
)
|
||||
|
||||
data class AddToFavoriteItem(
|
||||
val itemId: Any?, // 调用点: _
|
||||
val itemId: Long, // override
|
||||
)
|
||||
|
||||
data class GoToGarageAndSelectItem(
|
||||
@@ -1691,7 +1691,7 @@ data class GarageUpgradeItemConfirm(
|
||||
data class GarageDevicesLoadedAction(
|
||||
val baseItemId: Long, // runtime
|
||||
val devices: List<GarageDeviceObject>, // runtime
|
||||
val mountedDevice: List<String>?, // runtime
|
||||
val mountedDevice: GarageDevice?, // override
|
||||
)
|
||||
|
||||
data class SetRestrictionMount(
|
||||
@@ -1703,7 +1703,7 @@ data class SetGarageSkinsAction(
|
||||
)
|
||||
|
||||
data class GarageRemoveItemFromStore(
|
||||
val itemId: Any?, // 调用点: t.x57()
|
||||
val itemId: Long, // override
|
||||
)
|
||||
|
||||
data class GarageUpdateDepotItem(
|
||||
@@ -1712,8 +1712,8 @@ data class GarageUpdateDepotItem(
|
||||
)
|
||||
|
||||
data class GarageApplyResistanceMount(
|
||||
val resistance: Any?, // 调用点: n | n
|
||||
val index: Any?, // 调用点: r._v | r._v
|
||||
val resistance: GarageItem, // override
|
||||
val index: Int, // override
|
||||
val needServerMount: Boolean, // callsite
|
||||
)
|
||||
|
||||
@@ -1739,31 +1739,31 @@ data class AddRelatedResistanceModule(
|
||||
)
|
||||
|
||||
data class GarageUpgradeItemCoolDownStarted(
|
||||
val itemId: Any?, // 调用点: e
|
||||
val endTime: Any?, // 调用点: i
|
||||
val itemId: Long, // override
|
||||
val endTime: Long, // override
|
||||
)
|
||||
|
||||
data class GarageUpgradeItemCoolDownFinished(
|
||||
val itemId: Any?, // 调用点: n
|
||||
val endTime: Any?, // 调用点: i
|
||||
val itemId: Long, // override
|
||||
val endTime: Long, // override
|
||||
)
|
||||
|
||||
data class RemoveFromSale(
|
||||
val removeItems: Any?, // 调用点: h | h
|
||||
val removeItems: Collection<Long>, // override
|
||||
)
|
||||
|
||||
data class GarageUpdateItemCount(
|
||||
val item: Any?, // 调用点: _
|
||||
val count: Any?, // 调用点: r
|
||||
val item: GarageItem, // override
|
||||
val count: Int, // override
|
||||
)
|
||||
|
||||
data class GarageRemoveItemFromDepot(
|
||||
val item: Any?, // 调用点: o.rrf(cd, cd, cd, cd, cd, cd, cd, cd, cd
|
||||
val item: GarageItemObject, // override
|
||||
)
|
||||
|
||||
data class GarageAddItemToDepot(
|
||||
val itemId: Any?, // 调用点: l.frd_1
|
||||
val count: Any?, // 调用点: r
|
||||
val itemId: Long, // override
|
||||
val count: Int, // override
|
||||
)
|
||||
|
||||
data class ItemPurchaseData(
|
||||
@@ -1796,13 +1796,13 @@ data class GarageLoadDevicesIfNotLoaded(
|
||||
)
|
||||
|
||||
data class GarageRemoveDevice(
|
||||
val device: Any?, // 调用点: f | e
|
||||
val item: Any?, // 调用点: u | t.zas_1.o1p8_1
|
||||
val device: GarageDevice, // override
|
||||
val item: GarageItem, // override
|
||||
)
|
||||
|
||||
data class GarageInsertDeviceClientAndServer(
|
||||
val device: Any?, // 调用点: n | n
|
||||
val item: Any?, // 调用点: t.zas_1.o1p8_1 | t.zas_1.z1pm_1
|
||||
val device: GarageDevice, // override
|
||||
val item: GarageItem, // override
|
||||
)
|
||||
|
||||
data class GarageBuyAndInsertDevice(
|
||||
@@ -1812,27 +1812,27 @@ data class GarageBuyAndInsertDevice(
|
||||
)
|
||||
|
||||
data class GarageBuyDevice(
|
||||
val device: Any?, // 调用点: e
|
||||
val item: Any?, // 调用点: u
|
||||
val device: GarageDevice, // override
|
||||
val item: GarageItem, // override
|
||||
val currency: Any?, // 调用点: o
|
||||
val mount: Boolean, // dataflow
|
||||
)
|
||||
|
||||
data class GarageDeviceTrySetInfinityLifetime(
|
||||
val deviceId: Any?, // 调用点: i
|
||||
val deviceId: Long, // override
|
||||
)
|
||||
|
||||
data class GarageRemoveDiscountForDevice(
|
||||
val item: Any?, // 调用点: u
|
||||
val item: GarageItem, // override
|
||||
)
|
||||
|
||||
data class Devices(
|
||||
val baseItemIdToDevices: Any?, // 调用点: i | cg(this.xrg_1, Vd(t, l))
|
||||
val baseItemIdToDevices: Map<Long, List<GarageDevice>>, // override
|
||||
)
|
||||
|
||||
data class GarageDevice(
|
||||
val id: Any?, // 调用点: e | t
|
||||
val baseItemId: Any?, // 调用点: u | n
|
||||
val id: Long, // override
|
||||
val baseItemId: Long, // override
|
||||
val installed: Boolean, // callsite
|
||||
val name: Any?, // 调用点: s | r
|
||||
val category: Int, // dataflow
|
||||
@@ -1869,20 +1869,20 @@ data class DescriptionAlteration(
|
||||
)
|
||||
|
||||
data class GarageDeviceObject(
|
||||
val id: Any?, // 调用点: h
|
||||
val baseItemId: Any?, // 调用点: i
|
||||
val id: Long, // override
|
||||
val baseItemId: Long, // override
|
||||
val temporaryItemCC: Any?, // 调用点: a
|
||||
val description: Any?, // 调用点: c
|
||||
val item: Any?, // 调用点: l
|
||||
val isPremium: Any?, // 调用点: f
|
||||
val itemCategory: Any?, // 调用点: v
|
||||
val itemViewCategory: Any?, // 调用点: p
|
||||
val buyable: Any?, // 调用点: w
|
||||
val isPremium: Boolean, // override
|
||||
val itemCategory: Int, // override
|
||||
val itemViewCategory: Int, // override
|
||||
val buyable: Boolean, // override
|
||||
val discount: Any?, // 调用点: d
|
||||
val timePeriod: Any?, // 调用点: g
|
||||
val deviceProperty: Any?, // 调用点: m
|
||||
val rarity: Any?, // 调用点: null == z ? Yr() : z
|
||||
val visible: Any?, // 调用点: Gr(_, Z(rx))
|
||||
val visible: Boolean, // override
|
||||
val descriptionMedia: Any?, // 调用点: Gr(_, Z(ox))
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,653 @@
|
||||
// GarageReducer.kt —— 车库切片(对应 module_10032 的 UB 状态 + hF reducer)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 UB:`function UB(t, n, i, r, e, u, s, o, _, h, a, c, l, f, v, p, w, d, g, m, k, z, b, q, y, $, x, j, S, C, E)`,
|
||||
// 31 个字段,toString 名为 `Garage(itemsOnDepot=…, …, upgradeItemInProcessingId=…)`。默认值取自构造:
|
||||
// itemsOnDepot/itemsOnMarket/mountedItems/skinsItems = Yg()(HashSet)、items = new PB()、
|
||||
// devices = new UF()、garageObject = null、isLoaded = false、currentCategory = BB().sq5_1、
|
||||
// currentItemId/selectAlterationId/selectedSkinId/selectedShotSkinId = null、newItems = ag()(emptyMap)、
|
||||
// resistanceReadyToMount = false、delayMountTimeMs/cooldownReduceEndTime = new Dd(0,0)(Long 0)、
|
||||
// timeToReduceUpdateInMin = 0、currentRarity = null、purchaseOfUpgradesShopItemId = new Dd(886599726,214)、
|
||||
// garageDiscountNotification = false、showVideoInDescription = true、unlockedProtectionSlots = 1、
|
||||
// pricesToUnlockSlot = md()(emptyList)、numberRowsInPaintsUI = 2、overdriveDescriptions = ag()、
|
||||
// weaponToResistanceModule = ag()、waitServerItemMount = ag()、bazookaToSupply = ag()、
|
||||
// upgradeCoolDownEndTimes = ag()、upgradeItemInProcessingId = null。
|
||||
//
|
||||
// 根委派:`i = hF(t, n)`(根 reducer 把整个状态传入具名 reducer,切片槽位 n.dpv_1 只在 hF 体内出现)。
|
||||
//
|
||||
// hF 顶层分支:58 个 `t instanceof <动作>` + 2 个“接口/单例”分支:
|
||||
// · `Xd(t, LF)`:NF = GarageInsertDeviceClientAndServer(LF 是标记接口,NF 实现它)
|
||||
// · `yd(t, Nu)`:xU 单例动作(无字段,效果是把 upgradeItemInProcessingId 置 null)
|
||||
// 其余 58 个分支与 slice_garage.json 一一对应;`FX` / `UB` 是屏幕/状态标识,不是动作。
|
||||
//
|
||||
// 嵌套模型:
|
||||
// PB = GarageItemsState(Map<baseItemId, iB>),iB 无 toString → 见 GarageModels.kt 的 GarageBaseItems。
|
||||
// UF = Devices(Map<baseItemId, List<VF>>),VF = GarageDevice。
|
||||
// 物品对象 fB = GarageItemObject;aB = GarageItem(生成物,45 字段)。
|
||||
// 关键派生:urb_1 = modification.vcf_1 ?: id;trb_1 = hasDeviceSale && owned。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.AddOverdriveDescription
|
||||
import App.State.AddRelatedBazooka
|
||||
import App.State.AddRelatedResistanceModule
|
||||
import App.State.AddToFavoriteItem
|
||||
import App.State.BuyProtectionSlot
|
||||
import App.State.Devices
|
||||
import App.State.GarageApplyResistanceMount
|
||||
import App.State.GarageAddItemToDepot
|
||||
import App.State.GarageBaseItems
|
||||
import App.State.GarageBuyDevice
|
||||
import App.State.GarageDevice
|
||||
import App.State.GarageDeviceObject
|
||||
import App.State.GarageDeviceTrySetInfinityLifetime
|
||||
import App.State.GarageDevicesLoadedAction
|
||||
import App.State.GarageInsertDeviceClientAndServer
|
||||
import App.State.GarageItem
|
||||
import App.State.GarageItemModification
|
||||
import App.State.GarageItemObject
|
||||
import App.State.GarageItemsState
|
||||
import App.State.GarageObject
|
||||
import App.State.GarageRemoveDevice
|
||||
import App.State.GarageRemoveDiscountForDevice
|
||||
import App.State.GarageRemoveItemFromDepot
|
||||
import App.State.GarageRemoveItemFromStore
|
||||
import App.State.GarageResistanceUnMount
|
||||
import App.State.GarageSelectAlteration
|
||||
import App.State.GarageSelectItem
|
||||
import App.State.GarageSelectShotSkin
|
||||
import App.State.GarageSelectSkin
|
||||
import App.State.GarageUpgradeItemAction
|
||||
import App.State.GarageUpgradeItemConfirm
|
||||
import App.State.GarageUpgradeItemCoolDownFinished
|
||||
import App.State.GarageUpgradeItemCoolDownStarted
|
||||
import App.State.GarageUpdateItemCount
|
||||
import App.State.GoTo
|
||||
import App.State.OverdriveDescriptionData
|
||||
import App.State.RemoveFromFavoriteItem
|
||||
import App.State.RemoveFromSale
|
||||
import App.State.SetGarageSkinsAction
|
||||
import App.State.SetItemRarity
|
||||
import App.State.SetRestrictionMount
|
||||
import App.State.SwitchingRowsScroll
|
||||
import App.State.UpdateDiscount
|
||||
import State.InitState
|
||||
import kotlin.js.Date
|
||||
|
||||
/** 原 `BB().sq5_1`:Garage 屏幕的默认分类。真实值由屏幕对象携带;S3 用 null 作为默认分类。 */
|
||||
val GarageDefaultCategory: Any? = null
|
||||
|
||||
/** 原 `nz()`:抵抗模块的等待装配键。原包是分类常量,这里用一个不会与普通 category 冲突的哨兵。 */
|
||||
const val GarageResistanceCategoryKey: Int = Int.MIN_VALUE
|
||||
|
||||
/* ------------------------------------------------------------------ 匿名动作 */
|
||||
// 原 rF:没有 toString / 不在 action_inventory。效果见 gen_root_wiring.js 的 GarageAnonymousEffects。
|
||||
class ResetGarage
|
||||
data class SetGarageObject(val garageObject: GarageObject?)
|
||||
data class SetItemsOnDepot(val items: Collection<GarageItemObject>)
|
||||
data class SetItemsOnMarket(val items: Collection<GarageItemObject>)
|
||||
data class SetMountedItems(val items: Collection<GarageItemObject>)
|
||||
class GarageLoaded
|
||||
class SetGarageNotLoaded
|
||||
data class SelectGarageCategory(val category: Any?)
|
||||
data class AddGarageItemCount(val item: GarageItem, val delta: Int)
|
||||
data class GarageMountItem(val item: GarageItem)
|
||||
data class GarageUnmountItem(val itemId: Long)
|
||||
data class GarageMountItems(val itemIds: Collection<Long>)
|
||||
data class SetMountedSkinForItems(val skinId: Long, val item: GarageItem)
|
||||
data class SetMountedShotSkinForItems(val shotSkinId: Long, val item: GarageItem)
|
||||
data class SetNewItems(val items: Map<Long, Set<Long>>)
|
||||
data class AddNewItem(val itemId: Long, val value: Long)
|
||||
data class RemoveNewItem(val itemId: Long, val value: Long)
|
||||
data class SetResistanceReadyToMount(val ready: Boolean)
|
||||
class ResetMountDelay
|
||||
data class StartCooldownReduce(val seconds: Int, val minutes: Int)
|
||||
data class SetCooldownReduceEndTime(val seconds: Int)
|
||||
class ShowGarageDiscountNotification
|
||||
class HideVideoInDescription
|
||||
data class RemoveWaitServerItemMount(val categories: Collection<Int>)
|
||||
class ClearWaitServerItemMount
|
||||
|
||||
/** 原 xU:`Nu = new xU()` 单例动作,效果只有 upgradeItemInProcessingId = null。 */
|
||||
class ClearUpgradeItemInProcessing
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class GarageStateSlice(
|
||||
val ItemsOnDepot: Collection<GarageItemObject> = emptySet(),
|
||||
val ItemsOnMarket: Collection<GarageItemObject> = emptySet(),
|
||||
val MountedItems: Collection<GarageItemObject> = emptySet(),
|
||||
val SkinsItems: Collection<GarageItemObject> = emptySet(),
|
||||
val Items: GarageItemsState = GarageItemsState(emptyMap()),
|
||||
val Devices: Devices = Devices(emptyMap()),
|
||||
val GarageObject: GarageObject? = null,
|
||||
val IsLoaded: Boolean = false,
|
||||
val CurrentCategory: Any? = GarageDefaultCategory,
|
||||
val CurrentItemId: Long? = null,
|
||||
val SelectAlterationId: Long? = null,
|
||||
val SelectedSkinId: Long? = null,
|
||||
val SelectedShotSkinId: Long? = null,
|
||||
val NewItems: Map<Long, Set<Long>> = emptyMap(),
|
||||
val ResistanceReadyToMount: Boolean = false,
|
||||
val DelayMountTimeMs: Long = 0L,
|
||||
val CooldownReduceEndTime: Long = 0L,
|
||||
val TimeToReduceUpdateInMin: Int = 0,
|
||||
val CurrentRarity: Any? = null,
|
||||
val PurchaseOfUpgradesShopItemId: Long = 920109776942L,
|
||||
val GarageDiscountNotification: Boolean = false,
|
||||
val ShowVideoInDescription: Boolean = true,
|
||||
val UnlockedProtectionSlots: Int = 1,
|
||||
val PricesToUnlockSlot: List<Any?> = emptyList(),
|
||||
val NumberRowsInPaintsUI: Int = 2,
|
||||
val OverdriveDescriptions: Map<Long, Any?> = emptyMap(),
|
||||
val WeaponToResistanceModule: Map<Long, Long> = emptyMap(),
|
||||
val WaitServerItemMount: Map<Int, Boolean> = emptyMap(),
|
||||
val BazookaToSupply: Map<Long, Long> = emptyMap(),
|
||||
val UpgradeCoolDownEndTimes: Map<Long, Long> = emptyMap(),
|
||||
val UpgradeItemInProcessingId: Long? = null,
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ 小工具 */
|
||||
|
||||
private fun ToLong(Value: Any?): Long? = when (Value) {
|
||||
is Long -> Value
|
||||
is Int -> Value.toLong()
|
||||
is Number -> Value.toLong()
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun ToInt(Value: Any?, Default: Int = 0): Int = when (Value) {
|
||||
is Int -> Value
|
||||
is Long -> Value.toInt()
|
||||
is Number -> Value.toInt()
|
||||
else -> Default
|
||||
}
|
||||
|
||||
private fun ToBool(Value: Any?): Boolean = Value == true
|
||||
|
||||
private fun NowMs(): Long = Date.now().toLong()
|
||||
|
||||
/** 原 `aB.urb_1`:modification.vcf_1 ?: id。 */
|
||||
internal fun GarageItem.BaseItemId(): Long = modification?.vcf_1 ?: id
|
||||
|
||||
/** 原 `aB.trb_1`:hasDeviceSale && owned。 */
|
||||
private fun GarageItem.HasDeviceSaleAndOwned(): Boolean = hasDeviceSale && owned
|
||||
|
||||
/* ------------------------------------------------------------------ GarageItemsState(PB) */
|
||||
|
||||
private val GarageItemsState.ItemById: Map<Long, GarageItem>
|
||||
get() = itemsByBase.values.flatMap { it.Items }.associateBy { it.id }
|
||||
|
||||
private fun GarageItemsState.Item(ItemId: Long): GarageItem =
|
||||
ItemById[ItemId] ?: error("GarageItemsState 里没有 item $ItemId")
|
||||
|
||||
private fun GarageItemsState.HasItem(ItemId: Long): Boolean = ItemById.containsKey(ItemId)
|
||||
|
||||
private fun GarageItemsState.GroupOf(Item: GarageItem): GarageBaseItems =
|
||||
itemsByBase[Item.BaseItemId()] ?: error("GarageItemsState 里没有 baseItemId ${Item.BaseItemId()}")
|
||||
|
||||
private fun GarageItemsState.UpdateGroup(BaseId: Long, Group: GarageBaseItems): GarageItemsState =
|
||||
copy(itemsByBase = itemsByBase + (BaseId to Group))
|
||||
|
||||
/** 原 `PB.rr9`:按 itemId 取项(原包用 Map.getValue,缺键会抛)。 */
|
||||
private fun GarageItemsState.ItemOrThrow(ItemId: Long): GarageItem = Item(ItemId)
|
||||
|
||||
/** 原 `PB.grg`:在 item 所属 base 组里按 id 替换一项。 */
|
||||
private fun GarageItemsState.ReplaceItem(Item: GarageItem, F: (GarageItem) -> GarageItem): GarageItemsState {
|
||||
val BaseId = Item.BaseItemId()
|
||||
val Group = itemsByBase[BaseId] ?: error("GarageItemsState 里没有 baseItemId $BaseId")
|
||||
return copy(itemsByBase = itemsByBase + (BaseId to Group.Replace(Item.id, F)))
|
||||
}
|
||||
|
||||
/** 原 `PB.jrg`:同一 viewCategory 内先卸下已装配项,再装配本项。 */
|
||||
private fun GarageItemsState.MountItem(Item: GarageItem): GarageItemsState {
|
||||
val SameCategory = itemsByBase.values.filter { Group ->
|
||||
Group.Items.any { it.viewCategory == Item.viewCategory }
|
||||
}
|
||||
val Mounted = SameCategory.flatMap { it.Items }.firstOrNull { it.mounted }
|
||||
var Result = this
|
||||
if (Mounted != null) {
|
||||
Result = Result.ReplaceItem(Mounted) { it.copy(mounted = false) }
|
||||
}
|
||||
return Result.ReplaceItem(Item) { it.copy(mounted = true) }
|
||||
}
|
||||
|
||||
/** 原 `PB.krg`:批量装配;先卸下同 viewCategory 的已装配项,再置 owned + mounted。 */
|
||||
private fun GarageItemsState.MountItems(ItemIds: Collection<Long>): GarageItemsState {
|
||||
val Items = ItemIds.map { ItemOrThrow(it) }
|
||||
val Categories = Items.map { it.viewCategory }.toSet()
|
||||
val Groups = itemsByBase.values.filter { Group ->
|
||||
Group.Items.any { it.viewCategory in Categories }
|
||||
}
|
||||
val Mounted = Groups.flatMap { it.Items }.filter { it.mounted }
|
||||
var Result = this
|
||||
for (M in Mounted) Result = Result.ReplaceItem(M) { it.copy(mounted = false) }
|
||||
for (I in Items) Result = Result.ReplaceItem(I) { it.copy(owned = true, mounted = true) }
|
||||
return Result
|
||||
}
|
||||
|
||||
/** 原 `PB.mrg`:卸下单项。 */
|
||||
private fun GarageItemsState.UnmountItem(ItemId: Long): GarageItemsState =
|
||||
ReplaceItem(ItemOrThrow(ItemId)) { it.copy(mounted = false) }
|
||||
|
||||
/** 原 `PB.lrg`:装配抵抗模块;先检查 unlockedProtectionSlots。 */
|
||||
private fun GarageItemsState.MountResistance(
|
||||
State: GarageStateSlice,
|
||||
Item: GarageItem,
|
||||
Index: Int,
|
||||
): GarageItemsState {
|
||||
val MountedCount = itemsByBase.values
|
||||
.flatMap { it.Items }
|
||||
.count { it.mounted && it.viewCategory == Item.viewCategory }
|
||||
if (MountedCount >= State.UnlockedProtectionSlots) {
|
||||
error("已装配抵抗模块数 $MountedCount 超过 unlockedProtectionSlots ${State.UnlockedProtectionSlots}")
|
||||
}
|
||||
return ReplaceItem(Item) { it.copy(mounted = true, mountIndex = Index) }
|
||||
}
|
||||
|
||||
/** 原 `PB.qrg`:整组 mountedSkin = skinId。 */
|
||||
private fun GarageItemsState.SetGroupMountedSkin(SkinId: Long, Item: GarageItem): GarageItemsState {
|
||||
val Group = GroupOf(Item)
|
||||
return UpdateGroup(Item.BaseItemId(), Group.MapAll { it.copy(mountedSkin = SkinId) })
|
||||
}
|
||||
|
||||
/** 原 `PB.rrg`:整组 mountedShotSkin = skinId。 */
|
||||
private fun GarageItemsState.SetGroupMountedShotSkin(SkinId: Long, Item: GarageItem): GarageItemsState {
|
||||
val Group = GroupOf(Item)
|
||||
return UpdateGroup(Item.BaseItemId(), Group.MapAll { it.copy(mountedShotSkin = SkinId) })
|
||||
}
|
||||
|
||||
/** 原 `PB.srg`:把给定 baseItemId 集合里的所有项 buyable 置 false。 */
|
||||
private fun GarageItemsState.RemoveFromSale(BaseIds: Collection<Long>): GarageItemsState {
|
||||
val Set = BaseIds.toSet()
|
||||
var Result = this
|
||||
for ((BaseId, Group) in itemsByBase) {
|
||||
if (BaseId in Set) {
|
||||
Result = Result.UpdateGroup(BaseId, Group.MapAll { it.copy(buyable = false) })
|
||||
}
|
||||
}
|
||||
return Result
|
||||
}
|
||||
|
||||
/** 原 `PB.trg`:置 owned=true、count=n。 */
|
||||
private fun GarageItemsState.SetOwnedCount(Item: GarageItem, Count: Int): GarageItemsState =
|
||||
ReplaceItem(Item) { it.copy(owned = true, count = Count) }
|
||||
|
||||
/* ------------------------------------------------------------------ Devices(UF) */
|
||||
|
||||
private fun Devices.UpdateByIds(Ids: Set<Long>, F: (GarageDevice) -> GarageDevice): Devices =
|
||||
copy(baseItemIdToDevices = baseItemIdToDevices.mapValues { (_, List) ->
|
||||
List.map { if (it.id in Ids) F(it) else it }
|
||||
})
|
||||
|
||||
/** 原 `UF.frn`:去掉同组里旧 id 的项,再追加从 GarageDeviceObject 转换出的新项。 */
|
||||
private fun Devices.LoadDevices(
|
||||
BaseItemId: Long,
|
||||
Objects: List<GarageDeviceObject>,
|
||||
MountedDevice: GarageDevice?,
|
||||
): Devices {
|
||||
val NewIds = Objects.map { it.id }.toSet()
|
||||
val Old = baseItemIdToDevices[BaseItemId].orEmpty().filter { it.id !in NewIds }
|
||||
val Converted = Objects.map { DeviceFromObject(it, MountedDevice?.id == it.id) }
|
||||
return copy(baseItemIdToDevices = baseItemIdToDevices + (BaseItemId to (Old + Converted)))
|
||||
}
|
||||
|
||||
private fun DeviceFromObject(Object: GarageDeviceObject, Installed: Boolean): GarageDevice =
|
||||
GarageDevice(
|
||||
id = Object.id,
|
||||
baseItemId = Object.baseItemId,
|
||||
installed = Installed,
|
||||
name = Object.description?.toString() ?: "",
|
||||
category = Object.itemCategory,
|
||||
viewCategory = Object.itemViewCategory,
|
||||
priceWithoutDiscount = 0,
|
||||
description = Object.description,
|
||||
descriptionMedia = Object.descriptionMedia,
|
||||
previewImage = Object.item,
|
||||
isPremium = Object.isPremium,
|
||||
position = 0,
|
||||
minRank = 0,
|
||||
maxRank = 0,
|
||||
discount = ToInt(Object.discount),
|
||||
timeDiscountEnd = null,
|
||||
timeDiscountToStart = null,
|
||||
infinityLifetimeItem = false,
|
||||
lifeTimeInSec = 0,
|
||||
property = Object.deviceProperty?.toString() ?: "",
|
||||
properties = emptyList<Any?>(),
|
||||
isSellingForCoin = false,
|
||||
isSellingForCrystal = false,
|
||||
isSellingForRuby = false,
|
||||
isSellingForADS = false,
|
||||
isSellingForMoney = false,
|
||||
rarity = Object.rarity,
|
||||
visible = Object.visible,
|
||||
secret = false,
|
||||
buyable = Object.buyable,
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ 物品对象 → GarageItem */
|
||||
|
||||
private fun GarageItemObject.ToGarageItem(Owned: Boolean, Mounted: Boolean): GarageItem =
|
||||
GarageItem(
|
||||
id = id,
|
||||
name = description?.toString() ?: "",
|
||||
category = itemCategory,
|
||||
viewCategory = itemViewCategory,
|
||||
priceWithoutDiscount = 0,
|
||||
description = description,
|
||||
descriptionMedia = descriptionMedia,
|
||||
preview = item,
|
||||
isPremium = isPremium,
|
||||
owned = Owned,
|
||||
mountable = false,
|
||||
mounted = Mounted,
|
||||
mountIndex = mountIndex,
|
||||
position = 0,
|
||||
minRank = 0,
|
||||
maxRank = 0,
|
||||
discount = discount,
|
||||
modification = modification,
|
||||
properties = properties,
|
||||
upgradeableParams = upgradeableParams,
|
||||
count = count,
|
||||
kit = kit,
|
||||
countable = ToBool(countable),
|
||||
hasDeviceSale = false,
|
||||
devicesAvailable = devices != null,
|
||||
devicePreview = null,
|
||||
buyable = buyable,
|
||||
availableForAll = availableForAll,
|
||||
availableSkins = availableSkins,
|
||||
availableShotSkins = availableShotSkins,
|
||||
mountedSkin = mountedSkin,
|
||||
mountedShotSkin = mountedShotSkin,
|
||||
skinPreview = skinPreview,
|
||||
group = grouped,
|
||||
rarity = rarity,
|
||||
favorite = favorite,
|
||||
resistanceBackgroundImg = resistanceBackgroundImg,
|
||||
visible = visible,
|
||||
secret = false,
|
||||
saleByKitItems = saleByKitItems,
|
||||
isSellingForCoin = ToBool(isSellingForCoin),
|
||||
isSellingForCrystal = ToBool(isSellingForCrystal),
|
||||
isSellingForRuby = ToBool(isSellingForRuby),
|
||||
isSellingForMoney = false,
|
||||
isSellingForADS = false,
|
||||
)
|
||||
|
||||
/** 原 `eF`:按 depot / mounted / market / skins 四个物品对象集合重建 PB。 */
|
||||
private fun RebuildItems(State: GarageStateSlice): GarageItemsState {
|
||||
val All = LinkedHashMap<Long, GarageItem>()
|
||||
for (Object in State.ItemsOnDepot) All[Object.id] = Object.ToGarageItem(Owned = true, Mounted = false)
|
||||
for (Object in State.MountedItems) All[Object.id] = Object.ToGarageItem(Owned = true, Mounted = true)
|
||||
for (Object in State.ItemsOnMarket) All[Object.id] = Object.ToGarageItem(Owned = false, Mounted = false)
|
||||
for (Object in State.SkinsItems) All[Object.id] = Object.ToGarageItem(Owned = false, Mounted = false)
|
||||
val Grouped = All.values.groupBy { it.BaseItemId() }.mapValues { GarageBaseItems(it.value) }
|
||||
return GarageItemsState(Grouped)
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
fun ReduceGarage(State0: GarageStateSlice, Action: Any): GarageStateSlice = when (Action) {
|
||||
is InitState -> {
|
||||
// 原:if (t.zap_1.equals(og(UB))) { var h = t.aaq_1(o); _ = h instanceof UB ? h : wd() }
|
||||
// InitState(type, action) 里的 action 是「当前状态 → 新状态」的函数。
|
||||
if (Action.type == GarageStateSlice::class) {
|
||||
val Result = when (val F = Action.action) {
|
||||
is Function1<*, *> -> @Suppress("UNCHECKED_CAST") (F as (GarageStateSlice) -> Any?)(State0)
|
||||
is Function0<*> -> (F as () -> Any?)()
|
||||
else -> null
|
||||
}
|
||||
Result as? GarageStateSlice ?: State0
|
||||
} else State0
|
||||
}
|
||||
|
||||
is ResetGarage -> State0.copy(
|
||||
Devices = Devices(emptyMap()),
|
||||
UpgradeCoolDownEndTimes = emptyMap(),
|
||||
UpgradeItemInProcessingId = null,
|
||||
)
|
||||
|
||||
is SetGarageObject -> State0.copy(GarageObject = Action.garageObject)
|
||||
is SetItemsOnDepot -> State0.copy(ItemsOnDepot = Action.items)
|
||||
is SetItemsOnMarket -> State0.copy(ItemsOnMarket = Action.items)
|
||||
is SetMountedItems -> State0.copy(MountedItems = Action.items)
|
||||
is SetGarageSkinsAction -> State0.copy(SkinsItems = Action.skins)
|
||||
|
||||
is GarageLoaded -> State0.copy(Items = RebuildItems(State0), IsLoaded = true)
|
||||
is SetGarageNotLoaded -> State0.copy(IsLoaded = false)
|
||||
|
||||
is SelectGarageCategory -> State0.copy(CurrentCategory = Action.category, CurrentItemId = null)
|
||||
is GarageSelectItem -> State0.copy(CurrentItemId = Action.itemId)
|
||||
|
||||
is AddGarageItemCount -> {
|
||||
val Item = Action.item
|
||||
val Level = Item.modification?.xcf_1 ?: 0
|
||||
val Index = if (Level > 0) Level - 1 else 0
|
||||
val Preview = State0.Items.GroupOf(Item).Items.getOrNull(Index)?.devicePreview
|
||||
State0.copy(
|
||||
Items = State0.Items.ReplaceItem(Item) {
|
||||
it.copy(
|
||||
owned = true,
|
||||
count = it.count + Action.delta,
|
||||
devicePreview = Preview,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
is GarageUpdateItemCount ->
|
||||
State0.copy(Items = State0.Items.ReplaceItem(Action.item) { it.copy(count = Action.count) })
|
||||
|
||||
is GarageMountItem -> State0.copy(
|
||||
Items = State0.Items.MountItem(Action.item),
|
||||
WaitServerItemMount = State0.WaitServerItemMount + (Action.item.category to true),
|
||||
)
|
||||
|
||||
is GarageUnmountItem ->
|
||||
State0.copy(Items = State0.Items.UnmountItem(Action.itemId))
|
||||
|
||||
is GarageMountItems ->
|
||||
State0.copy(Items = State0.Items.MountItems(Action.itemIds))
|
||||
|
||||
is SetMountedSkinForItems ->
|
||||
State0.copy(Items = State0.Items.SetGroupMountedSkin(Action.skinId, Action.item))
|
||||
|
||||
is SetMountedShotSkinForItems ->
|
||||
State0.copy(Items = State0.Items.SetGroupMountedShotSkin(Action.shotSkinId, Action.item))
|
||||
|
||||
is GarageApplyResistanceMount -> State0.copy(
|
||||
Items = State0.Items.MountResistance(State0, Action.resistance, Action.index),
|
||||
// 原 WU 分支:`cg(o.vq6_1, new Km(nz(), !0))`,键是抵抗模块分类哨兵,不是物品 category。
|
||||
WaitServerItemMount = State0.WaitServerItemMount + (GarageResistanceCategoryKey to true),
|
||||
)
|
||||
|
||||
is GarageResistanceUnMount -> State0.copy(
|
||||
Items = State0.Items.UnmountItem(Action.resistance),
|
||||
WaitServerItemMount = State0.WaitServerItemMount + (GarageResistanceCategoryKey to true),
|
||||
)
|
||||
|
||||
is GarageUpgradeItemAction -> {
|
||||
val Item = State0.Items.ItemOrThrow(Action.itemId)
|
||||
State0.copy(
|
||||
Items = State0.Items.ReplaceItem(Item) {
|
||||
val Params = it.upgradeableParams
|
||||
it.copy(
|
||||
upgradeableParams = Params?.copy(
|
||||
currentLevel = Params.currentLevel + 1,
|
||||
upgradeConfirmed = false,
|
||||
) ?: Params,
|
||||
)
|
||||
},
|
||||
UpgradeItemInProcessingId = Action.itemId,
|
||||
)
|
||||
}
|
||||
|
||||
is GarageUpgradeItemCoolDownStarted -> State0.copy(
|
||||
UpgradeCoolDownEndTimes = State0.UpgradeCoolDownEndTimes + (Action.itemId to Action.endTime),
|
||||
)
|
||||
|
||||
is GarageUpgradeItemCoolDownFinished ->
|
||||
if (State0.UpgradeCoolDownEndTimes[Action.itemId] == Action.endTime) {
|
||||
State0.copy(UpgradeCoolDownEndTimes = State0.UpgradeCoolDownEndTimes - Action.itemId)
|
||||
} else State0
|
||||
|
||||
is GarageUpgradeItemConfirm -> {
|
||||
val Item = State0.Items.ItemOrThrow(Action.itemId)
|
||||
val Confirmed = if (State0.UpgradeItemInProcessingId == Action.itemId) null else State0.UpgradeItemInProcessingId
|
||||
State0.copy(
|
||||
Items = State0.Items.ReplaceItem(Item) {
|
||||
val Params = it.upgradeableParams
|
||||
it.copy(
|
||||
upgradeableParams = Params?.copy(
|
||||
upgradeConfirmed = Params.upgradeConfirmed == true || Params.currentLevel == Action.level,
|
||||
) ?: Params,
|
||||
)
|
||||
},
|
||||
UpgradeItemInProcessingId = Confirmed,
|
||||
)
|
||||
}
|
||||
|
||||
is ClearUpgradeItemInProcessing -> State0.copy(UpgradeItemInProcessingId = null)
|
||||
|
||||
is GarageDevicesLoadedAction -> State0.copy(
|
||||
Devices = State0.Devices.LoadDevices(Action.baseItemId, Action.devices, Action.mountedDevice),
|
||||
)
|
||||
|
||||
is GarageRemoveDevice -> State0.copy(
|
||||
Items = State0.Items.ReplaceItem(Action.item) { it.copy(devicePreview = null) },
|
||||
Devices = State0.Devices.UpdateByIds(setOf(Action.device.id)) { it.copy(installed = false) },
|
||||
)
|
||||
|
||||
is GarageInsertDeviceClientAndServer -> State0.copy(
|
||||
Items = State0.Items.ReplaceItem(Action.item) {
|
||||
it.copy(devicePreview = Action.device.previewImage)
|
||||
},
|
||||
Devices = State0.Devices.UpdateByIds(setOf(Action.device.id)) { it.copy(installed = true) },
|
||||
)
|
||||
|
||||
is GarageBuyDevice -> State0.copy(
|
||||
Items = State0.Items.ReplaceItem(Action.item) {
|
||||
it.copy(devicePreview = Action.device.previewImage)
|
||||
},
|
||||
Devices = State0.Devices.UpdateByIds(setOf(Action.device.id)) {
|
||||
it.copy(installed = Action.mount, infinityLifetimeItem = true)
|
||||
},
|
||||
)
|
||||
|
||||
is GarageDeviceTrySetInfinityLifetime -> State0.copy(
|
||||
Devices = State0.Devices.UpdateByIds(setOf(Action.deviceId)) {
|
||||
it.copy(infinityLifetimeItem = true)
|
||||
},
|
||||
)
|
||||
|
||||
is GarageSelectAlteration -> State0.copy(SelectAlterationId = Action.alterationId)
|
||||
is GarageSelectSkin -> State0.copy(SelectedSkinId = Action.skinId)
|
||||
is GarageSelectShotSkin -> State0.copy(SelectedShotSkinId = Action.shotSkinId)
|
||||
|
||||
is GarageRemoveDiscountForDevice -> State0.copy(
|
||||
Items = State0.Items.ReplaceItem(Action.item) {
|
||||
it.copy(hasDeviceSale = it.HasDeviceSaleAndOwned())
|
||||
},
|
||||
)
|
||||
|
||||
is UpdateDiscount -> State0.copy(
|
||||
// 原 zF 只把 discount 换成同一对象的副本(重新计算时间窗),字段值不变。
|
||||
Items = State0.Items.ReplaceItem(Action.item) { it.copy(discount = it.discount) },
|
||||
)
|
||||
|
||||
is GarageAddItemToDepot -> State0.copy(
|
||||
Items = State0.Items.SetOwnedCount(State0.Items.ItemOrThrow(Action.itemId), Action.count),
|
||||
)
|
||||
|
||||
is GarageRemoveItemFromDepot -> State0.copy(
|
||||
Items = State0.Items.ReplaceItem(State0.Items.ItemOrThrow(Action.item.id)) {
|
||||
it.copy(owned = false, count = Action.item.count)
|
||||
},
|
||||
)
|
||||
|
||||
is GarageRemoveItemFromStore -> State0.copy(
|
||||
Items = State0.Items.ReplaceItem(State0.Items.ItemOrThrow(Action.itemId)) {
|
||||
it.copy(buyable = false)
|
||||
},
|
||||
)
|
||||
|
||||
is SetNewItems -> State0.copy(NewItems = Action.items)
|
||||
|
||||
is AddNewItem -> {
|
||||
val Existing = State0.NewItems[Action.itemId].orEmpty()
|
||||
State0.copy(NewItems = State0.NewItems + (Action.itemId to (Existing + Action.value)))
|
||||
}
|
||||
|
||||
is RemoveNewItem -> {
|
||||
val Existing = State0.NewItems[Action.itemId].orEmpty() - Action.value
|
||||
State0.copy(
|
||||
NewItems = if (Existing.isEmpty()) State0.NewItems - Action.itemId
|
||||
else State0.NewItems + (Action.itemId to Existing),
|
||||
)
|
||||
}
|
||||
|
||||
is SetResistanceReadyToMount -> State0.copy(ResistanceReadyToMount = Action.ready)
|
||||
is RemoveFromSale -> State0.copy(Items = State0.Items.RemoveFromSale(Action.removeItems))
|
||||
is SetRestrictionMount -> State0.copy(
|
||||
DelayMountTimeMs = if (Action.delayMs > 0) NowMs() + Action.delayMs else 0L,
|
||||
)
|
||||
|
||||
is ResetMountDelay -> State0.copy(DelayMountTimeMs = 0L)
|
||||
|
||||
is StartCooldownReduce -> State0.copy(
|
||||
CooldownReduceEndTime = NowMs() + Action.seconds * 1000L,
|
||||
TimeToReduceUpdateInMin = Action.minutes,
|
||||
)
|
||||
|
||||
is SetCooldownReduceEndTime -> State0.copy(
|
||||
CooldownReduceEndTime = NowMs() + Action.seconds * 1000L,
|
||||
)
|
||||
|
||||
is SetItemRarity -> State0.copy(CurrentRarity = Action.rarity)
|
||||
|
||||
is AddToFavoriteItem -> State0.copy(
|
||||
Items = State0.Items.ReplaceItem(State0.Items.ItemOrThrow(Action.itemId)) {
|
||||
it.copy(favorite = true)
|
||||
},
|
||||
)
|
||||
|
||||
is RemoveFromFavoriteItem -> State0.copy(
|
||||
Items = State0.Items.ReplaceItem(State0.Items.ItemOrThrow(Action.itemId)) {
|
||||
it.copy(favorite = false)
|
||||
},
|
||||
)
|
||||
|
||||
is GoTo -> {
|
||||
// 原:if (Tk(t.grm_1).equals(og(FX))) return o.hri(…, Y.irm_1); 否则 i = o
|
||||
if (Action.screen.name == "Garage") {
|
||||
State0.copy(CurrentCategory = GarageDefaultCategory)
|
||||
} else State0
|
||||
}
|
||||
|
||||
is ShowGarageDiscountNotification -> State0.copy(GarageDiscountNotification = true)
|
||||
is HideVideoInDescription -> State0.copy(ShowVideoInDescription = false)
|
||||
is BuyProtectionSlot -> State0.copy(UnlockedProtectionSlots = State0.UnlockedProtectionSlots + 1)
|
||||
is SwitchingRowsScroll -> State0.copy(NumberRowsInPaintsUI = Action.numberRowsInPaintsUI)
|
||||
|
||||
is AddOverdriveDescription -> State0.copy(
|
||||
OverdriveDescriptions = State0.OverdriveDescriptions + (Action.itemId to Action.descriptionData),
|
||||
)
|
||||
|
||||
is AddRelatedResistanceModule -> State0.copy(
|
||||
WeaponToResistanceModule = State0.WeaponToResistanceModule + (Action.itemId to Action.resistanceModuleId),
|
||||
)
|
||||
|
||||
is AddRelatedBazooka -> State0.copy(
|
||||
BazookaToSupply = State0.BazookaToSupply + (Action.bazookaId to Action.supplyId),
|
||||
)
|
||||
|
||||
is RemoveWaitServerItemMount -> State0.copy(
|
||||
WaitServerItemMount = State0.WaitServerItemMount + Action.categories.map { it to false },
|
||||
)
|
||||
|
||||
is ClearWaitServerItemMount -> State0.copy(WaitServerItemMount = emptyMap())
|
||||
|
||||
else -> State0
|
||||
}
|
||||
@@ -11,12 +11,14 @@
|
||||
// shop → ReduceShop(j4 / `(inline@shop)` 分支)
|
||||
// screen → ReduceScreen(WK / dY().ks5)
|
||||
// lootBoxes → ReduceLootBoxes(aH / EH.wrv)
|
||||
// garage → ReduceGarage(UB / hF,根委派 `i = hF(t, n)`)
|
||||
//
|
||||
// 其余 81 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 其余 80 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
||||
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
||||
package App.State
|
||||
|
||||
import App.State.Reducers.ReduceGarage
|
||||
import App.State.Reducers.ReduceHome
|
||||
import App.State.Reducers.ReduceInvite
|
||||
import App.State.Reducers.ReduceLocalBattleUser
|
||||
@@ -47,6 +49,7 @@ object RootReducer {
|
||||
Shop = ReduceShop(State0.Shop, Action),
|
||||
Screen = ReduceScreen(State0.Screen, Action),
|
||||
LootBoxes = ReduceLootBoxes(State0.LootBoxes, Action),
|
||||
Garage = ReduceGarage(State0.Garage, Action),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// 已迁移的切片用强类型;其余保持 Any?(原样透传),迁移一个改一个再重新生成。
|
||||
package App.State
|
||||
|
||||
import App.State.Reducers.GarageStateSlice
|
||||
import App.State.Reducers.HomeStateSlice
|
||||
import App.State.Reducers.InviteStateSlice
|
||||
import App.State.Reducers.LocalBattleUserStateSlice
|
||||
@@ -28,8 +29,8 @@ data class RootState(
|
||||
val BattleStatistics: Any? = null,
|
||||
/** 原 battleTutorial(rE / Q.sq8)。未迁移:原样透传。 */
|
||||
val BattleTutorial: Any? = null,
|
||||
/** 原 garage(UB / hF)。未迁移:原样透传。 */
|
||||
val Garage: Any? = null,
|
||||
/** 原 garage(UB / hF)。已迁移。 */
|
||||
val Garage: GarageStateSlice = GarageStateSlice(),
|
||||
/** 原 garagePreview(IG / fs.eru)。未迁移:原样透传。 */
|
||||
val GaragePreview: Any? = null,
|
||||
/** 原 challenges(CZ / nh.hsj)。未迁移:原样透传。 */
|
||||
|
||||
@@ -19,7 +19,7 @@ object RootWiring {
|
||||
SliceWiring("modalScreen", "apv_1", "nV", "Fs.js1", "Fs.js1(t, n.apv_1)", listOf("?XW", "AddModal", "RemoveCurrentByName", "RemoveModal")),
|
||||
SliceWiring("battleStatistics", "bpv_1", "jR", "rr.fqr", "rr.fqr(t, n.bpv_1)", listOf("?DR", "?HR", "?KR", "?PR", "?QR", "?UR", "?XR", "?YR", "?ZR", "?nP", "?tP", "Init", "InitBattleModeWithLevels", "SetBattleMode", "SetDisplayClientInfo", "SetFlagOrBallOwner", "SetRankRange", "SetReArmor", "SetRemainingTime", "SetRoundRestartTime", "UpdateFund", "UpdateScore")),
|
||||
SliceWiring("battleTutorial", "cpv_1", "rE", "Q.sq8", "Q.sq8(t, n.cpv_1)", listOf("?oE", "?sE", "SetFragsCount", "ShowMessage")),
|
||||
SliceWiring("garage", "dpv_1", "UB", "hF", "hF(t, n)", listOf("?EU", "?FB", "?FX", "?JB", "?MU", "?NU", "?OU", "?PU", "?QU", "?RU", "?SU", "?VB", "?WB", "?aF", "?bU", "?cF", "?dU", "?eF", "?fF", "?iU", "?lF", "?pF", "?rF", "?vF", "?wU", "?yU", "AddOverdriveDescription", "AddRelatedBazooka", "AddRelatedResistanceModule", "AddToFavoriteItem", "BuyProtectionSlot", "Garage", "GarageAddItemToDepot", "GarageApplyResistanceMount", "GarageBuyDevice", "GarageDeviceTrySetInfinityLifetime", "GarageDevicesLoadedAction", "GarageRemoveDevice", "GarageRemoveDiscountForDevice", "GarageRemoveItemFromDepot", "GarageRemoveItemFromStore", "GarageResistanceUnMount", "GarageSelectAlteration", "GarageSelectItem", "GarageSelectShotSkin", "GarageSelectSkin", "GarageUpdateItemCount", "GarageUpgradeItemAction", "GarageUpgradeItemConfirm", "GarageUpgradeItemCoolDownFinished", "GarageUpgradeItemCoolDownStarted", "GoTo", "InitState", "RemoveFromFavoriteItem", "RemoveFromSale", "SetGarageSkinsAction", "SetItemRarity", "SetRestrictionMount", "SwitchingRowsScroll", "UpdateDiscount")),
|
||||
SliceWiring("garage", "dpv_1", "UB", "hF", "hF(t, n)", listOf("AddGarageItemCount", "AddNewItem", "AddOverdriveDescription", "AddRelatedBazooka", "AddRelatedResistanceModule", "AddToFavoriteItem", "BuyProtectionSlot", "ClearWaitServerItemMount", "GarageAddItemToDepot", "GarageApplyResistanceMount", "GarageBuyDevice", "GarageDeviceTrySetInfinityLifetime", "GarageDevicesLoadedAction", "GarageLoaded", "GarageMountItem", "GarageMountItems", "GarageRemoveDevice", "GarageRemoveDiscountForDevice", "GarageRemoveItemFromDepot", "GarageRemoveItemFromStore", "GarageResistanceUnMount", "GarageSelectAlteration", "GarageSelectItem", "GarageSelectShotSkin", "GarageSelectSkin", "GarageUnmountItem", "GarageUpdateItemCount", "GarageUpgradeItemAction", "GarageUpgradeItemConfirm", "GarageUpgradeItemCoolDownFinished", "GarageUpgradeItemCoolDownStarted", "GoTo", "HideVideoInDescription", "InitState", "RemoveFromFavoriteItem", "RemoveFromSale", "RemoveNewItem", "RemoveWaitServerItemMount", "ResetGarage", "ResetMountDelay", "SelectGarageCategory", "SetCooldownReduceEndTime", "SetGarageNotLoaded", "SetGarageObject", "SetGarageSkinsAction", "SetItemRarity", "SetItemsOnDepot", "SetItemsOnMarket", "SetMountedItems", "SetMountedShotSkinForItems", "SetMountedSkinForItems", "SetNewItems", "SetResistanceReadyToMount", "SetRestrictionMount", "ShowGarageDiscountNotification", "StartCooldownReduce", "SwitchingRowsScroll", "UpdateDiscount")),
|
||||
SliceWiring("garagePreview", "epv_1", "IG", "fs.eru", "fs.eru(t, n.epv_1)", listOf("?BG", "?JG", "?KG", "?OG", "?QG", "?UG", "?VG", "?XG", "?YG", "?ZG", "?nH", "?tH", "AddRequestedItem", "InitGarageResources", "ResetItem3dModelActionCache", "SetCaptureActions", "SetDrone", "SetExpectedItemId", "SetMountedItemsProperties", "SetPaint", "ShowRequest", "UpdatePreviewSettings")),
|
||||
SliceWiring("challenges", "fpv_1", "CZ", "nh.hsj", "nh.hsj(t, n.fpv_1)", listOf("?LZ", "RemoveChallenge", "SetBattlePass", "SetBattlePassPackages", "SetChallenge", "SetRewardForDialog", "SetTakenBattlePassRewardIndex", "SetTakenFreeRewardIndex", "UpdateStars")),
|
||||
SliceWiring("loginByPassword", "gpv_1", "gD", "nu.cr6", "nu.cr6(t, n.gpv_1)", listOf("?ND", "?PD", "?RD", "IncorrectLogin2FA", "RequestsNumber2FA", "SetLogin", "SetPassword", "SetRememberMe", "SetStatus")),
|
||||
@@ -106,7 +106,7 @@ object RootWiring {
|
||||
)
|
||||
|
||||
/** 已迁移(由 RootReducer 真正归约)的字段。 */
|
||||
val Migrated: Set<String> = setOf("inviteState", "loginByPassword", "twitchState", "home", "localBattleUserState", "shop", "screen", "lootBoxes")
|
||||
val Migrated: Set<String> = setOf("inviteState", "loginByPassword", "twitchState", "home", "localBattleUserState", "shop", "screen", "lootBoxes", "garage")
|
||||
|
||||
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
||||
val Unmigrated: List<SliceWiring> get() = All.filter { it.Field !in Migrated }
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// ⑥ 动作目录:816 个类与 138 个真实派发名对齐
|
||||
// ⑦ 回放:真实 toString 样例的类/字段/类型校验
|
||||
// ⑧ 全目录动作类都能按 KClass 路由
|
||||
// ⑨~⑱ 切片 reducer:InviteState / LoginByPasswordState / TwitchState / HomeScreen / LocalBattleUserState /
|
||||
// Shop(含 U7 类别表与 w3 物品表两个子 reducer)/ Screen / LootBoxes;⑭ 根 reducer 的 89 槽位委派
|
||||
// ⑨~⑲ 切片 reducer:InviteState / LoginByPasswordState / TwitchState / HomeScreen / LocalBattleUserState /
|
||||
// Shop(含 U7 类别表与 w3 物品表两个子 reducer)/ Screen / LootBoxes / Garage;⑭ 根 reducer 的 89 槽位委派
|
||||
//
|
||||
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
||||
package App
|
||||
@@ -166,6 +166,80 @@ import App.State.Reducers.SetIsBlockOpenButtons
|
||||
import App.State.Reducers.SetIsReopening
|
||||
import App.State.Reducers.SetPeriodOfGiveLootBox
|
||||
import App.State.Reducers.SetTimeToGiveLootBox
|
||||
import App.State.Devices
|
||||
import App.State.AddRelatedBazooka
|
||||
import App.State.AddRelatedResistanceModule
|
||||
import App.State.AddToFavoriteItem
|
||||
import App.State.AddOverdriveDescription
|
||||
import App.State.BuyProtectionSlot
|
||||
import App.State.GarageAddItemToDepot
|
||||
import App.State.GarageApplyResistanceMount
|
||||
import App.State.GarageBaseItems
|
||||
import App.State.GarageBuyDevice
|
||||
import App.State.GarageDevice
|
||||
import App.State.GarageDeviceObject
|
||||
import App.State.GarageDeviceTrySetInfinityLifetime
|
||||
import App.State.GarageDevicesLoadedAction
|
||||
import App.State.GarageInsertDeviceClientAndServer
|
||||
import App.State.GarageItem
|
||||
import App.State.GarageItemModification
|
||||
import App.State.GarageItemObject
|
||||
import App.State.GarageItemsState
|
||||
import App.State.GarageObject
|
||||
import App.State.GarageRemoveDevice
|
||||
import App.State.GarageRemoveDiscountForDevice
|
||||
import App.State.GarageRemoveItemFromDepot
|
||||
import App.State.GarageRemoveItemFromStore
|
||||
import App.State.GarageResistanceUnMount
|
||||
import App.State.GarageSelectAlteration
|
||||
import App.State.GarageSelectItem
|
||||
import App.State.GarageSelectShotSkin
|
||||
import App.State.GarageSelectSkin
|
||||
import App.State.GarageUpdateItemCount
|
||||
import App.State.GarageUpgradeItemAction
|
||||
import App.State.GarageUpgradeItemConfirm
|
||||
import App.State.GarageUpgradeItemCoolDownFinished
|
||||
import App.State.GarageUpgradeItemCoolDownStarted
|
||||
import App.State.OverdriveDescriptionData
|
||||
import App.State.RemoveFromFavoriteItem
|
||||
import App.State.RemoveFromSale
|
||||
import App.State.SetGarageSkinsAction
|
||||
import App.State.SetItemRarity
|
||||
import App.State.SetRestrictionMount
|
||||
import App.State.SwitchingRowsScroll
|
||||
import App.State.UpdateDiscount
|
||||
import App.State.UpgradableItemParams
|
||||
import App.State.Reducers.AddGarageItemCount
|
||||
import App.State.Reducers.AddNewItem
|
||||
import App.State.Reducers.ClearUpgradeItemInProcessing
|
||||
import App.State.Reducers.ClearWaitServerItemMount
|
||||
import App.State.Reducers.GarageDefaultCategory
|
||||
import App.State.Reducers.GarageLoaded
|
||||
import App.State.Reducers.GarageMountItem
|
||||
import App.State.Reducers.GarageMountItems
|
||||
import App.State.Reducers.GarageResistanceCategoryKey
|
||||
import App.State.Reducers.GarageStateSlice
|
||||
import App.State.Reducers.GarageUnmountItem
|
||||
import App.State.Reducers.HideVideoInDescription
|
||||
import App.State.Reducers.ReduceGarage
|
||||
import App.State.Reducers.RemoveNewItem
|
||||
import App.State.Reducers.RemoveWaitServerItemMount
|
||||
import App.State.Reducers.ResetGarage
|
||||
import App.State.Reducers.ResetMountDelay
|
||||
import App.State.Reducers.SelectGarageCategory
|
||||
import App.State.Reducers.SetCooldownReduceEndTime
|
||||
import App.State.Reducers.SetGarageNotLoaded
|
||||
import App.State.Reducers.SetGarageObject
|
||||
import App.State.Reducers.SetItemsOnDepot
|
||||
import App.State.Reducers.SetItemsOnMarket
|
||||
import App.State.Reducers.SetMountedItems
|
||||
import App.State.Reducers.SetMountedShotSkinForItems
|
||||
import App.State.Reducers.SetMountedSkinForItems
|
||||
import App.State.Reducers.SetNewItems
|
||||
import App.State.Reducers.SetResistanceReadyToMount
|
||||
import App.State.Reducers.ShowGarageDiscountNotification
|
||||
import App.State.Reducers.StartCooldownReduce
|
||||
import State.InitState
|
||||
|
||||
private data class AddFrags(val fragsCount: Int)
|
||||
private data class SetScreen(val screen: String)
|
||||
@@ -539,7 +613,7 @@ object StateCheck {
|
||||
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
||||
}
|
||||
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 八个已迁移切片一次归约
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 九个已迁移切片一次归约
|
||||
run {
|
||||
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
||||
Check(
|
||||
@@ -603,13 +677,13 @@ object StateCheck {
|
||||
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
||||
)
|
||||
Check(
|
||||
"根:迁移表 = 八个已迁移字段,其余 81 个待迁",
|
||||
"根:迁移表 = 九个已迁移字段,其余 80 个待迁",
|
||||
RootReducer.Migrated ==
|
||||
setOf(
|
||||
"inviteState", "loginByPassword", "twitchState", "home",
|
||||
"localBattleUserState", "shop", "screen", "lootBoxes",
|
||||
"localBattleUserState", "shop", "screen", "lootBoxes", "garage",
|
||||
) &&
|
||||
RootWiring.Unmigrated.size == 81
|
||||
RootWiring.Unmigrated.size == 80
|
||||
)
|
||||
|
||||
// 一次 ReduceRoot 里八个切片各归约自己的动作,互不串片
|
||||
@@ -665,7 +739,7 @@ object StateCheck {
|
||||
S5.User == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
||||
)
|
||||
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 8/89")
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 9/89")
|
||||
|
||||
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
||||
Store.Dispatch(SetStatus("LOGGING_IN"))
|
||||
@@ -1252,6 +1326,634 @@ object StateCheck {
|
||||
}
|
||||
}
|
||||
|
||||
// ⑲ 切片 reducer:Garage(原 module_10032 的 UB / hF,31 字段;58 个 instanceof + 2 个接口/单例臂)
|
||||
run {
|
||||
fun ToObj(
|
||||
Id: Long,
|
||||
Base: Long? = null,
|
||||
Category: Int = 1,
|
||||
View: Int = 1,
|
||||
Count: Int = 3,
|
||||
Buyable: Boolean = true,
|
||||
): GarageItemObject = GarageItemObject(
|
||||
id = Id,
|
||||
description = "obj-$Id",
|
||||
item = "preview-$Id",
|
||||
isPremium = false,
|
||||
itemCategory = Category,
|
||||
itemViewCategory = View,
|
||||
buyable = Buyable,
|
||||
availableForAll = false,
|
||||
discount = null,
|
||||
timePeriod = null,
|
||||
modification = if (Base != null) GarageItemModification(Base, 0) else null,
|
||||
properties = null,
|
||||
upgradeableParams = null,
|
||||
devices = null,
|
||||
count = Count,
|
||||
kit = null,
|
||||
countable = false,
|
||||
mountIndex = null,
|
||||
availableSkins = null,
|
||||
availableShotSkins = null,
|
||||
mountedSkin = null,
|
||||
mountedShotSkin = null,
|
||||
skinPreview = null,
|
||||
grouped = null,
|
||||
rarity = null,
|
||||
favorite = false,
|
||||
isSellingForCoin = false,
|
||||
isSellingForCrystal = false,
|
||||
isSellingForRuby = false,
|
||||
resistanceBackgroundImg = null,
|
||||
visible = true,
|
||||
descriptionMedia = null,
|
||||
saleByKitItems = null,
|
||||
)
|
||||
|
||||
fun ToItem(
|
||||
Id: Long,
|
||||
Base: Long? = null,
|
||||
Category: Int = 1,
|
||||
View: Int = 1,
|
||||
Owned: Boolean = true,
|
||||
Mounted: Boolean = false,
|
||||
Count: Int = 1,
|
||||
Buyable: Boolean = true,
|
||||
Favorite: Boolean = false,
|
||||
HasDeviceSale: Boolean = false,
|
||||
DevicePreview: Any? = null,
|
||||
Level: Int = 0,
|
||||
Confirmed: Boolean = false,
|
||||
Discount: Any? = null,
|
||||
): GarageItem = GarageItem(
|
||||
id = Id,
|
||||
name = "item-$Id",
|
||||
category = Category,
|
||||
viewCategory = View,
|
||||
priceWithoutDiscount = 100,
|
||||
description = "item-$Id",
|
||||
descriptionMedia = null,
|
||||
preview = "preview-$Id",
|
||||
isPremium = false,
|
||||
owned = Owned,
|
||||
mountable = true,
|
||||
mounted = Mounted,
|
||||
mountIndex = null,
|
||||
position = 0,
|
||||
minRank = 0,
|
||||
maxRank = 0,
|
||||
discount = Discount,
|
||||
modification = if (Base != null) GarageItemModification(Base, Level) else null,
|
||||
properties = null,
|
||||
upgradeableParams = UpgradableItemParams(
|
||||
itemPropertyParams = null,
|
||||
properties = null,
|
||||
currentLevel = Level,
|
||||
upgradeParams = null,
|
||||
upgradeDiscount = 0,
|
||||
upgradeConfirmed = Confirmed,
|
||||
),
|
||||
count = Count,
|
||||
kit = null,
|
||||
countable = false,
|
||||
hasDeviceSale = HasDeviceSale,
|
||||
devicesAvailable = false,
|
||||
devicePreview = DevicePreview,
|
||||
buyable = Buyable,
|
||||
availableForAll = false,
|
||||
availableSkins = null,
|
||||
availableShotSkins = null,
|
||||
mountedSkin = null,
|
||||
mountedShotSkin = null,
|
||||
skinPreview = null,
|
||||
group = null,
|
||||
rarity = null,
|
||||
favorite = Favorite,
|
||||
resistanceBackgroundImg = null,
|
||||
visible = true,
|
||||
secret = false,
|
||||
saleByKitItems = null,
|
||||
isSellingForCoin = false,
|
||||
isSellingForCrystal = false,
|
||||
isSellingForRuby = false,
|
||||
isSellingForMoney = false,
|
||||
isSellingForADS = false,
|
||||
)
|
||||
|
||||
fun ToDevice(
|
||||
Id: Long,
|
||||
Base: Long,
|
||||
Installed: Boolean = false,
|
||||
Preview: Any? = "device-$Id",
|
||||
Infinity: Boolean = false,
|
||||
): GarageDevice = GarageDevice(
|
||||
id = Id,
|
||||
baseItemId = Base,
|
||||
installed = Installed,
|
||||
name = "device-$Id",
|
||||
category = 1,
|
||||
viewCategory = 1,
|
||||
priceWithoutDiscount = 50,
|
||||
description = "device-$Id",
|
||||
descriptionMedia = null,
|
||||
previewImage = Preview,
|
||||
isPremium = false,
|
||||
position = 0,
|
||||
minRank = 0,
|
||||
maxRank = 0,
|
||||
discount = 0,
|
||||
timeDiscountEnd = null,
|
||||
timeDiscountToStart = null,
|
||||
infinityLifetimeItem = Infinity,
|
||||
lifeTimeInSec = 0,
|
||||
property = "",
|
||||
properties = null,
|
||||
isSellingForCoin = false,
|
||||
isSellingForCrystal = false,
|
||||
isSellingForRuby = false,
|
||||
isSellingForADS = false,
|
||||
isSellingForMoney = false,
|
||||
rarity = null,
|
||||
visible = true,
|
||||
secret = false,
|
||||
buyable = true,
|
||||
)
|
||||
|
||||
fun ToDeviceObj(Id: Long, Base: Long, Preview: Any? = "device-$Id"): GarageDeviceObject =
|
||||
GarageDeviceObject(
|
||||
id = Id,
|
||||
baseItemId = Base,
|
||||
temporaryItemCC = null,
|
||||
description = "device-$Id",
|
||||
item = Preview,
|
||||
isPremium = false,
|
||||
itemCategory = 1,
|
||||
itemViewCategory = 1,
|
||||
buyable = true,
|
||||
discount = null,
|
||||
timePeriod = null,
|
||||
deviceProperty = "",
|
||||
rarity = null,
|
||||
visible = true,
|
||||
descriptionMedia = null,
|
||||
)
|
||||
|
||||
fun BaseState(
|
||||
ItemList: List<GarageItem>,
|
||||
DeviceMap: Map<Long, List<GarageDevice>> = emptyMap(),
|
||||
): GarageStateSlice {
|
||||
val Grouped = ItemList
|
||||
.groupBy { it.modification?.vcf_1 ?: it.id }
|
||||
.mapValues { GarageBaseItems(it.value) }
|
||||
return GarageStateSlice(
|
||||
Items = GarageItemsState(Grouped),
|
||||
Devices = Devices(DeviceMap),
|
||||
)
|
||||
}
|
||||
|
||||
fun ItemIn(State: GarageStateSlice, Id: Long): GarageItem =
|
||||
State.Items.itemsByBase.values.flatMap { it.Items }.first { it.id == Id }
|
||||
|
||||
val S0 = GarageStateSlice()
|
||||
Check(
|
||||
"切片 Garage:默认值与原构造一致(31 字段)",
|
||||
S0.Items.itemsByBase.isEmpty() && S0.Devices.baseItemIdToDevices.isEmpty() &&
|
||||
S0.GarageObject == null && !S0.IsLoaded &&
|
||||
S0.CurrentCategory == GarageDefaultCategory && S0.CurrentItemId == null &&
|
||||
S0.SelectAlterationId == null && S0.SelectedSkinId == null &&
|
||||
S0.SelectedShotSkinId == null && S0.NewItems.isEmpty() &&
|
||||
!S0.ResistanceReadyToMount && S0.DelayMountTimeMs == 0L &&
|
||||
S0.CooldownReduceEndTime == 0L && S0.TimeToReduceUpdateInMin == 0 &&
|
||||
S0.CurrentRarity == null && S0.PurchaseOfUpgradesShopItemId == 920109776942L &&
|
||||
!S0.GarageDiscountNotification && S0.ShowVideoInDescription &&
|
||||
S0.UnlockedProtectionSlots == 1 && S0.PricesToUnlockSlot.isEmpty() &&
|
||||
S0.NumberRowsInPaintsUI == 2 && S0.OverdriveDescriptions.isEmpty() &&
|
||||
S0.WeaponToResistanceModule.isEmpty() && S0.WaitServerItemMount.isEmpty() &&
|
||||
S0.BazookaToSupply.isEmpty() && S0.UpgradeCoolDownEndTimes.isEmpty() &&
|
||||
S0.UpgradeItemInProcessingId == null
|
||||
)
|
||||
|
||||
val O1 = ToObj(101, Count = 3)
|
||||
val O2 = ToObj(202, Count = 1, Buyable = false)
|
||||
val O3 = ToObj(303, Count = 2)
|
||||
val O4 = ToObj(404, Count = 1)
|
||||
val GarageObj = GarageObject("temp")
|
||||
val S1 = ReduceGarage(S0, SetGarageObject(GarageObj))
|
||||
Check("切片 Garage:SetGarageObject", S1.GarageObject == GarageObj)
|
||||
val S1a = ReduceGarage(S1, SetItemsOnDepot(listOf(O1, O3)))
|
||||
Check(
|
||||
"切片 Garage:SetItemsOnDepot",
|
||||
S1a.ItemsOnDepot.toList() == listOf(O1, O3) && S1a.GarageObject == GarageObj
|
||||
)
|
||||
val S1b = ReduceGarage(S1a, SetItemsOnMarket(listOf(O2)))
|
||||
Check("切片 Garage:SetItemsOnMarket", S1b.ItemsOnMarket.toList() == listOf(O2))
|
||||
val S1c = ReduceGarage(S1b, SetMountedItems(listOf(O3)))
|
||||
Check("切片 Garage:SetMountedItems", S1c.MountedItems.toList() == listOf(O3))
|
||||
val S1d = ReduceGarage(S1c, SetGarageSkinsAction(listOf(O4)))
|
||||
Check("切片 Garage:SetGarageSkinsAction", S1d.SkinsItems.toList() == listOf(O4))
|
||||
|
||||
val Loaded0 = GarageStateSlice(
|
||||
ItemsOnDepot = listOf(O1, O3, ToObj(505, Count = 1)),
|
||||
MountedItems = listOf(O3),
|
||||
ItemsOnMarket = listOf(O2),
|
||||
SkinsItems = listOf(O4),
|
||||
)
|
||||
val Loaded1 = ReduceGarage(Loaded0, GarageLoaded())
|
||||
val LoadedItems = Loaded1.Items.itemsByBase.values.flatMap { it.Items }
|
||||
Check(
|
||||
"切片 Garage:GarageLoaded 重建 PB(depot/mounted/market/skins)",
|
||||
Loaded1.IsLoaded && LoadedItems.map { it.id }.sorted() == listOf(101L, 202L, 303L, 404L, 505L) &&
|
||||
LoadedItems.first { it.id == 101L }.owned &&
|
||||
LoadedItems.first { it.id == 303L }.owned && LoadedItems.first { it.id == 303L }.mounted &&
|
||||
!LoadedItems.first { it.id == 202L }.owned && !LoadedItems.first { it.id == 202L }.buyable &&
|
||||
!LoadedItems.first { it.id == 404L }.owned
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:SetGarageNotLoaded",
|
||||
!ReduceGarage(Loaded1, SetGarageNotLoaded()).IsLoaded
|
||||
)
|
||||
|
||||
val SC = ReduceGarage(S0, SelectGarageCategory("paints"))
|
||||
Check(
|
||||
"切片 Garage:SelectGarageCategory 同时清空 currentItemId",
|
||||
SC.CurrentCategory == "paints" && SC.CurrentItemId == null
|
||||
)
|
||||
val SI = ReduceGarage(SC, GarageSelectItem(101))
|
||||
Check(
|
||||
"切片 Garage:GarageSelectItem 只改 currentItemId",
|
||||
SI.CurrentItemId == 101L && SI.CurrentCategory == "paints"
|
||||
)
|
||||
|
||||
val I101 = ToItem(101, Count = 3)
|
||||
val SU = ReduceGarage(BaseState(listOf(I101)), GarageUpdateItemCount(I101, 9))
|
||||
Check("切片 Garage:GarageUpdateItemCount", ItemIn(SU, 101).count == 9)
|
||||
|
||||
val L1 = ToItem(110, Base = 110, Level = 1, DevicePreview = "lvl-1")
|
||||
val L2 = ToItem(111, Base = 110, Level = 2, DevicePreview = "lvl-2")
|
||||
val L3 = ToItem(112, Base = 110, Level = 3, DevicePreview = "lvl-3")
|
||||
val AddCount = ReduceGarage(BaseState(listOf(L1, L2, L3)), AddGarageItemCount(L2, 4))
|
||||
Check(
|
||||
"切片 Garage:AddGarageItemCount(owned=true、count+=、devicePreview 取等级项)",
|
||||
ItemIn(AddCount, 111).owned && ItemIn(AddCount, 111).count == 5 &&
|
||||
ItemIn(AddCount, 111).devicePreview == "lvl-2"
|
||||
)
|
||||
|
||||
val M1 = ToItem(201, Mounted = true)
|
||||
val M2 = ToItem(202)
|
||||
val Mounted = ReduceGarage(BaseState(listOf(M1, M2)), GarageMountItem(M2))
|
||||
Check(
|
||||
"切片 Garage:GarageMountItem 先卸同 viewCategory 再装,并写 waitServerItemMount",
|
||||
!ItemIn(Mounted, 201).mounted && ItemIn(Mounted, 202).mounted &&
|
||||
Mounted.WaitServerItemMount[1] == true
|
||||
)
|
||||
val Unmounted = ReduceGarage(Mounted, GarageUnmountItem(202))
|
||||
Check("切片 Garage:GarageUnmountItem", !ItemIn(Unmounted, 202).mounted)
|
||||
|
||||
val MountAll = ReduceGarage(
|
||||
BaseState(listOf(M1, M2)),
|
||||
GarageMountItems(listOf(201, 202)),
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:GarageMountItems 批量 owned+mounted",
|
||||
ItemIn(MountAll, 201).mounted && ItemIn(MountAll, 201).owned &&
|
||||
ItemIn(MountAll, 202).mounted && ItemIn(MountAll, 202).owned
|
||||
)
|
||||
|
||||
val SkinBase = BaseState(listOf(ToItem(301, Base = 301), ToItem(302, Base = 301)))
|
||||
val Skinned = ReduceGarage(SkinBase, SetMountedSkinForItems(9001, ItemIn(SkinBase, 302)))
|
||||
Check(
|
||||
"切片 Garage:SetMountedSkinForItems 整组写入 mountedSkin",
|
||||
ItemIn(Skinned, 301).mountedSkin == 9001L && ItemIn(Skinned, 302).mountedSkin == 9001L
|
||||
)
|
||||
val Shot = ReduceGarage(SkinBase, SetMountedShotSkinForItems(9002, ItemIn(SkinBase, 302)))
|
||||
Check(
|
||||
"切片 Garage:SetMountedShotSkinForItems 整组写入 mountedShotSkin",
|
||||
ItemIn(Shot, 301).mountedShotSkin == 9002L && ItemIn(Shot, 302).mountedShotSkin == 9002L
|
||||
)
|
||||
|
||||
val R1 = ToItem(401, View = 5)
|
||||
val R2 = ToItem(402, View = 5)
|
||||
val Resist = ReduceGarage(BaseState(listOf(R1, R2)), GarageApplyResistanceMount(R1, 3, false))
|
||||
Check(
|
||||
"切片 Garage:GarageApplyResistanceMount(mounted + mountIndex + waitServerItemMount)",
|
||||
ItemIn(Resist, 401).mounted && ItemIn(Resist, 401).mountIndex == 3 &&
|
||||
Resist.WaitServerItemMount[GarageResistanceCategoryKey] == true
|
||||
)
|
||||
var ResistanceThrew = false
|
||||
try {
|
||||
ReduceGarage(Resist, GarageApplyResistanceMount(R2, 4, false))
|
||||
} catch (_: Throwable) {
|
||||
ResistanceThrew = true
|
||||
}
|
||||
Check("切片 Garage:抵抗模块装配数受 unlockedProtectionSlots 限制", ResistanceThrew)
|
||||
val ResistOff = ReduceGarage(Resist, GarageResistanceUnMount(401, true))
|
||||
Check(
|
||||
"切片 Garage:GarageResistanceUnMount",
|
||||
!ItemIn(ResistOff, 401).mounted &&
|
||||
ResistOff.WaitServerItemMount[GarageResistanceCategoryKey] == true
|
||||
)
|
||||
|
||||
val Up0 = ReduceGarage(
|
||||
BaseState(listOf(ToItem(501, Level = 2, Confirmed = true))),
|
||||
GarageUpgradeItemAction(501, 100, "coin"),
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:GarageUpgradeItemAction(level+1、confirmed=false、processing=itemId)",
|
||||
ItemIn(Up0, 501).upgradeableParams!!.currentLevel == 3 &&
|
||||
ItemIn(Up0, 501).upgradeableParams!!.upgradeConfirmed == false &&
|
||||
Up0.UpgradeItemInProcessingId == 501L
|
||||
)
|
||||
val Up1 = ReduceGarage(Up0, GarageUpgradeItemCoolDownStarted(501, 12345))
|
||||
Check("切片 Garage:GarageUpgradeItemCoolDownStarted", Up1.UpgradeCoolDownEndTimes[501L] == 12345L)
|
||||
val Up2 = ReduceGarage(Up1, GarageUpgradeItemCoolDownFinished(501, 12345))
|
||||
Check("切片 Garage:GarageUpgradeItemCoolDownFinished 命中时删键", Up2.UpgradeCoolDownEndTimes.isEmpty())
|
||||
Check(
|
||||
"切片 Garage:GarageUpgradeItemCoolDownFinished 不命中时原样返回",
|
||||
ReduceGarage(Up1, GarageUpgradeItemCoolDownFinished(501, 999)) == Up1
|
||||
)
|
||||
val Confirmed = ReduceGarage(Up0, GarageUpgradeItemConfirm(501, 3))
|
||||
Check(
|
||||
"切片 Garage:GarageUpgradeItemConfirm 确认并清 processing",
|
||||
ItemIn(Confirmed, 501).upgradeableParams!!.upgradeConfirmed == true &&
|
||||
Confirmed.UpgradeItemInProcessingId == null
|
||||
)
|
||||
val ConfirmedOther = ReduceGarage(
|
||||
Up0.copy(UpgradeItemInProcessingId = 999L),
|
||||
GarageUpgradeItemConfirm(501, 3),
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:Confirm 其他 processing id 不清",
|
||||
ConfirmedOther.UpgradeItemInProcessingId == 999L
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:ClearUpgradeItemInProcessing(原 xU 单例)",
|
||||
ReduceGarage(Up0, ClearUpgradeItemInProcessing()).UpgradeItemInProcessingId == null
|
||||
)
|
||||
|
||||
val DItem = ToItem(601)
|
||||
val DBase = BaseState(listOf(DItem), mapOf(601L to listOf(ToDevice(9001, 601))))
|
||||
val DLoaded = ReduceGarage(
|
||||
DBase,
|
||||
GarageDevicesLoadedAction(
|
||||
601,
|
||||
listOf(ToDeviceObj(9001, 601), ToDeviceObj(9002, 601)),
|
||||
ToDevice(9002, 601),
|
||||
),
|
||||
)
|
||||
val DList = DLoaded.Devices.baseItemIdToDevices[601L].orEmpty()
|
||||
Check(
|
||||
"切片 Garage:GarageDevicesLoadedAction 合并旧列表并按 mountedDevice 置 installed",
|
||||
DList.map { it.id }.sorted() == listOf(9001L, 9002L) &&
|
||||
!DList.first { it.id == 9001L }.installed &&
|
||||
DList.first { it.id == 9002L }.installed
|
||||
)
|
||||
val DRemoved = ReduceGarage(DLoaded, GarageRemoveDevice(ToDevice(9001, 601), DItem))
|
||||
Check(
|
||||
"切片 Garage:GarageRemoveDevice(devicePreview=null、installed=false)",
|
||||
ItemIn(DRemoved, 601).devicePreview == null &&
|
||||
!DRemoved.Devices.baseItemIdToDevices[601L]!!.first { it.id == 9001L }.installed
|
||||
)
|
||||
val DInserted = ReduceGarage(
|
||||
DLoaded,
|
||||
GarageInsertDeviceClientAndServer(ToDevice(9002, 601, Preview = "dev-preview"), DItem),
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:GarageInsertDeviceClientAndServer(devicePreview=设备预览图、installed=true)",
|
||||
ItemIn(DInserted, 601).devicePreview == "dev-preview" &&
|
||||
DInserted.Devices.baseItemIdToDevices[601L]!!.first { it.id == 9002L }.installed
|
||||
)
|
||||
val DBought = ReduceGarage(
|
||||
DLoaded,
|
||||
GarageBuyDevice(ToDevice(9002, 601, Preview = "bought"), DItem, "coin", true),
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:GarageBuyDevice(installed=mount、infinityLifetimeItem=true、devicePreview)",
|
||||
ItemIn(DBought, 601).devicePreview == "bought" &&
|
||||
DBought.Devices.baseItemIdToDevices[601L]!!.first { it.id == 9002L }.installed &&
|
||||
DBought.Devices.baseItemIdToDevices[601L]!!.first { it.id == 9002L }.infinityLifetimeItem
|
||||
)
|
||||
val DInf = ReduceGarage(DLoaded, GarageDeviceTrySetInfinityLifetime(9001))
|
||||
Check(
|
||||
"切片 Garage:GarageDeviceTrySetInfinityLifetime",
|
||||
DInf.Devices.baseItemIdToDevices[601L]!!.first { it.id == 9001L }.infinityLifetimeItem
|
||||
)
|
||||
|
||||
val Sel = ReduceGarage(S0, GarageSelectAlteration(7001))
|
||||
val Sel2 = ReduceGarage(Sel, GarageSelectSkin(7002))
|
||||
val Sel3 = ReduceGarage(Sel2, GarageSelectShotSkin(7003))
|
||||
Check(
|
||||
"切片 Garage:三个选择动作",
|
||||
Sel3.SelectAlterationId == 7001L && Sel3.SelectedSkinId == 7002L &&
|
||||
Sel3.SelectedShotSkinId == 7003L
|
||||
)
|
||||
|
||||
val DiscItem = ToItem(801, Owned = true, HasDeviceSale = true)
|
||||
val NoDisc = ReduceGarage(BaseState(listOf(DiscItem)), GarageRemoveDiscountForDevice(DiscItem))
|
||||
Check(
|
||||
"切片 Garage:GarageRemoveDiscountForDevice(hasDeviceSale && owned)",
|
||||
ItemIn(NoDisc, 801).hasDeviceSale
|
||||
)
|
||||
val UnownedDisc = ToItem(802, Owned = false, HasDeviceSale = true)
|
||||
val NoDisc2 = ReduceGarage(BaseState(listOf(UnownedDisc)), GarageRemoveDiscountForDevice(UnownedDisc))
|
||||
Check("切片 Garage:未拥有项去折扣后 hasDeviceSale=false", !ItemIn(NoDisc2, 802).hasDeviceSale)
|
||||
Check(
|
||||
"切片 Garage:UpdateDiscount 保留原 discount 值",
|
||||
ReduceGarage(BaseState(listOf(ToItem(803, Discount = "d"))), UpdateDiscount(ToItem(803, Discount = "d")))
|
||||
.let { ItemIn(it, 803).discount == "d" }
|
||||
)
|
||||
|
||||
val DepotItem = ToItem(901, Owned = false, Count = 1)
|
||||
val DepotState = BaseState(listOf(DepotItem))
|
||||
val Added = ReduceGarage(DepotState, GarageAddItemToDepot(901, 5))
|
||||
Check("切片 Garage:GarageAddItemToDepot(owned=true、count 覆盖)",
|
||||
ItemIn(Added, 901).owned && ItemIn(Added, 901).count == 5)
|
||||
val Removed = ReduceGarage(Added, GarageRemoveItemFromDepot(ToObj(901, Count = 2)))
|
||||
Check("切片 Garage:GarageRemoveItemFromDepot(owned=false、count 取动作 item)",
|
||||
!ItemIn(Removed, 901).owned && ItemIn(Removed, 901).count == 2)
|
||||
val NotSold = ReduceGarage(Added, GarageRemoveItemFromStore(901))
|
||||
Check("切片 Garage:GarageRemoveItemFromStore(buyable=false)", !ItemIn(NotSold, 901).buyable)
|
||||
|
||||
val New0 = ReduceGarage(S0, SetNewItems(mapOf(1L to setOf(10L, 20L))))
|
||||
val New1 = ReduceGarage(New0, AddNewItem(1, 30))
|
||||
val New2 = ReduceGarage(New1, AddNewItem(2, 5))
|
||||
Check(
|
||||
"切片 Garage:SetNewItems / AddNewItem",
|
||||
New2.NewItems[1L] == setOf(10L, 20L, 30L) && New2.NewItems[2L] == setOf(5L)
|
||||
)
|
||||
val New3 = ReduceGarage(New2, RemoveNewItem(1, 10))
|
||||
val New4 = ReduceGarage(New3, RemoveNewItem(1, 20))
|
||||
val New5 = ReduceGarage(New4, RemoveNewItem(1, 30))
|
||||
Check(
|
||||
"切片 Garage:RemoveNewItem 逐个移除并在空集时删键",
|
||||
New3.NewItems[1L] == setOf(20L, 30L) && !New5.NewItems.containsKey(1L) &&
|
||||
New5.NewItems[2L] == setOf(5L)
|
||||
)
|
||||
|
||||
Check(
|
||||
"切片 Garage:SetResistanceReadyToMount",
|
||||
ReduceGarage(S0, SetResistanceReadyToMount(true)).ResistanceReadyToMount
|
||||
)
|
||||
|
||||
val SaleBase = BaseState(
|
||||
listOf(ToItem(1001, Base = 1001), ToItem(1002, Base = 1001), ToItem(1003, Base = 1003))
|
||||
)
|
||||
val Sale = ReduceGarage(SaleBase, RemoveFromSale(listOf(1001L)))
|
||||
Check(
|
||||
"切片 Garage:RemoveFromSale 只影响给定 baseItemId 组",
|
||||
!ItemIn(Sale, 1001).buyable && !ItemIn(Sale, 1002).buyable && ItemIn(Sale, 1003).buyable
|
||||
)
|
||||
|
||||
val Delay = ReduceGarage(S0, SetRestrictionMount(5000))
|
||||
Check(
|
||||
"切片 Garage:SetRestrictionMount 正延迟写成 now+delay",
|
||||
Delay.DelayMountTimeMs > 0L && ReduceGarage(S0, SetRestrictionMount(0)).DelayMountTimeMs == 0L
|
||||
)
|
||||
Check("切片 Garage:ResetMountDelay", ReduceGarage(Delay, ResetMountDelay()).DelayMountTimeMs == 0L)
|
||||
|
||||
val Cool = ReduceGarage(S0, StartCooldownReduce(60, 5))
|
||||
Check(
|
||||
"切片 Garage:StartCooldownReduce(now+seconds*1000、minutes)",
|
||||
Cool.CooldownReduceEndTime > 0L && Cool.TimeToReduceUpdateInMin == 5
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:SetCooldownReduceEndTime(now+seconds*1000)",
|
||||
ReduceGarage(S0, SetCooldownReduceEndTime(10)).CooldownReduceEndTime > 0L
|
||||
)
|
||||
Check("切片 Garage:SetItemRarity", ReduceGarage(S0, SetItemRarity("rare")).CurrentRarity == "rare")
|
||||
|
||||
val Fav = BaseState(listOf(ToItem(1101)))
|
||||
val Favorited = ReduceGarage(Fav, AddToFavoriteItem(1101))
|
||||
Check("切片 Garage:AddToFavoriteItem", ItemIn(Favorited, 1101).favorite)
|
||||
Check(
|
||||
"切片 Garage:RemoveFromFavoriteItem",
|
||||
!ItemIn(ReduceGarage(Favorited, RemoveFromFavoriteItem(1101)), 1101).favorite
|
||||
)
|
||||
|
||||
val GoGarage = ReduceGarage(SC.copy(CurrentItemId = 101L), GoTo(NamedScreen("Garage"), false))
|
||||
Check(
|
||||
"切片 Garage:GoTo Garage 复位 currentCategory 并原样返回 currentItemId",
|
||||
GoGarage.CurrentCategory == GarageDefaultCategory && GoGarage.CurrentItemId == 101L
|
||||
)
|
||||
val GoShop = ReduceGarage(SC, GoTo(NamedScreen("Shop"), false))
|
||||
Check("切片 Garage:GoTo 其他屏幕不改分类", GoShop.CurrentCategory == "paints")
|
||||
|
||||
Check(
|
||||
"切片 Garage:ShowGarageDiscountNotification",
|
||||
ReduceGarage(S0, ShowGarageDiscountNotification()).GarageDiscountNotification
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:HideVideoInDescription",
|
||||
!ReduceGarage(S0, HideVideoInDescription()).ShowVideoInDescription
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:BuyProtectionSlot",
|
||||
ReduceGarage(S0, BuyProtectionSlot(1)).UnlockedProtectionSlots == 2
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:SwitchingRowsScroll",
|
||||
ReduceGarage(S0, SwitchingRowsScroll(4)).NumberRowsInPaintsUI == 4
|
||||
)
|
||||
|
||||
val Desc = OverdriveDescriptionData("name", "icon", "text")
|
||||
Check(
|
||||
"切片 Garage:AddOverdriveDescription",
|
||||
ReduceGarage(S0, AddOverdriveDescription(12, Desc)).OverdriveDescriptions[12L] == Desc
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:AddRelatedResistanceModule",
|
||||
ReduceGarage(S0, AddRelatedResistanceModule(12, 34)).WeaponToResistanceModule[12L] == 34L
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:AddRelatedBazooka",
|
||||
ReduceGarage(S0, AddRelatedBazooka(12, 34)).BazookaToSupply[12L] == 34L
|
||||
)
|
||||
|
||||
val Wait0 = S0.copy(WaitServerItemMount = mapOf(1 to true, 2 to true))
|
||||
val Wait1 = ReduceGarage(Wait0, RemoveWaitServerItemMount(listOf(1)))
|
||||
Check(
|
||||
"切片 Garage:RemoveWaitServerItemMount 给定键置 false",
|
||||
Wait1.WaitServerItemMount[1] == false && Wait1.WaitServerItemMount[2] == true
|
||||
)
|
||||
Check(
|
||||
"切片 Garage:ClearWaitServerItemMount",
|
||||
ReduceGarage(Wait1, ClearWaitServerItemMount()).WaitServerItemMount.isEmpty()
|
||||
)
|
||||
|
||||
val Reset0 = S0.copy(
|
||||
Devices = Devices(mapOf(1L to listOf(ToDevice(1, 1)))),
|
||||
UpgradeCoolDownEndTimes = mapOf(1L to 2L),
|
||||
UpgradeItemInProcessingId = 3L,
|
||||
)
|
||||
val Reset1 = ReduceGarage(Reset0, ResetGarage())
|
||||
Check(
|
||||
"切片 Garage:ResetGarage 清 devices / coolDown / processing",
|
||||
Reset1.Devices.baseItemIdToDevices.isEmpty() &&
|
||||
Reset1.UpgradeCoolDownEndTimes.isEmpty() && Reset1.UpgradeItemInProcessingId == null
|
||||
)
|
||||
|
||||
val Init = ReduceGarage(
|
||||
S0,
|
||||
InitState(GarageStateSlice::class, { S: GarageStateSlice -> S.copy(IsLoaded = true) }),
|
||||
)
|
||||
Check("切片 Garage:InitState 按 GarageStateSlice::class 灌入状态", Init.IsLoaded)
|
||||
Check(
|
||||
"切片 Garage:InitState 其他类型不改状态",
|
||||
ReduceGarage(S0, InitState(String::class, { S: GarageStateSlice -> S.copy(IsLoaded = true) })) == S0
|
||||
)
|
||||
Check("切片 Garage:无关动作返回等值状态", ReduceGarage(BaseState(listOf(I101)), AddFrags(1)) == BaseState(listOf(I101)))
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, GarageSelectItem(101))
|
||||
Check(
|
||||
"根:GarageSelectItem 只动 garage",
|
||||
Root1.Garage.CurrentItemId == 101L && Root1.Shop == Root0.Shop && Root1.Screen == Root0.Screen &&
|
||||
Root1.LootBoxes == Root0.LootBoxes && Root1.Home == Root0.Home
|
||||
)
|
||||
val Root2 = ReduceRoot(Root1, SetGarageObject(GarageObj))
|
||||
Check(
|
||||
"根:SetGarageObject 保留 garage 前一次归约",
|
||||
Root2.Garage.GarageObject == GarageObj && Root2.Garage.CurrentItemId == 101L &&
|
||||
Root2.LootBoxes == Root1.LootBoxes
|
||||
)
|
||||
Check("根:garage 迁移后无关动作仍返回等值状态", ReduceRoot(Root2, AddFrags(1)) == Root2)
|
||||
|
||||
val W = RootWiring.ByField("garage")!!
|
||||
Check(
|
||||
"根:garage 委派到 UB / hF 且 58 个动作全部具名",
|
||||
W.SliceClass == "UB" && W.Reducer == "hF" && W.Actions.size == 58 &&
|
||||
W.Actions.none { it.startsWith("?") }
|
||||
)
|
||||
Check(
|
||||
"根:garage 的动作名覆盖 58 个 instanceof 臂",
|
||||
listOf(
|
||||
"ResetGarage", "SetGarageObject", "SetItemsOnDepot", "SetItemsOnMarket",
|
||||
"SetMountedItems", "GarageLoaded", "SetGarageNotLoaded", "SelectGarageCategory",
|
||||
"GarageSelectItem", "GarageUpdateItemCount", "AddGarageItemCount", "GarageMountItem", "GarageUnmountItem",
|
||||
"GarageMountItems", "SetMountedSkinForItems", "SetMountedShotSkinForItems",
|
||||
"SetGarageSkinsAction",
|
||||
"GarageApplyResistanceMount", "GarageResistanceUnMount", "GarageUpgradeItemAction",
|
||||
"GarageUpgradeItemCoolDownStarted", "GarageUpgradeItemCoolDownFinished",
|
||||
"GarageUpgradeItemConfirm", "GarageDevicesLoadedAction", "GarageRemoveDevice",
|
||||
"GarageBuyDevice",
|
||||
"GarageDeviceTrySetInfinityLifetime", "GarageSelectAlteration", "GarageSelectSkin",
|
||||
"GarageSelectShotSkin", "GarageRemoveDiscountForDevice", "UpdateDiscount",
|
||||
"GarageAddItemToDepot", "GarageRemoveItemFromDepot", "GarageRemoveItemFromStore",
|
||||
"SetNewItems", "AddNewItem", "RemoveNewItem", "SetResistanceReadyToMount",
|
||||
"RemoveFromSale", "SetRestrictionMount", "ResetMountDelay", "StartCooldownReduce",
|
||||
"SetCooldownReduceEndTime", "SetItemRarity", "AddToFavoriteItem",
|
||||
"RemoveFromFavoriteItem", "GoTo", "ShowGarageDiscountNotification",
|
||||
"HideVideoInDescription", "BuyProtectionSlot", "SwitchingRowsScroll",
|
||||
"AddOverdriveDescription", "AddRelatedResistanceModule", "AddRelatedBazooka",
|
||||
"RemoveWaitServerItemMount", "ClearWaitServerItemMount", "InitState",
|
||||
).all { it in W.Actions }
|
||||
)
|
||||
Check(
|
||||
"根:garage 的动作表不含 FX / UB 标识类",
|
||||
W.Actions.none { it == "FX" || it == "UB" || it == "Garage" }
|
||||
)
|
||||
}
|
||||
|
||||
val Failed = Results.filter { !it.second }
|
||||
println("TankiOffline 状态层自检:${Results.size} 项")
|
||||
for ((Name, Ok) in Results) println((if (Ok) " ✓ " else " ✗ ") + Name)
|
||||
|
||||
Reference in new issue
Block a user