feat(state): 迁移 garagePreview 切片(22 字段 / 25 分支)
This commit is contained in:
1 parent
3c0ed0a998
commit
1194c395b4
14 files changed
+1574
-49
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` 动作名。
|
||||
- 已迁移切片 **9/89**:
|
||||
- 已迁移切片 **10/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)
|
||||
@@ -172,9 +172,18 @@
|
||||
`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 槽位完整性、九片一次归约互不串片、未迁移字段透传,
|
||||
- `garagePreview` → `IG` / `fs.eru`(`GaragePreviewReducer.kt`):22 字段,25 个顶层臂
|
||||
(22 个 `instanceof` + 3 个单例 `yd(t, is/es/rs)`)。`ShowRequest` 按 `withDelay` 决定
|
||||
`isVisible = !withDelay && 原值`、`needVisible = withDelay || 原值`;`UpdateViewStyle` 无字段,
|
||||
原 `t.fru_1` 是 `undefined`,`trs` 视作省略,状态不变。
|
||||
`SetHullData` / `SetWeaponData` / `SetDrone` / `SetPaint` 先查 `rrs(category, itemId)`
|
||||
(`expectedItemId[category] == null || == itemId`);命中才写 3D 数据,但无论命中都缓存动作并删 `requestedItems`。
|
||||
`TankPartData` / `TankPreviewSettings` / `HullEngineType` / `TurretMechanism` 见 `GaragePreviewModels.kt`;
|
||||
12 个匿名动作按效果定名(`BG`→`CaptureScreenshot` … `tH`→`ClearDroneData`),
|
||||
3 个单例臂定名 `ClearGaragePreviewParams` / `ShowGaragePreview` / `HideGaragePreview`,不在 `Actions` 表里。
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 只归约上述十片,其余 **79 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 10/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **275 项全绿**,含 89 槽位完整性、十片一次归约互不串片、未迁移字段透传,
|
||||
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||
@@ -183,7 +192,7 @@
|
||||
`o1` → `ShowShopDiscountNotification`(`$_$.gl` 单例,由 module_18334 的 `Qx.qge` 派发;
|
||||
效果是把 `HomeScreen.shopDiscountNotification` 置 true,对应主菜单商店项的折扣提示);
|
||||
shop 的 17 个匿名类按 reducer 效果定名并登记(`Yut`→`ShopLoaded`、`F5`→`ResetShop` 等);
|
||||
screen 的 9 个、lootBoxes 的 6 个、garage 的 25 个匿名类同样按效果定名并登记。
|
||||
screen 的 9 个、lootBoxes 的 6 个、garage 的 25 个、garagePreview 的 15 个匿名类同样按效果定名并登记。
|
||||
|
||||
### S4 引擎核心
|
||||
- 模块:32088(3D 数学)、92980(渲染)、61378(ECS)、55088(物理)、36659 + 71105(资源)、36734(音频)、3569(输入)
|
||||
|
||||
+107
-16
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generatedAt": "2026-10-23T05:35:58.037Z",
|
||||
"generatedAt": "2026-10-23T06:35:15.369Z",
|
||||
"module": "module_10032.js",
|
||||
"RootState": {
|
||||
"Class": "z6",
|
||||
@@ -15,7 +15,8 @@
|
||||
"shop",
|
||||
"screen",
|
||||
"lootBoxes",
|
||||
"garage"
|
||||
"garage",
|
||||
"garagePreview"
|
||||
],
|
||||
"AnonymousActions": [
|
||||
{
|
||||
@@ -366,6 +367,96 @@
|
||||
"Name": "ClearWaitServerItemMount",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "waitServerItemMount = emptyMap()"
|
||||
},
|
||||
{
|
||||
"Local": "BG",
|
||||
"Name": "CaptureScreenshot",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "调用 captureScreenshotAction(),状态不变(`null == y || y(), i = n`)"
|
||||
},
|
||||
{
|
||||
"Local": "UG",
|
||||
"Name": "CaptureVideo",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "调用 captureVideoAction(),状态不变(`null == $ || $(), i = n`)"
|
||||
},
|
||||
{
|
||||
"Local": "JG",
|
||||
"Name": "ClearHasGrenades",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "hasGrenades = false(第 13 个构造参数 !1)"
|
||||
},
|
||||
{
|
||||
"Local": "KG",
|
||||
"Name": "SetWeaponData",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "若 expectedItemId[WEAPON] 命中,则 weaponData = TankPartData(resource, emissionColors)、turretMechanism = action;并缓存动作、从 requestedItems 删除 itemId"
|
||||
},
|
||||
{
|
||||
"Local": "OG",
|
||||
"Name": "UpdateViewStyle",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "UpdateViewStyle:动作类没有字段,原 `t.fru_1` 为 undefined,`trs` 视作省略,状态不变"
|
||||
},
|
||||
{
|
||||
"Local": "QG",
|
||||
"Name": "ClearHullData",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "hullData = null(第 9 个构造参数 null)"
|
||||
},
|
||||
{
|
||||
"Local": "VG",
|
||||
"Name": "SetHullData",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "若 expectedItemId[ARMOR] 命中,则 hullData = TankPartData(6 字段)、hullEngineType = action;并缓存动作、从 requestedItems 删除 itemId"
|
||||
},
|
||||
{
|
||||
"Local": "XG",
|
||||
"Name": "SetHasGrenades",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "hasGrenades = true(第 13 个构造参数 !0)"
|
||||
},
|
||||
{
|
||||
"Local": "YG",
|
||||
"Name": "SetGrenadeData",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "grenadeData = resource == null ? null : TankPartData(resource, emissionColors)(第 12 个构造参数)"
|
||||
},
|
||||
{
|
||||
"Local": "ZG",
|
||||
"Name": "ClearWeaponData",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "weaponData = null(第 10 个构造参数 null)"
|
||||
},
|
||||
{
|
||||
"Local": "nH",
|
||||
"Name": "ClearGrenadeData",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "grenadeData = null(第 12 个构造参数 null)"
|
||||
},
|
||||
{
|
||||
"Local": "tH",
|
||||
"Name": "ClearDroneData",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "droneData = null(第 11 个构造参数 null)"
|
||||
},
|
||||
{
|
||||
"Local": "is",
|
||||
"Name": "ClearGaragePreviewParams",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "params = null(第 8 个构造参数 null)"
|
||||
},
|
||||
{
|
||||
"Local": "es",
|
||||
"Name": "ShowGaragePreview",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "isVisible = true、needVisible = false(`n.trs(!0, cd, !1)`)"
|
||||
},
|
||||
{
|
||||
"Local": "rs",
|
||||
"Name": "HideGaragePreview",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "isVisible = false(`n.trs(!1)`)"
|
||||
}
|
||||
],
|
||||
"Markers": [
|
||||
@@ -602,31 +693,31 @@
|
||||
"Reducer": "fs.eru",
|
||||
"Delegate": "fs.eru(t, n.epv_1)",
|
||||
"Actions": [
|
||||
"?BG",
|
||||
"?JG",
|
||||
"?KG",
|
||||
"?OG",
|
||||
"?QG",
|
||||
"?UG",
|
||||
"?VG",
|
||||
"?XG",
|
||||
"?YG",
|
||||
"?ZG",
|
||||
"?nH",
|
||||
"?tH",
|
||||
"AddRequestedItem",
|
||||
"CaptureScreenshot",
|
||||
"CaptureVideo",
|
||||
"ClearDroneData",
|
||||
"ClearGrenadeData",
|
||||
"ClearHasGrenades",
|
||||
"ClearHullData",
|
||||
"ClearWeaponData",
|
||||
"InitGarageResources",
|
||||
"ResetItem3dModelActionCache",
|
||||
"SetCaptureActions",
|
||||
"SetDrone",
|
||||
"SetExpectedItemId",
|
||||
"SetGrenadeData",
|
||||
"SetHasGrenades",
|
||||
"SetHullData",
|
||||
"SetMountedItemsProperties",
|
||||
"SetPaint",
|
||||
"SetWeaponData",
|
||||
"ShowRequest",
|
||||
"UpdatePreviewSettings"
|
||||
"UpdatePreviewSettings",
|
||||
"UpdateViewStyle"
|
||||
],
|
||||
"Default": "new IG()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "challenges",
|
||||
|
||||
@@ -0,0 +1,696 @@
|
||||
{
|
||||
"generatedAt": "2026-10-23T07:01:46.681Z",
|
||||
"module": "module_10032.js",
|
||||
"Field": "garagePreview",
|
||||
"Slot": "epv_1",
|
||||
"Class": "IG",
|
||||
"ClassSource": "new IG()",
|
||||
"NamedReducer": "fs.eru",
|
||||
"Params": [
|
||||
"t",
|
||||
"n",
|
||||
"i",
|
||||
"r",
|
||||
"e",
|
||||
"u",
|
||||
"s",
|
||||
"o",
|
||||
"_",
|
||||
"h",
|
||||
"a",
|
||||
"c",
|
||||
"l",
|
||||
"f",
|
||||
"v",
|
||||
"p",
|
||||
"w",
|
||||
"d",
|
||||
"g",
|
||||
"m",
|
||||
"k",
|
||||
"z"
|
||||
],
|
||||
"Fields": [
|
||||
{
|
||||
"Field": "isVisible",
|
||||
"Slot": "vrr_1",
|
||||
"Kotlin": "IsVisible",
|
||||
"Default": "false"
|
||||
},
|
||||
{
|
||||
"Field": "photoMode",
|
||||
"Slot": "wrr_1",
|
||||
"Kotlin": "PhotoMode",
|
||||
"Default": "false"
|
||||
},
|
||||
{
|
||||
"Field": "needVisible",
|
||||
"Slot": "xrr_1",
|
||||
"Kotlin": "NeedVisible",
|
||||
"Default": "false"
|
||||
},
|
||||
{
|
||||
"Field": "viewStyle",
|
||||
"Slot": "yrr_1",
|
||||
"Kotlin": "ViewStyle",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "dynViewStyle",
|
||||
"Slot": "zrr_1",
|
||||
"Kotlin": "DynViewStyle",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "tankPreviewSettings",
|
||||
"Slot": "ars_1",
|
||||
"Kotlin": "TankPreviewSettings",
|
||||
"Default": "new Ny()"
|
||||
},
|
||||
{
|
||||
"Field": "needShowDrone",
|
||||
"Slot": "brs_1",
|
||||
"Kotlin": "NeedShowDrone",
|
||||
"Default": "false"
|
||||
},
|
||||
{
|
||||
"Field": "params",
|
||||
"Slot": "crs_1",
|
||||
"Kotlin": "Params",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "hullData",
|
||||
"Slot": "drs_1",
|
||||
"Kotlin": "HullData",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "weaponData",
|
||||
"Slot": "ers_1",
|
||||
"Kotlin": "WeaponData",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "droneData",
|
||||
"Slot": "frs_1",
|
||||
"Kotlin": "DroneData",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "grenadeData",
|
||||
"Slot": "grs_1",
|
||||
"Kotlin": "GrenadeData",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "hasGrenades",
|
||||
"Slot": "hrs_1",
|
||||
"Kotlin": "HasGrenades",
|
||||
"Default": "false"
|
||||
},
|
||||
{
|
||||
"Field": "hullEngineType",
|
||||
"Slot": "irs_1",
|
||||
"Kotlin": "HullEngineType",
|
||||
"Default": "My()"
|
||||
},
|
||||
{
|
||||
"Field": "turretMechanism",
|
||||
"Slot": "jrs_1",
|
||||
"Kotlin": "TurretMechanism",
|
||||
"Default": "Oy()"
|
||||
},
|
||||
{
|
||||
"Field": "paint",
|
||||
"Slot": "krs_1",
|
||||
"Kotlin": "Paint",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "properties",
|
||||
"Slot": "lrs_1",
|
||||
"Kotlin": "Properties",
|
||||
"Default": "md()"
|
||||
},
|
||||
{
|
||||
"Field": "captureScreenshotAction",
|
||||
"Slot": "mrs_1",
|
||||
"Kotlin": "CaptureScreenshotAction",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "captureVideoAction",
|
||||
"Slot": "nrs_1",
|
||||
"Kotlin": "CaptureVideoAction",
|
||||
"Default": "null"
|
||||
},
|
||||
{
|
||||
"Field": "item3dModelActionCache",
|
||||
"Slot": "ors_1",
|
||||
"Kotlin": "Item3dModelActionCache",
|
||||
"Default": "ag()"
|
||||
},
|
||||
{
|
||||
"Field": "requestedItems",
|
||||
"Slot": "prs_1",
|
||||
"Kotlin": "RequestedItems",
|
||||
"Default": "Yg()"
|
||||
},
|
||||
{
|
||||
"Field": "expectedItemId",
|
||||
"Slot": "qrs_1",
|
||||
"Kotlin": "ExpectedItemId",
|
||||
"Default": "ag()"
|
||||
}
|
||||
],
|
||||
"CopyMethod": "trs",
|
||||
"Branches": [
|
||||
{
|
||||
"Guard": "yd(t, is)",
|
||||
"Locals": [],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 7,
|
||||
"Field": "params",
|
||||
"Slot": "crs_1",
|
||||
"Kotlin": "Params",
|
||||
"Value": "null"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, null)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof NG",
|
||||
"Locals": [
|
||||
"NG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 0,
|
||||
"Field": "isVisible",
|
||||
"Slot": "vrr_1",
|
||||
"Kotlin": "IsVisible",
|
||||
"Value": "r"
|
||||
},
|
||||
{
|
||||
"Index": 1,
|
||||
"Field": "photoMode",
|
||||
"Slot": "wrr_1",
|
||||
"Kotlin": "PhotoMode",
|
||||
"Value": "_"
|
||||
},
|
||||
{
|
||||
"Index": 2,
|
||||
"Field": "needVisible",
|
||||
"Slot": "xrr_1",
|
||||
"Kotlin": "NeedVisible",
|
||||
"Value": "e"
|
||||
},
|
||||
{
|
||||
"Index": 3,
|
||||
"Field": "viewStyle",
|
||||
"Slot": "yrr_1",
|
||||
"Kotlin": "ViewStyle",
|
||||
"Value": "u"
|
||||
},
|
||||
{
|
||||
"Index": 5,
|
||||
"Field": "tankPreviewSettings",
|
||||
"Slot": "ars_1",
|
||||
"Kotlin": "TankPreviewSettings",
|
||||
"Value": "s"
|
||||
},
|
||||
{
|
||||
"Index": 6,
|
||||
"Field": "needShowDrone",
|
||||
"Slot": "brs_1",
|
||||
"Kotlin": "NeedShowDrone",
|
||||
"Value": "o"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(r, _, e, u, cd, s, o)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof MG",
|
||||
"Locals": [
|
||||
"MG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 5,
|
||||
"Field": "tankPreviewSettings",
|
||||
"Slot": "ars_1",
|
||||
"Kotlin": "TankPreviewSettings",
|
||||
"Value": "t.zrs_1"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, t.zrs_1)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof OG",
|
||||
"Locals": [
|
||||
"OG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 4,
|
||||
"Field": "dynViewStyle",
|
||||
"Slot": "zrr_1",
|
||||
"Kotlin": "DynViewStyle",
|
||||
"Value": "t.fru_1"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, t.fru_1)"
|
||||
},
|
||||
{
|
||||
"Guard": "yd(t, es)",
|
||||
"Locals": [],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 0,
|
||||
"Field": "isVisible",
|
||||
"Slot": "vrr_1",
|
||||
"Kotlin": "IsVisible",
|
||||
"Value": "!0"
|
||||
},
|
||||
{
|
||||
"Index": 2,
|
||||
"Field": "needVisible",
|
||||
"Slot": "xrr_1",
|
||||
"Kotlin": "NeedVisible",
|
||||
"Value": "!1"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(!0, cd, !1)"
|
||||
},
|
||||
{
|
||||
"Guard": "yd(t, rs)",
|
||||
"Locals": [],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 0,
|
||||
"Field": "isVisible",
|
||||
"Slot": "vrr_1",
|
||||
"Kotlin": "IsVisible",
|
||||
"Value": "!1"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(!1)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof FG",
|
||||
"Locals": [
|
||||
"FG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 7,
|
||||
"Field": "params",
|
||||
"Slot": "crs_1",
|
||||
"Kotlin": "Params",
|
||||
"Value": "t.crt_1"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, t.crt_1)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof HG",
|
||||
"Locals": [
|
||||
"HG"
|
||||
],
|
||||
"Kind": "copy-helper",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 21,
|
||||
"Field": "expectedItemId",
|
||||
"Slot": "qrs_1",
|
||||
"Kotlin": "ExpectedItemId",
|
||||
"Value": "am(n.qrs_1, t.grt_1)"
|
||||
}
|
||||
],
|
||||
"Expr": "null == t.hrt_1 ? n.trs( cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, am(n.qrs_1, t.grt_1), ) : n.trs( cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cg(n.qrs_1, Vd(t.grt_1, t.hrt_1)), )"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof WG",
|
||||
"Locals": [
|
||||
"WG"
|
||||
],
|
||||
"Kind": "copy-helper",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 20,
|
||||
"Field": "requestedItems",
|
||||
"Slot": "prs_1",
|
||||
"Kotlin": "RequestedItems",
|
||||
"Value": "Xg(n.prs_1, t.irt_1)"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs( cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, Xg(n.prs_1, t.irt_1), )"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof VG",
|
||||
"Locals": [
|
||||
"VG"
|
||||
],
|
||||
"Kind": "conditional",
|
||||
"Changed": [],
|
||||
"Expr": "h"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof KG",
|
||||
"Locals": [
|
||||
"KG"
|
||||
],
|
||||
"Kind": "conditional",
|
||||
"Changed": [],
|
||||
"Expr": "v"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof iH",
|
||||
"Locals": [
|
||||
"iH"
|
||||
],
|
||||
"Kind": "conditional",
|
||||
"Changed": [],
|
||||
"Expr": "m"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof ZG",
|
||||
"Locals": [
|
||||
"ZG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 9,
|
||||
"Field": "weaponData",
|
||||
"Slot": "ers_1",
|
||||
"Kotlin": "WeaponData",
|
||||
"Value": "null"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, cd, cd, null)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof QG",
|
||||
"Locals": [
|
||||
"QG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 8,
|
||||
"Field": "hullData",
|
||||
"Slot": "drs_1",
|
||||
"Kotlin": "HullData",
|
||||
"Value": "null"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, cd, null)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof tH",
|
||||
"Locals": [
|
||||
"tH"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 10,
|
||||
"Field": "droneData",
|
||||
"Slot": "frs_1",
|
||||
"Kotlin": "DroneData",
|
||||
"Value": "null"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, null)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof nH",
|
||||
"Locals": [
|
||||
"nH"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 11,
|
||||
"Field": "grenadeData",
|
||||
"Slot": "grs_1",
|
||||
"Kotlin": "GrenadeData",
|
||||
"Value": "null"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, null)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof YG",
|
||||
"Locals": [
|
||||
"YG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 11,
|
||||
"Field": "grenadeData",
|
||||
"Slot": "grs_1",
|
||||
"Kotlin": "GrenadeData",
|
||||
"Value": "b"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, b)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof XG",
|
||||
"Locals": [
|
||||
"XG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 12,
|
||||
"Field": "hasGrenades",
|
||||
"Slot": "hrs_1",
|
||||
"Kotlin": "HasGrenades",
|
||||
"Value": "!0"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, !0)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof JG",
|
||||
"Locals": [
|
||||
"JG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 12,
|
||||
"Field": "hasGrenades",
|
||||
"Slot": "hrs_1",
|
||||
"Kotlin": "HasGrenades",
|
||||
"Value": "!1"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, !1)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof rH",
|
||||
"Locals": [
|
||||
"rH"
|
||||
],
|
||||
"Kind": "copy-helper",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 15,
|
||||
"Field": "paint",
|
||||
"Slot": "krs_1",
|
||||
"Kotlin": "Paint",
|
||||
"Value": "t.bru_1"
|
||||
},
|
||||
{
|
||||
"Index": 19,
|
||||
"Field": "item3dModelActionCache",
|
||||
"Slot": "ors_1",
|
||||
"Kotlin": "Item3dModelActionCache",
|
||||
"Value": "cg(n.ors_1, Vd(t.aru_1, t))"
|
||||
},
|
||||
{
|
||||
"Index": 20,
|
||||
"Field": "requestedItems",
|
||||
"Slot": "prs_1",
|
||||
"Kotlin": "RequestedItems",
|
||||
"Value": "Jg(n.prs_1, t.aru_1)"
|
||||
}
|
||||
],
|
||||
"Expr": "n.rrs(Vk(), t.aru_1) ? n.trs( cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, t.bru_1, cd, cd, cd, cg(n.ors_1, Vd(t.aru_1, t)), Jg(n.prs_1, t.aru_1), ) : n.trs( cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cg(n.ors_1, Vd(t.aru_1, t)), Jg(n.prs_1, t.aru_1), "
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof eH",
|
||||
"Locals": [
|
||||
"eH"
|
||||
],
|
||||
"Kind": "copy-helper",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 19,
|
||||
"Field": "item3dModelActionCache",
|
||||
"Slot": "ors_1",
|
||||
"Kotlin": "Item3dModelActionCache",
|
||||
"Value": "am(n.ors_1, t.cru_1)"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs( cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, am(n.ors_1, t.cru_1), )"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof uH",
|
||||
"Locals": [
|
||||
"uH"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 16,
|
||||
"Field": "properties",
|
||||
"Slot": "lrs_1",
|
||||
"Kotlin": "Properties",
|
||||
"Value": "t.dru_1"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, t.dru_1)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof LG",
|
||||
"Locals": [
|
||||
"LG"
|
||||
],
|
||||
"Kind": "copy",
|
||||
"Changed": [
|
||||
{
|
||||
"Index": 17,
|
||||
"Field": "captureScreenshotAction",
|
||||
"Slot": "mrs_1",
|
||||
"Kotlin": "CaptureScreenshotAction",
|
||||
"Value": "t.art_1"
|
||||
},
|
||||
{
|
||||
"Index": 18,
|
||||
"Field": "captureVideoAction",
|
||||
"Slot": "nrs_1",
|
||||
"Kotlin": "CaptureVideoAction",
|
||||
"Value": "t.brt_1"
|
||||
}
|
||||
],
|
||||
"Expr": "n.trs(cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, t.art_1, t.brt_1)"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof BG",
|
||||
"Locals": [
|
||||
"BG"
|
||||
],
|
||||
"Kind": "noop",
|
||||
"Changed": [],
|
||||
"Expr": "n"
|
||||
},
|
||||
{
|
||||
"Guard": "t instanceof UG",
|
||||
"Locals": [
|
||||
"UG"
|
||||
],
|
||||
"Kind": "noop",
|
||||
"Changed": [],
|
||||
"Expr": "n"
|
||||
},
|
||||
{
|
||||
"Guard": "(else)",
|
||||
"Locals": [],
|
||||
"Kind": "noop",
|
||||
"Changed": [],
|
||||
"Expr": "n"
|
||||
}
|
||||
],
|
||||
"SubReducers": [],
|
||||
"Counts": {
|
||||
"TotalInstanceof": 22,
|
||||
"TopLevelBranches": 26,
|
||||
"SubReducerArms": 0
|
||||
},
|
||||
"Locals": {
|
||||
"NG": {
|
||||
"Name": "ShowRequest"
|
||||
},
|
||||
"MG": {
|
||||
"Name": "UpdatePreviewSettings"
|
||||
},
|
||||
"OG": {
|
||||
"Name": null
|
||||
},
|
||||
"FG": {
|
||||
"Name": "InitGarageResources"
|
||||
},
|
||||
"HG": {
|
||||
"Name": "SetExpectedItemId"
|
||||
},
|
||||
"WG": {
|
||||
"Name": "AddRequestedItem"
|
||||
},
|
||||
"VG": {
|
||||
"Name": null
|
||||
},
|
||||
"KG": {
|
||||
"Name": null
|
||||
},
|
||||
"iH": {
|
||||
"Name": "SetDrone"
|
||||
},
|
||||
"ZG": {
|
||||
"Name": null
|
||||
},
|
||||
"QG": {
|
||||
"Name": null
|
||||
},
|
||||
"tH": {
|
||||
"Name": null
|
||||
},
|
||||
"nH": {
|
||||
"Name": null
|
||||
},
|
||||
"YG": {
|
||||
"Name": null
|
||||
},
|
||||
"XG": {
|
||||
"Name": null
|
||||
},
|
||||
"JG": {
|
||||
"Name": null
|
||||
},
|
||||
"rH": {
|
||||
"Name": "SetPaint"
|
||||
},
|
||||
"eH": {
|
||||
"Name": "ResetItem3dModelActionCache"
|
||||
},
|
||||
"uH": {
|
||||
"Name": "SetMountedItemsProperties"
|
||||
},
|
||||
"LG": {
|
||||
"Name": "SetCaptureActions"
|
||||
},
|
||||
"BG": {
|
||||
"Name": null
|
||||
},
|
||||
"UG": {
|
||||
"Name": null
|
||||
}
|
||||
},
|
||||
"Delegate": "fs.eru(t, n.epv_1)",
|
||||
"CopyParamCount": 23,
|
||||
"CopyMatchesFields": false
|
||||
}
|
||||
@@ -635,6 +635,12 @@ const FieldTypeOverrides = new Map([
|
||||
['AddToFavoriteItem.itemId', 'Long'],
|
||||
['RemoveFromFavoriteItem.itemId', 'Long'],
|
||||
['BuyProtectionSlot.slotToUnlock', 'Int'],
|
||||
// garagePreview 切片:状态里这些字段参与 Long/Boolean/Set 运算;动作字段来自真实派发。
|
||||
['ShowRequest.needShowDrone', 'Boolean'],
|
||||
['AddRequestedItem.itemId', 'Long'],
|
||||
['ResetItem3dModelActionCache.itemId', 'Long'],
|
||||
['SetCaptureActions.screenshotAction', '(() -> Unit)?'],
|
||||
['SetCaptureActions.videoAction', '(() -> Unit)?'],
|
||||
]);
|
||||
|
||||
const Emitted = [];
|
||||
|
||||
@@ -102,6 +102,23 @@ const AnonymousActionNames = new Map([
|
||||
['WB', 'HideVideoInDescription'],
|
||||
['OU', 'RemoveWaitServerItemMount'],
|
||||
['FB', 'ClearWaitServerItemMount'],
|
||||
// garagePreview 切片(IG / fs.eru):12 个没有 toString 的 instanceof 动作 + 3 个单例动作。
|
||||
// 括号里是原 reducer 的效果;实现见 GaragePreviewReducer.kt。
|
||||
['BG', 'CaptureScreenshot'],
|
||||
['UG', 'CaptureVideo'],
|
||||
['JG', 'ClearHasGrenades'],
|
||||
['KG', 'SetWeaponData'],
|
||||
['OG', 'UpdateViewStyle'],
|
||||
['QG', 'ClearHullData'],
|
||||
['VG', 'SetHullData'],
|
||||
['XG', 'SetHasGrenades'],
|
||||
['YG', 'SetGrenadeData'],
|
||||
['ZG', 'ClearWeaponData'],
|
||||
['nH', 'ClearGrenadeData'],
|
||||
['tH', 'ClearDroneData'],
|
||||
['is', 'ClearGaragePreviewParams'],
|
||||
['es', 'ShowGaragePreview'],
|
||||
['rs', 'HideGaragePreview'],
|
||||
]);
|
||||
|
||||
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
||||
@@ -471,6 +488,7 @@ const Migrated = {
|
||||
screen: { Type: 'ScreenStateSlice', Reduce: 'ReduceScreen' },
|
||||
lootBoxes: { Type: 'LootBoxesStateSlice', Reduce: 'ReduceLootBoxes' },
|
||||
garage: { Type: 'GarageStateSlice', Reduce: 'ReduceGarage' },
|
||||
garagePreview: { Type: 'GaragePreviewStateSlice', Reduce: 'ReduceGaragePreview' },
|
||||
};
|
||||
|
||||
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
||||
@@ -564,6 +582,25 @@ const GarageAnonymousEffects = {
|
||||
FB: 'waitServerItemMount = emptyMap()',
|
||||
};
|
||||
|
||||
// garagePreview 切片(IG / fs.eru):没有 toString / 不在 action_inventory 的类,按 reducer 分支效果定名。
|
||||
const GaragePreviewAnonymousEffects = {
|
||||
BG: '调用 captureScreenshotAction(),状态不变(`null == y || y(), i = n`)',
|
||||
UG: '调用 captureVideoAction(),状态不变(`null == $ || $(), i = n`)',
|
||||
JG: 'hasGrenades = false(第 13 个构造参数 !1)',
|
||||
KG: '若 expectedItemId[WEAPON] 命中,则 weaponData = TankPartData(resource, emissionColors)、turretMechanism = action;并缓存动作、从 requestedItems 删除 itemId',
|
||||
OG: 'UpdateViewStyle:动作类没有字段,原 `t.fru_1` 为 undefined,`trs` 视作省略,状态不变',
|
||||
QG: 'hullData = null(第 9 个构造参数 null)',
|
||||
VG: '若 expectedItemId[ARMOR] 命中,则 hullData = TankPartData(6 字段)、hullEngineType = action;并缓存动作、从 requestedItems 删除 itemId',
|
||||
XG: 'hasGrenades = true(第 13 个构造参数 !0)',
|
||||
YG: 'grenadeData = resource == null ? null : TankPartData(resource, emissionColors)(第 12 个构造参数)',
|
||||
ZG: 'weaponData = null(第 10 个构造参数 null)',
|
||||
nH: 'grenadeData = null(第 12 个构造参数 null)',
|
||||
tH: 'droneData = null(第 11 个构造参数 null)',
|
||||
is: 'params = null(第 8 个构造参数 null)',
|
||||
es: 'isVisible = true、needVisible = false(`n.trs(!0, cd, !1)`)',
|
||||
rs: 'isVisible = false(`n.trs(!1)`)',
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(P, 'names', 'root_wiring.json'),
|
||||
JSON.stringify(
|
||||
@@ -604,6 +641,12 @@ fs.writeFileSync(
|
||||
DispatchedAt: '未在 action_trace_merged.json 中出现;按 reducer 分支效果定名',
|
||||
Effect,
|
||||
})),
|
||||
...Object.entries(GaragePreviewAnonymousEffects).map(([Local, Effect]) => ({
|
||||
Local,
|
||||
Name: AnonymousActionNames.get(Local),
|
||||
DispatchedAt: '未在 action_trace_merged.json 中出现;按 reducer 分支效果定名',
|
||||
Effect,
|
||||
})),
|
||||
],
|
||||
Markers: [
|
||||
{
|
||||
|
||||
@@ -201,7 +201,11 @@ function FindGuards(Text) {
|
||||
const C = M[I];
|
||||
if ('([{'.includes(C)) { Depth++; I++; continue; }
|
||||
if (')]}'.includes(C)) { Depth--; I++; continue; }
|
||||
if (Depth === 0 && M.startsWith('if (', I) && M.slice(I, I + 80).includes('instanceof')) {
|
||||
if (
|
||||
Depth === 0 &&
|
||||
M.startsWith('if (', I) &&
|
||||
(M.slice(I, I + 80).includes('instanceof') || M.slice(I, I + 80).includes('yd(t,'))
|
||||
) {
|
||||
const OpenP = I + 3;
|
||||
let D = 0, J = OpenP;
|
||||
for (; J < Text.length; J++) { const D0 = M[J]; if (D0 === '(') D++; else if (D0 === ')') { D--; if (D === 0) break; } }
|
||||
@@ -274,6 +278,7 @@ function PlanSlice(Field) {
|
||||
// 第 2 种需要回查被调函数的函数体,确认它确实读写 `n.<slot>`。
|
||||
let A = Assignments.find((X) => new RegExp('\\bn\\.' + F.Slot + '\\b').test(X.Expr));
|
||||
let NamedReducer = null;
|
||||
let NamedBody = null;
|
||||
if (!A) {
|
||||
for (const X of Assignments) {
|
||||
const Call = /^([A-Za-z0-9_$]+)\(t,\s*n\)$/.exec(X.Expr.replace(/\s+/g, ' ').trim());
|
||||
@@ -282,12 +287,28 @@ function PlanSlice(Field) {
|
||||
if (new RegExp('\\bn\\.' + F.Slot + '\\b').test(T.slice(Fn.Body, Fn.End))) {
|
||||
A = X;
|
||||
NamedReducer = Call[1];
|
||||
NamedBody = T.slice(Fn.Body, Fn.End);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!A) throw new Error(Field + ' 在根 reducer 里找不到委派');
|
||||
|
||||
// 第 3 种:根 reducer 直接调用对象方法,`fs.eru(t, n.epv_1)`(garagePreview)。
|
||||
// 方法体在 Methods 表里,和具名 reducer 一样按字段数锁定 copy 方法。
|
||||
if (!NamedBody) {
|
||||
const MCall = /^([A-Za-z0-9_$]+)\.([A-Za-z0-9_$]+)\(t,\s*n\.[A-Za-z0-9_$]+\)$/.exec(
|
||||
A.Expr.replace(/\s+/g, ' ').trim(),
|
||||
);
|
||||
if (MCall) {
|
||||
const M = FindMethod(MCall[1], MCall[2]) || Methods.find((X) => X.Method === MCall[2]);
|
||||
if (M) {
|
||||
NamedReducer = MCall[1] + '.' + MCall[2];
|
||||
NamedBody = T.slice(M.Body, M.End);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Param = [...SlotOfParam.keys()].find((P2) => SlotOfParam.get(P2) === F.Slot);
|
||||
const SliceClass = (DefaultOfParam.get(Param) || '').match(/^new ([A-Za-z0-9_$]+)\(/);
|
||||
const ClassName = SliceClass ? SliceClass[1] : null;
|
||||
@@ -319,13 +340,11 @@ function PlanSlice(Field) {
|
||||
}
|
||||
|
||||
const CopyName = (A.Expr.match(/\bn\.([A-Za-z0-9_$]+)\(/) || [])[1] || null;
|
||||
// 具名 reducer 的副本方法只在函数体里(`o.hri(...)`),按「参数个数 == 字段数」锁定。
|
||||
let NamedBody = null;
|
||||
if (NamedReducer) {
|
||||
const Fn = Fns.get(NamedReducer);
|
||||
NamedBody = T.slice(Fn.Body, Fn.End);
|
||||
// 具名 reducer / 对象方法 reducer 的副本方法只在函数体里(`o.hri(...)` 或 `n.trs(...)`),
|
||||
// 按「参数个数 == 字段数」锁定。
|
||||
if (NamedBody) {
|
||||
const ByArity = [];
|
||||
for (const M of NamedBody.matchAll(/\bo\.([A-Za-z0-9_$]+)\(/g)) {
|
||||
for (const M of NamedBody.matchAll(/\b(?:o|n)\.([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];
|
||||
|
||||
@@ -331,16 +331,16 @@ object ActionCatalog {
|
||||
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?"))),
|
||||
ActionMeta("ShowRequest", ShowRequest::class, listOf(ActionFieldMeta("viewStyle", "Any?"), ActionFieldMeta("tankPreviewSettings", "Any?"), ActionFieldMeta("needShowDrone", "Any?"), ActionFieldMeta("photoMode", "Boolean"), ActionFieldMeta("withDelay", "Boolean"))),
|
||||
ActionMeta("ShowRequest", ShowRequest::class, listOf(ActionFieldMeta("viewStyle", "Any?"), ActionFieldMeta("tankPreviewSettings", "Any?"), ActionFieldMeta("needShowDrone", "Boolean"), ActionFieldMeta("photoMode", "Boolean"), ActionFieldMeta("withDelay", "Boolean"))),
|
||||
ActionMeta("UpdatePreviewSettings", UpdatePreviewSettings::class, listOf(ActionFieldMeta("tankPreviewSettings", "Any?"))),
|
||||
ActionMeta("SetCaptureActions", SetCaptureActions::class, listOf(ActionFieldMeta("screenshotAction", "Any?"), ActionFieldMeta("videoAction", "Any?"))),
|
||||
ActionMeta("SetCaptureActions", SetCaptureActions::class, listOf(ActionFieldMeta("screenshotAction", "(() -> Unit)?"), ActionFieldMeta("videoAction", "(() -> Unit)?"))),
|
||||
ActionMeta("InitGarageResources", InitGarageResources::class, listOf(ActionFieldMeta("params", "GaragePreviewModelCC"))),
|
||||
ActionMeta("SetFromCacheOrRequest", SetFromCacheOrRequest::class, listOf(ActionFieldMeta("item", "Any?"), ActionFieldMeta("request", "Any?"))),
|
||||
ActionMeta("SetExpectedItemId", SetExpectedItemId::class, listOf(ActionFieldMeta("category", "Any?"), ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("AddRequestedItem", AddRequestedItem::class, listOf(ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("AddRequestedItem", AddRequestedItem::class, listOf(ActionFieldMeta("itemId", "Long"))),
|
||||
ActionMeta("SetDrone", SetDrone::class, listOf(ActionFieldMeta("itemId", "Long"), ActionFieldMeta("resource", "Any?"), ActionFieldMeta("emissionColors", "EmissionColors"))),
|
||||
ActionMeta("SetPaint", SetPaint::class, listOf(ActionFieldMeta("itemId", "Long"), ActionFieldMeta("paint", "Coloring"))),
|
||||
ActionMeta("ResetItem3dModelActionCache", ResetItem3dModelActionCache::class, listOf(ActionFieldMeta("itemId", "Any?"))),
|
||||
ActionMeta("ResetItem3dModelActionCache", ResetItem3dModelActionCache::class, listOf(ActionFieldMeta("itemId", "Long"))),
|
||||
ActionMeta("SetMountedItemsProperties", SetMountedItemsProperties::class, listOf(ActionFieldMeta("properties", "List<String>"))),
|
||||
ActionMeta("IconsState", IconsState::class, listOf(ActionFieldMeta("icons", "Any?"))),
|
||||
ActionMeta("SetIcons", SetIcons::class, listOf(ActionFieldMeta("icons", "List<IconData>"))),
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// GaragePreviewModels.kt —— garagePreview 切片里来自其它模块的嵌套模型(原 module_10032 的 IG / fs.eru)
|
||||
//
|
||||
// 证据链:
|
||||
// · TankPartData(module_03569 的 th,导出名 s7):构造 6 字段
|
||||
// `function th(t, n, i, r, e, u)`,toString 为
|
||||
// `TankPartData(resource, emissionColors, turretMountPoint, skinOffset,
|
||||
// leftTrackTexToWorldRatio, rightTrackTexToWorldRatio)`。
|
||||
// 原 reducer 的 VG/KG/iH/YG 分支都用 `new Dy(…)` 构造它。
|
||||
// · TankPreviewSettings(module_03569 的 lh,导出名 v7):构造 10 字段,
|
||||
// toString 为 `TankPreviewSettings(cameraHeight, distanceToTank, lookAtZOffset,
|
||||
// lookAtXOffset, cameraFov, tankZ, lightSettings, hasReflection,
|
||||
// reflectionAlpha, reflectionAlphaDistant)`。
|
||||
// · HullEngineType:module_85196 的 `zw` 枚举,`TRACKED(0)` / `HOVER(1)`;
|
||||
// 原 `My = p.$_$.k3` 返回 `TRACKED`,是 IG 的默认值。
|
||||
// · TurretMechanism:module_85196 的 `Fw` 枚举,`ROTATING_TURRET(0)` / `ELEVATING_BARREL(1)`;
|
||||
// 原 `Oy = p.$_$.m3` 返回 `ROTATING_TURRET`,是 IG 的默认值。
|
||||
package App.State
|
||||
|
||||
/** 原 `TankPreviewLightSettings`(module_03569 的 fh):只占位,本切片不读取其字段。 */
|
||||
data class TankPreviewLightSettings(
|
||||
val ambientColor: Any? = null,
|
||||
val lightColor: Any? = null,
|
||||
val lightDirection: Any? = null,
|
||||
val additionalLightDirection: Any? = null,
|
||||
)
|
||||
|
||||
/** 原 `TankPreviewSettings`(module_03569 的 lh):默认值取构造函数。 */
|
||||
data class TankPreviewSettings(
|
||||
val cameraHeight: Int = 300,
|
||||
val distanceToTank: Int = 1750,
|
||||
val lookAtZOffset: Int = 90,
|
||||
val lookAtXOffset: Int = 0,
|
||||
val cameraFov: Double = 0.5,
|
||||
val tankZ: Int = 120,
|
||||
val lightSettings: TankPreviewLightSettings = TankPreviewLightSettings(),
|
||||
val hasReflection: Boolean = true,
|
||||
val reflectionAlpha: Double = 0.2,
|
||||
val reflectionAlphaDistant: Double = 0.08,
|
||||
)
|
||||
|
||||
/** 原 `TankPartData`(module_03569 的 th):车体 / 炮塔 / 无人机 / 手雷的 3D 资源数据。 */
|
||||
data class TankPartData(
|
||||
val resource: Any? = null,
|
||||
val emissionColors: EmissionColors? = null,
|
||||
val turretMountPoint: Any? = null,
|
||||
val skinOffset: Any? = null,
|
||||
val leftTrackTexToWorldRatio: Int = 0,
|
||||
val rightTrackTexToWorldRatio: Int = 0,
|
||||
)
|
||||
|
||||
/** 原 `zw` 枚举:履带式 / 悬浮式。 */
|
||||
enum class HullEngineType {
|
||||
TRACKED,
|
||||
HOVER,
|
||||
}
|
||||
|
||||
/** 原 `Fw` 枚举:旋转炮塔 / 俯仰炮管。 */
|
||||
enum class TurretMechanism {
|
||||
ROTATING_TURRET,
|
||||
ELEVATING_BARREL,
|
||||
}
|
||||
@@ -5,7 +5,7 @@ package App.State
|
||||
|
||||
import Core.Vector3
|
||||
|
||||
// 动作/状态类共 816 个,字段 2150 个(已定类型 567 个)
|
||||
// 动作/状态类共 816 个,字段 2150 个(已定类型 572 个)
|
||||
data class AnnouncementState(
|
||||
val isEnabled: Any?, // 仅 copy 转发(无类型信息)
|
||||
val modelLoaded: Any?, // 仅 copy 转发(无类型信息)
|
||||
@@ -1934,7 +1934,7 @@ data class GaragePreview(
|
||||
data class ShowRequest(
|
||||
val viewStyle: Any?, // 调用点: new nE(hNn().x1iy()) | t
|
||||
val tankPreviewSettings: Any?, // 调用点: new tE(350, 1200, 180, $q, 0.6, 0, $q, ! | Mrt(this)
|
||||
val needShowDrone: Any?, // 调用点: $q | $q
|
||||
val needShowDrone: Boolean, // override
|
||||
val photoMode: Boolean, // callsite
|
||||
val withDelay: Boolean, // callsite
|
||||
)
|
||||
@@ -1944,8 +1944,8 @@ data class UpdatePreviewSettings(
|
||||
)
|
||||
|
||||
data class SetCaptureActions(
|
||||
val screenshotAction: Any?, // 调用点: r | null
|
||||
val videoAction: Any?, // 调用点: (function (t) { var n = func | null
|
||||
val screenshotAction: (() -> Unit)?, // override
|
||||
val videoAction: (() -> Unit)?, // override
|
||||
)
|
||||
|
||||
data class InitGarageResources(
|
||||
@@ -1963,7 +1963,7 @@ data class SetExpectedItemId(
|
||||
)
|
||||
|
||||
data class AddRequestedItem(
|
||||
val itemId: Any?, // 调用点: n | n
|
||||
val itemId: Long, // override
|
||||
)
|
||||
|
||||
data class SetDrone(
|
||||
@@ -1978,7 +1978,7 @@ data class SetPaint(
|
||||
)
|
||||
|
||||
data class ResetItem3dModelActionCache(
|
||||
val itemId: Any?, // 调用点: t.zas_1.r1pm_1.zr9_1
|
||||
val itemId: Long, // override
|
||||
)
|
||||
|
||||
data class SetMountedItemsProperties(
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
// GaragePreviewReducer.kt —— 车库 3D 预览切片(对应 module_10032 的 IG 状态 + fs.eru reducer)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 IG:`function IG(t, n, i, r, e, u, s, o, _, h, a, c, l, f, v, p, w, d, g, m, k, z)`,
|
||||
// 22 个字段,toString 名为 `GaragePreview(isVisible=…, …, expectedItemId=…)`。默认值取自构造:
|
||||
// isVisible / photoMode / needVisible = false,viewStyle / dynViewStyle = null,
|
||||
// tankPreviewSettings = new Ny()(TankPreviewSettings()),needShowDrone = false,
|
||||
// params / hullData / weaponData / droneData / grenadeData / paint = null,hasGrenades = false,
|
||||
// hullEngineType = My()(TRACKED),turretMechanism = Oy()(ROTATING_TURRET),
|
||||
// properties = md()(emptyList),captureScreenshotAction / captureVideoAction = null,
|
||||
// item3dModelActionCache / expectedItemId = ag()(emptyMap),requestedItems = Yg()(HashSet)。
|
||||
//
|
||||
// 根委派:`fs.eru(t, n.epv_1)`。eru 有 25 个顶层臂:
|
||||
// 22 个 instanceof 动作(10 个具名 + 12 个匿名) + 3 个单例动作
|
||||
// (`yd(t, is)` / `yd(t, es)` / `yd(t, rs)`,不在 root_wiring 的 Actions 表里)。
|
||||
//
|
||||
// 关键语义(`trs` 是 IG.copy,参数省略时保留原字段):
|
||||
// · ShowRequest 不是简单展示:withDelay 为 true 时 isVisible=false、needVisible=true。
|
||||
// · UpdateViewStyle(OG)没有字段,原 `t.fru_1` 是 undefined,`trs` 把它当省略,状态不变。
|
||||
// · SetHullData / SetWeaponData / SetDrone / SetPaint 先查 `rrs(category, itemId)`:
|
||||
// 仅当 expectedItemId[category] 为 null 或等于 itemId 时才写 3D 数据;
|
||||
// 无论是否命中,都会把动作写入 item3dModelActionCache 并从 requestedItems 删除 itemId。
|
||||
// · ClearHullData / ClearWeaponData / ClearDroneData / ClearGrenadeData 分别置空对应数据。
|
||||
// · SetGrenadeData 不写缓存、不删 requestedItems,只按 resource 是否为空写 grenadeData。
|
||||
// · CaptureScreenshot / CaptureVideo 只调用回调,返回原状态。
|
||||
// · ClearGaragePreviewParams / ShowGaragePreview / HideGaragePreview 是三个单例臂。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.AddRequestedItem
|
||||
import App.State.Coloring
|
||||
import App.State.EmissionColors
|
||||
import App.State.GaragePreviewModelCC
|
||||
import App.State.HullEngineType
|
||||
import App.State.InitGarageResources
|
||||
import App.State.ResetItem3dModelActionCache
|
||||
import App.State.SetCaptureActions
|
||||
import App.State.SetDrone
|
||||
import App.State.SetExpectedItemId
|
||||
import App.State.SetMountedItemsProperties
|
||||
import App.State.SetPaint
|
||||
import App.State.ShowRequest
|
||||
import App.State.TankPartData
|
||||
import App.State.TankPreviewSettings
|
||||
import App.State.TurretMechanism
|
||||
import App.State.UpdatePreviewSettings
|
||||
|
||||
/** 原 `vo` 物品分类枚举里本切片用到的键(module_85667 的 `Wt/Vt/Kt/on`)。 */
|
||||
const val PreviewWeaponCategory: Int = 0
|
||||
const val PreviewHullCategory: Int = 1
|
||||
const val PreviewPaintCategory: Int = 2
|
||||
const val PreviewDroneCategory: Int = 14
|
||||
|
||||
/* ------------------------------------------------------------------ 匿名动作 */
|
||||
// 12 个没有 toString 的 instanceof 动作,按 reducer 分支效果定名(证据见 gen_root_wiring.js)。
|
||||
class CaptureScreenshot
|
||||
class CaptureVideo
|
||||
class ClearHasGrenades
|
||||
class SetHasGrenades
|
||||
class UpdateViewStyle
|
||||
class ClearHullData
|
||||
class ClearWeaponData
|
||||
class ClearDroneData
|
||||
class ClearGrenadeData
|
||||
|
||||
data class SetHullData(
|
||||
val itemId: Long,
|
||||
val hullEngineType: HullEngineType,
|
||||
val resource: Any?,
|
||||
val emissionColors: EmissionColors?,
|
||||
val turretMountPoint: Any?,
|
||||
val skinOffset: Any?,
|
||||
val leftTrackTexToWorldRatio: Int,
|
||||
val rightTrackTexToWorldRatio: Int,
|
||||
) {
|
||||
fun ToTankPartData(): TankPartData = TankPartData(
|
||||
resource = resource,
|
||||
emissionColors = emissionColors,
|
||||
turretMountPoint = turretMountPoint,
|
||||
skinOffset = skinOffset,
|
||||
leftTrackTexToWorldRatio = leftTrackTexToWorldRatio,
|
||||
rightTrackTexToWorldRatio = rightTrackTexToWorldRatio,
|
||||
)
|
||||
}
|
||||
|
||||
data class SetWeaponData(
|
||||
val itemId: Long,
|
||||
val turretMechanism: TurretMechanism,
|
||||
val resource: Any?,
|
||||
val emissionColors: EmissionColors?,
|
||||
) {
|
||||
fun ToTankPartData(): TankPartData = TankPartData(
|
||||
resource = resource,
|
||||
emissionColors = emissionColors,
|
||||
)
|
||||
}
|
||||
|
||||
data class SetGrenadeData(
|
||||
val resource: Any?,
|
||||
val emissionColors: EmissionColors?,
|
||||
) {
|
||||
fun ToTankPartData(): TankPartData = TankPartData(
|
||||
resource = resource,
|
||||
emissionColors = emissionColors,
|
||||
)
|
||||
}
|
||||
|
||||
/** 三个单例动作(原 `is` / `es` / `rs`,不在 root_wiring 的 Actions 表里)。 */
|
||||
class ClearGaragePreviewParams
|
||||
class ShowGaragePreview
|
||||
class HideGaragePreview
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class GaragePreviewStateSlice(
|
||||
val IsVisible: Boolean = false,
|
||||
val PhotoMode: Boolean = false,
|
||||
val NeedVisible: Boolean = false,
|
||||
val ViewStyle: Any? = null,
|
||||
val DynViewStyle: Any? = null,
|
||||
val TankPreviewSettings: Any? = TankPreviewSettings(),
|
||||
val NeedShowDrone: Boolean = false,
|
||||
val Params: GaragePreviewModelCC? = null,
|
||||
val HullData: TankPartData? = null,
|
||||
val WeaponData: TankPartData? = null,
|
||||
val DroneData: TankPartData? = null,
|
||||
val GrenadeData: TankPartData? = null,
|
||||
val HasGrenades: Boolean = false,
|
||||
val HullEngineType: HullEngineType = App.State.HullEngineType.TRACKED,
|
||||
val TurretMechanism: TurretMechanism = App.State.TurretMechanism.ROTATING_TURRET,
|
||||
val Paint: Coloring? = null,
|
||||
val Properties: List<String> = emptyList(),
|
||||
val CaptureScreenshotAction: (() -> Unit)? = null,
|
||||
val CaptureVideoAction: (() -> Unit)? = null,
|
||||
val Item3dModelActionCache: Map<Long, Any> = emptyMap(),
|
||||
val RequestedItems: Set<Long> = emptySet(),
|
||||
val ExpectedItemId: Map<Any?, Any?> = emptyMap(),
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ 小工具 */
|
||||
|
||||
/** 原 `IG.rrs(category, itemId)`:expectedItemId[category] 为 null 或等于 itemId。 */
|
||||
private fun GaragePreviewStateSlice.Rrs(Category: Any?, ItemId: Any?): Boolean {
|
||||
val Expected = ExpectedItemId[Category]
|
||||
return Expected == null || Expected == ItemId
|
||||
}
|
||||
|
||||
private fun <T> Map<Long, T>.With(ItemId: Long, Value: T): Map<Long, T> = this + (ItemId to Value)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
fun ReduceGaragePreview(State0: GaragePreviewStateSlice, Action: Any): GaragePreviewStateSlice = when (Action) {
|
||||
is ClearGaragePreviewParams -> State0.copy(Params = null)
|
||||
is ShowGaragePreview -> State0.copy(IsVisible = true, NeedVisible = false)
|
||||
is HideGaragePreview -> State0.copy(IsVisible = false)
|
||||
|
||||
is ShowRequest -> State0.copy(
|
||||
// 原:`var r = !t.yrs_1 && n.vrr_1, e = !!t.yrs_1 || n.xrr_1`。
|
||||
IsVisible = !Action.withDelay && State0.IsVisible,
|
||||
PhotoMode = Action.photoMode,
|
||||
NeedVisible = Action.withDelay || State0.NeedVisible,
|
||||
ViewStyle = Action.viewStyle,
|
||||
TankPreviewSettings = Action.tankPreviewSettings,
|
||||
NeedShowDrone = Action.needShowDrone,
|
||||
)
|
||||
|
||||
is UpdatePreviewSettings -> State0.copy(TankPreviewSettings = Action.tankPreviewSettings)
|
||||
is UpdateViewStyle -> State0
|
||||
|
||||
is InitGarageResources -> State0.copy(Params = Action.params)
|
||||
|
||||
is SetExpectedItemId -> {
|
||||
// 原:itemId == null ? am(map, category) : cg(map, category to itemId)。
|
||||
val NewExpected = if (Action.itemId == null) {
|
||||
State0.ExpectedItemId - Action.category
|
||||
} else {
|
||||
State0.ExpectedItemId + (Action.category to Action.itemId)
|
||||
}
|
||||
State0.copy(ExpectedItemId = NewExpected)
|
||||
}
|
||||
|
||||
is AddRequestedItem -> State0.copy(RequestedItems = State0.RequestedItems + Action.itemId)
|
||||
|
||||
is SetHullData -> {
|
||||
val Matches = State0.Rrs(PreviewHullCategory, Action.itemId)
|
||||
State0.copy(
|
||||
HullData = if (Matches) Action.ToTankPartData() else State0.HullData,
|
||||
HullEngineType = if (Matches) Action.hullEngineType else State0.HullEngineType,
|
||||
Item3dModelActionCache = State0.Item3dModelActionCache.With(Action.itemId, Action),
|
||||
RequestedItems = State0.RequestedItems - Action.itemId,
|
||||
)
|
||||
}
|
||||
|
||||
is SetWeaponData -> {
|
||||
val Matches = State0.Rrs(PreviewWeaponCategory, Action.itemId)
|
||||
State0.copy(
|
||||
WeaponData = if (Matches) Action.ToTankPartData() else State0.WeaponData,
|
||||
TurretMechanism = if (Matches) Action.turretMechanism else State0.TurretMechanism,
|
||||
Item3dModelActionCache = State0.Item3dModelActionCache.With(Action.itemId, Action),
|
||||
RequestedItems = State0.RequestedItems - Action.itemId,
|
||||
)
|
||||
}
|
||||
|
||||
is SetDrone -> {
|
||||
val Matches = State0.Rrs(PreviewDroneCategory, Action.itemId)
|
||||
val Data = if (Action.resource == null) null else TankPartData(
|
||||
resource = Action.resource,
|
||||
emissionColors = Action.emissionColors,
|
||||
)
|
||||
State0.copy(
|
||||
DroneData = if (Matches) Data else State0.DroneData,
|
||||
Item3dModelActionCache = State0.Item3dModelActionCache.With(Action.itemId, Action),
|
||||
RequestedItems = State0.RequestedItems - Action.itemId,
|
||||
)
|
||||
}
|
||||
|
||||
is SetGrenadeData -> State0.copy(
|
||||
GrenadeData = if (Action.resource == null) null else Action.ToTankPartData(),
|
||||
)
|
||||
|
||||
is ClearWeaponData -> State0.copy(WeaponData = null)
|
||||
is ClearHullData -> State0.copy(HullData = null)
|
||||
is ClearDroneData -> State0.copy(DroneData = null)
|
||||
is ClearGrenadeData -> State0.copy(GrenadeData = null)
|
||||
|
||||
is SetHasGrenades -> State0.copy(HasGrenades = true)
|
||||
is ClearHasGrenades -> State0.copy(HasGrenades = false)
|
||||
|
||||
is SetPaint -> {
|
||||
val Matches = State0.Rrs(PreviewPaintCategory, Action.itemId)
|
||||
State0.copy(
|
||||
Paint = if (Matches) Action.paint else State0.Paint,
|
||||
Item3dModelActionCache = State0.Item3dModelActionCache.With(Action.itemId, Action),
|
||||
RequestedItems = State0.RequestedItems - Action.itemId,
|
||||
)
|
||||
}
|
||||
|
||||
is ResetItem3dModelActionCache ->
|
||||
State0.copy(Item3dModelActionCache = State0.Item3dModelActionCache - Action.itemId)
|
||||
|
||||
is SetMountedItemsProperties -> State0.copy(Properties = Action.properties)
|
||||
|
||||
is SetCaptureActions -> State0.copy(
|
||||
CaptureScreenshotAction = Action.screenshotAction,
|
||||
CaptureVideoAction = Action.videoAction,
|
||||
)
|
||||
|
||||
is CaptureScreenshot -> {
|
||||
State0.CaptureScreenshotAction?.invoke()
|
||||
State0
|
||||
}
|
||||
|
||||
is CaptureVideo -> {
|
||||
State0.CaptureVideoAction?.invoke()
|
||||
State0
|
||||
}
|
||||
|
||||
else -> State0
|
||||
}
|
||||
@@ -12,13 +12,15 @@
|
||||
// screen → ReduceScreen(WK / dY().ks5)
|
||||
// lootBoxes → ReduceLootBoxes(aH / EH.wrv)
|
||||
// garage → ReduceGarage(UB / hF,根委派 `i = hF(t, n)`)
|
||||
// garagePreview → ReduceGaragePreview(IG / fs.eru,根委派 `fs.eru(t, n.epv_1)`)
|
||||
//
|
||||
// 其余 80 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 其余 79 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
||||
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
||||
package App.State
|
||||
|
||||
import App.State.Reducers.ReduceGarage
|
||||
import App.State.Reducers.ReduceGaragePreview
|
||||
import App.State.Reducers.ReduceHome
|
||||
import App.State.Reducers.ReduceInvite
|
||||
import App.State.Reducers.ReduceLocalBattleUser
|
||||
@@ -50,6 +52,7 @@ object RootReducer {
|
||||
Screen = ReduceScreen(State0.Screen, Action),
|
||||
LootBoxes = ReduceLootBoxes(State0.LootBoxes, Action),
|
||||
Garage = ReduceGarage(State0.Garage, Action),
|
||||
GaragePreview = ReduceGaragePreview(State0.GaragePreview, Action),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package App.State
|
||||
|
||||
import App.State.Reducers.GarageStateSlice
|
||||
import App.State.Reducers.GaragePreviewStateSlice
|
||||
import App.State.Reducers.HomeStateSlice
|
||||
import App.State.Reducers.InviteStateSlice
|
||||
import App.State.Reducers.LocalBattleUserStateSlice
|
||||
@@ -31,8 +32,8 @@ data class RootState(
|
||||
val BattleTutorial: Any? = null,
|
||||
/** 原 garage(UB / hF)。已迁移。 */
|
||||
val Garage: GarageStateSlice = GarageStateSlice(),
|
||||
/** 原 garagePreview(IG / fs.eru)。未迁移:原样透传。 */
|
||||
val GaragePreview: Any? = null,
|
||||
/** 原 garagePreview(IG / fs.eru)。已迁移。 */
|
||||
val GaragePreview: GaragePreviewStateSlice = GaragePreviewStateSlice(),
|
||||
/** 原 challenges(CZ / nh.hsj)。未迁移:原样透传。 */
|
||||
val Challenges: Any? = null,
|
||||
/** 原 loginByPassword(gD / nu.cr6)。已迁移。 */
|
||||
|
||||
@@ -20,7 +20,7 @@ object RootWiring {
|
||||
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("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("garagePreview", "epv_1", "IG", "fs.eru", "fs.eru(t, n.epv_1)", listOf("AddRequestedItem", "CaptureScreenshot", "CaptureVideo", "ClearDroneData", "ClearGrenadeData", "ClearHasGrenades", "ClearHullData", "ClearWeaponData", "InitGarageResources", "ResetItem3dModelActionCache", "SetCaptureActions", "SetDrone", "SetExpectedItemId", "SetGrenadeData", "SetHasGrenades", "SetHullData", "SetMountedItemsProperties", "SetPaint", "SetWeaponData", "ShowRequest", "UpdatePreviewSettings", "UpdateViewStyle")),
|
||||
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")),
|
||||
SliceWiring("register", "hpv_1", "Cit", "cp.stg", "cp.stg(t, n.hpv_1)", listOf("?Bit", "?Dit", "?Fit", "?Git", "?Hit", "?Lit", "?Mit", "?Uit", "?_rt", "?hrt", "EnteredUidIsBusy", "ForceSetUid", "ReceiveOAuthUri", "SetOpenedPassword", "SetPassword", "SetPasswordRestrictions", "SetUid", "SocialNetworkAvailability", "SocialNetworkClientIds")),
|
||||
@@ -106,7 +106,7 @@ object RootWiring {
|
||||
)
|
||||
|
||||
/** 已迁移(由 RootReducer 真正归约)的字段。 */
|
||||
val Migrated: Set<String> = setOf("inviteState", "loginByPassword", "twitchState", "home", "localBattleUserState", "shop", "screen", "lootBoxes", "garage")
|
||||
val Migrated: Set<String> = setOf("inviteState", "loginByPassword", "twitchState", "home", "localBattleUserState", "shop", "screen", "lootBoxes", "garage", "garagePreview")
|
||||
|
||||
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
||||
val Unmigrated: List<SliceWiring> get() = All.filter { it.Field !in Migrated }
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
// ⑥ 动作目录:816 个类与 138 个真实派发名对齐
|
||||
// ⑦ 回放:真实 toString 样例的类/字段/类型校验
|
||||
// ⑧ 全目录动作类都能按 KClass 路由
|
||||
// ⑨~⑲ 切片 reducer:InviteState / LoginByPasswordState / TwitchState / HomeScreen / LocalBattleUserState /
|
||||
// Shop(含 U7 类别表与 w3 物品表两个子 reducer)/ Screen / LootBoxes / Garage;⑭ 根 reducer 的 89 槽位委派
|
||||
// ⑨~⑳ 切片 reducer:InviteState / LoginByPasswordState / TwitchState / HomeScreen / LocalBattleUserState /
|
||||
// Shop(含 U7 类别表与 w3 物品表两个子 reducer)/ Screen / LootBoxes / Garage / GaragePreview;
|
||||
// ⑭ 根 reducer 的 89 槽位委派
|
||||
//
|
||||
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
||||
package App
|
||||
@@ -209,19 +210,52 @@ import App.State.SetRestrictionMount
|
||||
import App.State.SwitchingRowsScroll
|
||||
import App.State.UpdateDiscount
|
||||
import App.State.UpgradableItemParams
|
||||
import App.State.AddRequestedItem
|
||||
import App.State.Coloring
|
||||
import App.State.EmissionColors
|
||||
import App.State.GaragePreviewModelCC
|
||||
import App.State.HullEngineType
|
||||
import App.State.InitGarageResources
|
||||
import App.State.ResetItem3dModelActionCache
|
||||
import App.State.SetCaptureActions
|
||||
import App.State.SetDrone
|
||||
import App.State.SetExpectedItemId
|
||||
import App.State.SetMountedItemsProperties
|
||||
import App.State.SetPaint
|
||||
import App.State.ShowRequest
|
||||
import App.State.TankPartData
|
||||
import App.State.TankPreviewSettings
|
||||
import App.State.TextureFrameAnimation
|
||||
import App.State.TurretMechanism
|
||||
import App.State.UpdatePreviewSettings
|
||||
import App.State.Reducers.AddGarageItemCount
|
||||
import App.State.Reducers.AddNewItem
|
||||
import App.State.Reducers.CaptureScreenshot
|
||||
import App.State.Reducers.CaptureVideo
|
||||
import App.State.Reducers.ClearDroneData
|
||||
import App.State.Reducers.ClearGaragePreviewParams
|
||||
import App.State.Reducers.ClearGrenadeData
|
||||
import App.State.Reducers.ClearHasGrenades
|
||||
import App.State.Reducers.ClearHullData
|
||||
import App.State.Reducers.ClearUpgradeItemInProcessing
|
||||
import App.State.Reducers.ClearWaitServerItemMount
|
||||
import App.State.Reducers.ClearWeaponData
|
||||
import App.State.Reducers.GarageDefaultCategory
|
||||
import App.State.Reducers.GarageLoaded
|
||||
import App.State.Reducers.GarageMountItem
|
||||
import App.State.Reducers.GarageMountItems
|
||||
import App.State.Reducers.GaragePreviewStateSlice
|
||||
import App.State.Reducers.GarageResistanceCategoryKey
|
||||
import App.State.Reducers.GarageStateSlice
|
||||
import App.State.Reducers.GarageUnmountItem
|
||||
import App.State.Reducers.HideGaragePreview
|
||||
import App.State.Reducers.HideVideoInDescription
|
||||
import App.State.Reducers.PreviewDroneCategory
|
||||
import App.State.Reducers.PreviewHullCategory
|
||||
import App.State.Reducers.PreviewPaintCategory
|
||||
import App.State.Reducers.PreviewWeaponCategory
|
||||
import App.State.Reducers.ReduceGarage
|
||||
import App.State.Reducers.ReduceGaragePreview
|
||||
import App.State.Reducers.RemoveNewItem
|
||||
import App.State.Reducers.RemoveWaitServerItemMount
|
||||
import App.State.Reducers.ResetGarage
|
||||
@@ -230,6 +264,9 @@ import App.State.Reducers.SelectGarageCategory
|
||||
import App.State.Reducers.SetCooldownReduceEndTime
|
||||
import App.State.Reducers.SetGarageNotLoaded
|
||||
import App.State.Reducers.SetGarageObject
|
||||
import App.State.Reducers.SetGrenadeData
|
||||
import App.State.Reducers.SetHasGrenades
|
||||
import App.State.Reducers.SetHullData
|
||||
import App.State.Reducers.SetItemsOnDepot
|
||||
import App.State.Reducers.SetItemsOnMarket
|
||||
import App.State.Reducers.SetMountedItems
|
||||
@@ -237,8 +274,11 @@ import App.State.Reducers.SetMountedShotSkinForItems
|
||||
import App.State.Reducers.SetMountedSkinForItems
|
||||
import App.State.Reducers.SetNewItems
|
||||
import App.State.Reducers.SetResistanceReadyToMount
|
||||
import App.State.Reducers.SetWeaponData
|
||||
import App.State.Reducers.ShowGarageDiscountNotification
|
||||
import App.State.Reducers.ShowGaragePreview
|
||||
import App.State.Reducers.StartCooldownReduce
|
||||
import App.State.Reducers.UpdateViewStyle
|
||||
import State.InitState
|
||||
|
||||
private data class AddFrags(val fragsCount: Int)
|
||||
@@ -613,7 +653,7 @@ object StateCheck {
|
||||
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
||||
}
|
||||
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 九个已迁移切片一次归约
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 十个已迁移切片一次归约
|
||||
run {
|
||||
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
||||
Check(
|
||||
@@ -677,13 +717,14 @@ object StateCheck {
|
||||
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
||||
)
|
||||
Check(
|
||||
"根:迁移表 = 九个已迁移字段,其余 80 个待迁",
|
||||
"根:迁移表 = 十个已迁移字段,其余 79 个待迁",
|
||||
RootReducer.Migrated ==
|
||||
setOf(
|
||||
"inviteState", "loginByPassword", "twitchState", "home",
|
||||
"localBattleUserState", "shop", "screen", "lootBoxes", "garage",
|
||||
"garagePreview",
|
||||
) &&
|
||||
RootWiring.Unmigrated.size == 80
|
||||
RootWiring.Unmigrated.size == 79
|
||||
)
|
||||
|
||||
// 一次 ReduceRoot 里八个切片各归约自己的动作,互不串片
|
||||
@@ -739,7 +780,7 @@ object StateCheck {
|
||||
S5.User == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
||||
)
|
||||
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 9/89")
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 10/89")
|
||||
|
||||
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
||||
Store.Dispatch(SetStatus("LOGGING_IN"))
|
||||
@@ -1954,6 +1995,303 @@ object StateCheck {
|
||||
)
|
||||
}
|
||||
|
||||
// ⑳ 切片 reducer:GaragePreview(原 module_10032 的 IG / fs.eru,22 字段;25 个顶层臂)
|
||||
run {
|
||||
val S0 = GaragePreviewStateSlice()
|
||||
Check(
|
||||
"切片 GaragePreview:默认值与原构造一致(22 字段)",
|
||||
!S0.IsVisible && !S0.PhotoMode && !S0.NeedVisible &&
|
||||
S0.ViewStyle == null && S0.DynViewStyle == null &&
|
||||
S0.TankPreviewSettings is TankPreviewSettings && !S0.NeedShowDrone &&
|
||||
S0.Params == null && S0.HullData == null && S0.WeaponData == null &&
|
||||
S0.DroneData == null && S0.GrenadeData == null && !S0.HasGrenades &&
|
||||
S0.HullEngineType == HullEngineType.TRACKED &&
|
||||
S0.TurretMechanism == TurretMechanism.ROTATING_TURRET &&
|
||||
S0.Paint == null && S0.Properties.isEmpty() &&
|
||||
S0.CaptureScreenshotAction == null && S0.CaptureVideoAction == null &&
|
||||
S0.Item3dModelActionCache.isEmpty() && S0.RequestedItems.isEmpty() &&
|
||||
S0.ExpectedItemId.isEmpty()
|
||||
)
|
||||
|
||||
val Colors = EmissionColors(1, 2, 3, 4, "STRICT")
|
||||
val OldSettings = TankPreviewSettings(cameraHeight = 111)
|
||||
val NewSettings = TankPreviewSettings(cameraHeight = 777)
|
||||
val Params = GaragePreviewModelCC(80, 1000, 1.57, -110, null, null)
|
||||
val OldPaint = Coloring(null, TextureFrameAnimation(32, 4, 8, 16))
|
||||
val NewPaint = Coloring(null, TextureFrameAnimation(64, 8, 8, 32))
|
||||
val OldPart = TankPartData(resource = "old")
|
||||
val Base = S0.copy(
|
||||
IsVisible = true,
|
||||
NeedVisible = false,
|
||||
ViewStyle = "old",
|
||||
DynViewStyle = "dyn-old",
|
||||
TankPreviewSettings = OldSettings,
|
||||
Params = Params,
|
||||
HullData = OldPart,
|
||||
WeaponData = OldPart,
|
||||
DroneData = OldPart,
|
||||
GrenadeData = OldPart,
|
||||
Paint = OldPaint,
|
||||
Properties = listOf("old"),
|
||||
)
|
||||
|
||||
val ClearParams = ReduceGaragePreview(Base, ClearGaragePreviewParams())
|
||||
Check("切片 GaragePreview:ClearGaragePreviewParams 只清 params", ClearParams.Params == null)
|
||||
|
||||
val Shown = ReduceGaragePreview(Base.copy(NeedVisible = true), ShowGaragePreview())
|
||||
Check(
|
||||
"切片 GaragePreview:ShowGaragePreview 置 isVisible=true、needVisible=false",
|
||||
Shown.IsVisible && !Shown.NeedVisible
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:HideGaragePreview 置 isVisible=false",
|
||||
!ReduceGaragePreview(Base, HideGaragePreview()).IsVisible
|
||||
)
|
||||
|
||||
val Req = ShowRequest(
|
||||
viewStyle = "new",
|
||||
tankPreviewSettings = NewSettings,
|
||||
needShowDrone = true,
|
||||
photoMode = true,
|
||||
withDelay = false,
|
||||
)
|
||||
val S1 = ReduceGaragePreview(Base, Req)
|
||||
Check(
|
||||
"切片 GaragePreview:ShowRequest(无延迟)保留 isVisible 并写 view/settings/photo/drone",
|
||||
S1.IsVisible && !S1.NeedVisible && S1.ViewStyle == "new" &&
|
||||
S1.TankPreviewSettings == NewSettings && S1.PhotoMode &&
|
||||
S1.NeedShowDrone && S1.DynViewStyle == "dyn-old" &&
|
||||
S1.Params == Params && S1.HullData == OldPart
|
||||
)
|
||||
val S2 = ReduceGaragePreview(Base, Req.copy(withDelay = true))
|
||||
Check(
|
||||
"切片 GaragePreview:ShowRequest(延迟)置 isVisible=false、needVisible=true",
|
||||
!S2.IsVisible && S2.NeedVisible && S2.ViewStyle == "new"
|
||||
)
|
||||
|
||||
Check(
|
||||
"切片 GaragePreview:UpdatePreviewSettings 只写 tankPreviewSettings",
|
||||
ReduceGaragePreview(Base, UpdatePreviewSettings(NewSettings)).TankPreviewSettings == NewSettings
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:UpdateViewStyle 无字段,原 fru_1=undefined 被 trs 视作省略",
|
||||
ReduceGaragePreview(Base, UpdateViewStyle()) == Base
|
||||
)
|
||||
|
||||
val Init = ReduceGaragePreview(S0, InitGarageResources(Params))
|
||||
Check("切片 GaragePreview:InitGarageResources 写 params", Init.Params == Params)
|
||||
|
||||
val Expected1 = ReduceGaragePreview(S0, SetExpectedItemId(PreviewHullCategory, 42L))
|
||||
Check(
|
||||
"切片 GaragePreview:SetExpectedItemId 写分类键",
|
||||
Expected1.ExpectedItemId[PreviewHullCategory] == 42L
|
||||
)
|
||||
val Expected2 = ReduceGaragePreview(Expected1, SetExpectedItemId(PreviewHullCategory, null))
|
||||
Check(
|
||||
"切片 GaragePreview:SetExpectedItemId(itemId=null) 删除分类键",
|
||||
!Expected2.ExpectedItemId.containsKey(PreviewHullCategory)
|
||||
)
|
||||
|
||||
Check(
|
||||
"切片 GaragePreview:AddRequestedItem 加入 requestedItems",
|
||||
ReduceGaragePreview(S0, AddRequestedItem(42L)).RequestedItems == setOf(42L)
|
||||
)
|
||||
|
||||
val HullAction = SetHullData(
|
||||
itemId = 42L,
|
||||
hullEngineType = HullEngineType.HOVER,
|
||||
resource = "hull",
|
||||
emissionColors = Colors,
|
||||
turretMountPoint = "mount",
|
||||
skinOffset = "skin",
|
||||
leftTrackTexToWorldRatio = 7,
|
||||
rightTrackTexToWorldRatio = 8,
|
||||
)
|
||||
val HullBase = S0.copy(RequestedItems = setOf(42L))
|
||||
val HullHit = ReduceGaragePreview(HullBase, HullAction)
|
||||
Check(
|
||||
"切片 GaragePreview:SetHullData 命中时写 hullData/hullEngineType、缓存动作并删 requested",
|
||||
HullHit.HullData == TankPartData("hull", Colors, "mount", "skin", 7, 8) &&
|
||||
HullHit.HullEngineType == HullEngineType.HOVER &&
|
||||
HullHit.Item3dModelActionCache[42L] == HullAction &&
|
||||
HullHit.RequestedItems.isEmpty()
|
||||
)
|
||||
val HullMiss = ReduceGaragePreview(
|
||||
HullBase.copy(ExpectedItemId = mapOf<Any?, Any?>(PreviewHullCategory to 99L)),
|
||||
HullAction,
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:SetHullData 未命中只缓存动作,不写 hullData",
|
||||
HullMiss.HullData == null && HullMiss.HullEngineType == HullEngineType.TRACKED &&
|
||||
HullMiss.Item3dModelActionCache[42L] == HullAction &&
|
||||
HullMiss.RequestedItems.isEmpty()
|
||||
)
|
||||
|
||||
val WeaponAction = SetWeaponData(
|
||||
itemId = 43L,
|
||||
turretMechanism = TurretMechanism.ELEVATING_BARREL,
|
||||
resource = "weapon",
|
||||
emissionColors = Colors,
|
||||
)
|
||||
val WeaponBase = S0.copy(RequestedItems = setOf(43L))
|
||||
val WeaponHit = ReduceGaragePreview(WeaponBase, WeaponAction)
|
||||
Check(
|
||||
"切片 GaragePreview:SetWeaponData 命中时写 weaponData/turretMechanism、缓存动作并删 requested",
|
||||
WeaponHit.WeaponData == TankPartData("weapon", Colors) &&
|
||||
WeaponHit.TurretMechanism == TurretMechanism.ELEVATING_BARREL &&
|
||||
WeaponHit.Item3dModelActionCache[43L] == WeaponAction &&
|
||||
WeaponHit.RequestedItems.isEmpty()
|
||||
)
|
||||
val WeaponMiss = ReduceGaragePreview(
|
||||
WeaponBase.copy(ExpectedItemId = mapOf<Any?, Any?>(PreviewWeaponCategory to 99L)),
|
||||
WeaponAction,
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:SetWeaponData 未命中只缓存动作,不写 weaponData",
|
||||
WeaponMiss.WeaponData == null &&
|
||||
WeaponMiss.TurretMechanism == TurretMechanism.ROTATING_TURRET &&
|
||||
WeaponMiss.Item3dModelActionCache[43L] == WeaponAction
|
||||
)
|
||||
|
||||
val DroneAction = SetDrone(44L, "drone", Colors)
|
||||
val DroneHit = ReduceGaragePreview(S0.copy(RequestedItems = setOf(44L)), DroneAction)
|
||||
Check(
|
||||
"切片 GaragePreview:SetDrone 命中时写 droneData 并删 requested",
|
||||
DroneHit.DroneData == TankPartData("drone", Colors) &&
|
||||
DroneHit.Item3dModelActionCache[44L] == DroneAction &&
|
||||
DroneHit.RequestedItems.isEmpty()
|
||||
)
|
||||
val DroneMiss = ReduceGaragePreview(
|
||||
S0.copy(
|
||||
DroneData = OldPart,
|
||||
ExpectedItemId = mapOf<Any?, Any?>(PreviewDroneCategory to 99L),
|
||||
),
|
||||
DroneAction,
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:SetDrone 未命中保留 droneData",
|
||||
DroneMiss.DroneData == OldPart && DroneMiss.Item3dModelActionCache[44L] == DroneAction
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:SetDrone(resource=null) 命中时写 null",
|
||||
ReduceGaragePreview(S0.copy(DroneData = OldPart), SetDrone(45L, null, Colors)).DroneData == null
|
||||
)
|
||||
|
||||
Check(
|
||||
"切片 GaragePreview:SetGrenadeData 写 grenadeData",
|
||||
ReduceGaragePreview(S0, SetGrenadeData("grenade", Colors)).GrenadeData ==
|
||||
TankPartData("grenade", Colors)
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:SetGrenadeData(resource=null) 写 null",
|
||||
ReduceGaragePreview(S0.copy(GrenadeData = OldPart), SetGrenadeData(null, Colors)).GrenadeData == null
|
||||
)
|
||||
|
||||
Check("切片 GaragePreview:ClearHullData", ReduceGaragePreview(Base, ClearHullData()).HullData == null)
|
||||
Check("切片 GaragePreview:ClearWeaponData", ReduceGaragePreview(Base, ClearWeaponData()).WeaponData == null)
|
||||
Check("切片 GaragePreview:ClearDroneData", ReduceGaragePreview(Base, ClearDroneData()).DroneData == null)
|
||||
Check("切片 GaragePreview:ClearGrenadeData", ReduceGaragePreview(Base, ClearGrenadeData()).GrenadeData == null)
|
||||
|
||||
Check(
|
||||
"切片 GaragePreview:SetHasGrenades",
|
||||
ReduceGaragePreview(S0, SetHasGrenades()).HasGrenades
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:ClearHasGrenades",
|
||||
!ReduceGaragePreview(S0.copy(HasGrenades = true), ClearHasGrenades()).HasGrenades
|
||||
)
|
||||
|
||||
val PaintAction = SetPaint(46L, NewPaint)
|
||||
val PaintHit = ReduceGaragePreview(S0.copy(RequestedItems = setOf(46L)), PaintAction)
|
||||
Check(
|
||||
"切片 GaragePreview:SetPaint 命中时写 paint、缓存动作并删 requested",
|
||||
PaintHit.Paint == NewPaint && PaintHit.Item3dModelActionCache[46L] == PaintAction &&
|
||||
PaintHit.RequestedItems.isEmpty()
|
||||
)
|
||||
val PaintMiss = ReduceGaragePreview(
|
||||
S0.copy(
|
||||
Paint = OldPaint,
|
||||
ExpectedItemId = mapOf<Any?, Any?>(PreviewPaintCategory to 99L),
|
||||
),
|
||||
PaintAction,
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:SetPaint 未命中保留 paint",
|
||||
PaintMiss.Paint == OldPaint && PaintMiss.Item3dModelActionCache[46L] == PaintAction
|
||||
)
|
||||
|
||||
Check(
|
||||
"切片 GaragePreview:ResetItem3dModelActionCache 删缓存",
|
||||
!ReduceGaragePreview(PaintHit, ResetItem3dModelActionCache(46L))
|
||||
.Item3dModelActionCache.containsKey(46L)
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:SetMountedItemsProperties 写 properties",
|
||||
ReduceGaragePreview(S0, SetMountedItemsProperties(listOf("ROTATING_WEAPON", "HOVER_CHASSIS")))
|
||||
.Properties == listOf("ROTATING_WEAPON", "HOVER_CHASSIS")
|
||||
)
|
||||
|
||||
var Shots = 0
|
||||
var Videos = 0
|
||||
val Capture = ReduceGaragePreview(S0, SetCaptureActions({ Shots += 1 }, { Videos += 1 }))
|
||||
Check(
|
||||
"切片 GaragePreview:SetCaptureActions 写两个回调",
|
||||
Capture.CaptureScreenshotAction != null && Capture.CaptureVideoAction != null
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:CaptureScreenshot 只调用回调、状态不变",
|
||||
ReduceGaragePreview(Capture, CaptureScreenshot()) == Capture && Shots == 1
|
||||
)
|
||||
Check(
|
||||
"切片 GaragePreview:CaptureVideo 只调用回调、状态不变",
|
||||
ReduceGaragePreview(Capture, CaptureVideo()) == Capture && Videos == 1
|
||||
)
|
||||
|
||||
Check(
|
||||
"切片 GaragePreview:无关动作返回等值状态",
|
||||
ReduceGaragePreview(Base, AddFrags(1)) == Base
|
||||
)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, AddRequestedItem(7L))
|
||||
Check(
|
||||
"根:AddRequestedItem 只动 garagePreview",
|
||||
Root1.GaragePreview.RequestedItems == setOf(7L) && Root1.Garage == Root0.Garage &&
|
||||
Root1.Shop == Root0.Shop && Root1.Screen == Root0.Screen && Root1.LootBoxes == Root0.LootBoxes
|
||||
)
|
||||
val Root2 = ReduceRoot(Root1, SetHasGrenades())
|
||||
Check(
|
||||
"根:SetHasGrenades 保留 garagePreview 前一次归约",
|
||||
Root2.GaragePreview.HasGrenades && Root2.GaragePreview.RequestedItems == setOf(7L)
|
||||
)
|
||||
Check("根:garagePreview 迁移后无关动作仍返回等值状态", ReduceRoot(Root2, AddFrags(1)) == Root2)
|
||||
|
||||
val W = RootWiring.ByField("garagePreview")!!
|
||||
Check(
|
||||
"根:garagePreview 委派到 IG / fs.eru 且 22 个动作全部具名",
|
||||
W.SliceClass == "IG" && W.Reducer == "fs.eru" && W.Actions.size == 22 &&
|
||||
W.Actions.none { it.startsWith("?") }
|
||||
)
|
||||
Check(
|
||||
"根:garagePreview 的动作名覆盖 22 个 instanceof 臂",
|
||||
listOf(
|
||||
"AddRequestedItem", "CaptureScreenshot", "CaptureVideo", "ClearDroneData",
|
||||
"ClearGrenadeData", "ClearHasGrenades", "ClearHullData", "ClearWeaponData",
|
||||
"InitGarageResources", "ResetItem3dModelActionCache", "SetCaptureActions",
|
||||
"SetDrone", "SetExpectedItemId", "SetGrenadeData", "SetHasGrenades",
|
||||
"SetHullData", "SetMountedItemsProperties", "SetPaint", "SetWeaponData",
|
||||
"ShowRequest", "UpdatePreviewSettings", "UpdateViewStyle",
|
||||
).all { it in W.Actions }
|
||||
)
|
||||
Check(
|
||||
"根:garagePreview 的动作表不含 IG 标识和 3 个单例臂",
|
||||
W.Actions.none {
|
||||
it == "IG" || it == "GaragePreview" ||
|
||||
it == "ClearGaragePreviewParams" || it == "ShowGaragePreview" || it == "HideGaragePreview"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
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