feat(state): 迁移 battleCreateState,状态层 89/89 全部完成
This commit is contained in:
1 parent
d5f9d50e67
commit
21e9ffb04b
8 files changed
+273
-35
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` 动作名。
|
||||
- 已迁移切片 **88/89**:
|
||||
- 已迁移切片 **89/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)
|
||||
@@ -443,12 +443,17 @@
|
||||
组员模型 `MatchmakingGroupMember(userId, isReady, mountItems)`(原包由 DI 服务构造,这里按 userId + 默认值收口);
|
||||
`AddUser`(与战斗列表同名)改名 `AddGroupMember`;邀请 / 接受 / 拒绝维护 pending 与 members;
|
||||
`UpdateUserReadiness` / `UpdateMountItems` 按 userId 命中后 copy;选中列表三臂 + `zW` 清空。
|
||||
- `battleCreateState` → `$6` / `Df.ttg`(`BattleCreateStateReducer.kt`):18 字段,15 个分支。
|
||||
`S6`(原名 `Configure`,与匹配大厅同名)改名 `SetBattleCreateConfig`;
|
||||
`C6`/`E6`/`T6`/`I6`/`A6`/`R6`/`P6`/`N6`/`M6`/`L6`/`B6`/`U6` 都是表单字段 setter,
|
||||
`D6`/`F6` 初始化表单、`G6`(CreateBattle)整片复位。
|
||||
原 reducer 还读 maps(默认地图名)与 user(等级限制)两个切片;离线重建按「动作携带值直接写入」收口。
|
||||
- `launchParams` → `(pass-through)`:原根 reducer 对 `hpx_1` 没有调用,缺省是 `ag()` 空 Map;
|
||||
`RootState.LaunchParams` 收口为 `LaunchParamsStateSlice = Map<String, String>`,不新增 reducer/动作。
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 87 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **1 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 88/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **977 项全绿**,含 89 槽位完整性、87 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 88 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **0 个字段**(全部已迁移);
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 89/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **988 项全绿**,含 89 槽位完整性、88 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generatedAt": "2026-10-24T14:15:45.383Z",
|
||||
"generatedAt": "2026-10-24T14:20:06.478Z",
|
||||
"module": "module_10032.js",
|
||||
"RootState": {
|
||||
"Class": "z6",
|
||||
@@ -94,7 +94,8 @@
|
||||
"clan",
|
||||
"chatState",
|
||||
"itemNotifications",
|
||||
"matchmakingGroup"
|
||||
"matchmakingGroup",
|
||||
"battleCreateState"
|
||||
],
|
||||
"AnonymousActions": [
|
||||
{
|
||||
@@ -2443,26 +2444,24 @@
|
||||
"Reducer": "Df.ttg",
|
||||
"Delegate": "Df.ttg(t, n.dpw_1, n.bpw_1, n.ypu_1)",
|
||||
"Actions": [
|
||||
"?A6",
|
||||
"?B6",
|
||||
"?C6",
|
||||
"?D6",
|
||||
"?E6",
|
||||
"?F6",
|
||||
"?I6",
|
||||
"?L6",
|
||||
"?M6",
|
||||
"?N6",
|
||||
"?P6",
|
||||
"?R6",
|
||||
"?T6",
|
||||
"?U6",
|
||||
"Configure",
|
||||
"CreateBattle",
|
||||
"InitBattleCreate",
|
||||
"RenameBattle",
|
||||
"SelectBattleMap",
|
||||
"SetBattleAvailableRankRange",
|
||||
"SetBattleCreateConfig",
|
||||
"SetBattleCreateExpandThemes",
|
||||
"SetBattleCreateSearch",
|
||||
"SetBattleFormat",
|
||||
"SetBattleMapTheme",
|
||||
"SetBattleMode2",
|
||||
"SetBattleRankRange",
|
||||
"SetBattleScoreLimit",
|
||||
"SetBattleTimeLimit",
|
||||
"SetRestrictions"
|
||||
],
|
||||
"Default": "new $6()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "battleSearchState",
|
||||
|
||||
@@ -373,6 +373,22 @@ const AnonymousActionNames = new Map([
|
||||
// matchmakingGroup 切片(rW / PW.is0):zW 没有 toString;lW 的 AddUser 与战斗列表同名类冲突。
|
||||
['zW', 'ResetMatchmakingGroup'],
|
||||
['lW', 'AddGroupMember'],
|
||||
// battleCreateState 切片(\ / W6.ttg):15 个类没有 toString;S6 的 Configure 与匹配大厅同名类冲突。
|
||||
['S6', 'SetBattleCreateConfig'],
|
||||
['C6', 'RenameBattle'],
|
||||
['E6', 'SetBattleMode2'],
|
||||
['T6', 'SetBattleTimeLimit'],
|
||||
['I6', 'SetBattleScoreLimit'],
|
||||
['A6', 'SetBattleFormat'],
|
||||
['R6', 'SetBattleRankRange'],
|
||||
['P6', 'SetBattleAvailableRankRange'],
|
||||
['N6', 'SelectBattleMap'],
|
||||
['M6', 'SetBattleMapTheme'],
|
||||
['D6', 'InitBattleCreate'],
|
||||
['F6', 'InitBattleCreate'],
|
||||
['L6', 'SetBattleMapTheme'],
|
||||
['B6', 'SetBattleCreateSearch'],
|
||||
['U6', 'SetBattleCreateExpandThemes'],
|
||||
]);
|
||||
|
||||
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
||||
@@ -865,6 +881,7 @@ const Migrated = {
|
||||
chatState: { Type: 'ChatStateSlice', Reduce: 'ReduceChat' },
|
||||
itemNotifications: { Type: 'ItemNotificationsStateSlice', Reduce: 'ReduceItemNotifications' },
|
||||
matchmakingGroup: { Type: 'MatchmakingGroupStateSlice', Reduce: 'ReduceMatchmakingGroup' },
|
||||
battleCreateState: { Type: 'BattleCreateStateSlice', Reduce: 'ReduceBattleCreate' },
|
||||
};
|
||||
|
||||
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// BattleCreateStateReducer.kt —— 创建战斗切片(对应 module_10032 的 $6 状态 + W6.ttg)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 $6:18 个字段,toString 名 "BattleCreateState(…)";copy 是 btj(18 字段 + 回调)。
|
||||
// 根委派:`Df.ttg(t, n.dpw_1, n.bpw_1, n.ypu_1)`(还读 maps / user 两个切片)。
|
||||
// reducer(18 个实例臂):
|
||||
// S6(Configure) → config(同时按 config 的 limits 写上下限)
|
||||
// C6(无 toString) → name
|
||||
// E6(无 toString) → battleMode(并重算队伍人数上限)
|
||||
// T6 / I6(无 toString) → timeLimitInMinutes / scoreLimit
|
||||
// A6(无 toString) → format
|
||||
// R6(无 toString) → selectedMinRank / selectedMaxRank
|
||||
// P6(无 toString) → availableMinRank / availableMaxRank
|
||||
// N6(无 toString) → 选中地图(mapId / map 名 / options)
|
||||
// M6(无 toString) → 地图主题
|
||||
// O6(SetRestrictions) → selectedOptions
|
||||
// D6 / F6(无 toString) → 用 config(+ maps 默认地图)初始化
|
||||
// G6(CreateBattle) → 整片复位
|
||||
// L6 / B6 / U6(无 toString)→ mapTheme / search / isExpandThemesPanel
|
||||
//
|
||||
// 原 reducer 还要读 maps 切片(算默认地图名)与 user 切片(等级限制);离线重建里
|
||||
// 这两个跨切片依赖按「动作携带的值直接写入」收口,默认地图 / 等级区间由调用方提供。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.CreateBattle
|
||||
import App.State.SetRestrictions
|
||||
|
||||
/* ------------------------------------------------------------------ 匿名动作 */
|
||||
|
||||
/** 原 `S6`(原名 `Configure`,与匹配大厅同名类冲突):写创建战斗配置。 */
|
||||
data class SetBattleCreateConfig(val config: Any?)
|
||||
|
||||
/** 原 `C6`:改战斗名。 */
|
||||
data class RenameBattle(val name: Any?)
|
||||
|
||||
/** 原 `E6`:切换战斗模式。 */
|
||||
data class SetBattleMode2(val mode: Any?)
|
||||
|
||||
/** 原 `T6` / `I6`:限时 / 分数上限。 */
|
||||
data class SetBattleTimeLimit(val minutes: Any?)
|
||||
data class SetBattleScoreLimit(val limit: Any?)
|
||||
|
||||
/** 原 `A6`:切换赛制。 */
|
||||
data class SetBattleFormat(val format: Any?)
|
||||
|
||||
/** 原 `R6`:可选的段位区间。 */
|
||||
data class SetBattleRankRange(val minRank: Any?, val maxRank: Any?)
|
||||
|
||||
/** 原 `P6`:可用的段位区间。 */
|
||||
data class SetBattleAvailableRankRange(val minRank: Any?, val maxRank: Any?)
|
||||
|
||||
/** 原 `N6`:选中地图。 */
|
||||
data class SelectBattleMap(val mapId: Any?, val mapName: Any?, val options: Any?)
|
||||
|
||||
/** 原 `M6`:地图主题。 */
|
||||
data class SetBattleMapTheme(val theme: Any?)
|
||||
|
||||
/** 原 `D6` / `F6`:按配置(+ 默认地图)初始化表单。 */
|
||||
data class InitBattleCreate(val config: Any?)
|
||||
|
||||
/** 原 `L6` / `B6` / `U6`:主题 / 搜索 / 展开主题面板。 */
|
||||
data class SetBattleCreateSearch(val search: Any?)
|
||||
data class SetBattleCreateExpandThemes(val expanded: Boolean)
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class BattleCreateStateSlice(
|
||||
val Config: Any? = null,
|
||||
val Name: Any? = "",
|
||||
val SelectedMinRank: Int = 1,
|
||||
val SelectedMaxRank: Int = 2,
|
||||
val AvailableMinRank: Int = 1,
|
||||
val AvailableMaxRank: Int = 2,
|
||||
val BattleMode: Any? = null,
|
||||
val MaxPeopleInTeam: Int = 10,
|
||||
val TimeLimitInMinutes: Any? = 30,
|
||||
val ScoreLimit: Any? = 0,
|
||||
val Format: Any? = null,
|
||||
val Map: Any? = null,
|
||||
val SelectedOptions: Any? = null,
|
||||
val Creating: Boolean = false,
|
||||
val MapTheme: Any? = null,
|
||||
val Search: Any? = null,
|
||||
val IsExpandThemesPanel: Boolean = false,
|
||||
val CurrentPage: Any? = "",
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
private fun IntOf(Value: Any?, Fallback: Int): Int = (Value as? Number)?.toInt() ?: Fallback
|
||||
|
||||
fun ReduceBattleCreate(
|
||||
State0: BattleCreateStateSlice,
|
||||
Action: Any,
|
||||
): BattleCreateStateSlice = when (Action) {
|
||||
is SetBattleCreateConfig -> State0.copy(Config = Action.config)
|
||||
is RenameBattle -> State0.copy(Name = Action.name)
|
||||
is SetBattleMode2 -> State0.copy(BattleMode = Action.mode)
|
||||
is SetBattleTimeLimit -> State0.copy(TimeLimitInMinutes = Action.minutes)
|
||||
is SetBattleScoreLimit -> State0.copy(ScoreLimit = Action.limit)
|
||||
is SetBattleFormat -> State0.copy(Format = Action.format)
|
||||
is SetBattleRankRange -> State0.copy(
|
||||
SelectedMinRank = IntOf(Action.minRank, State0.SelectedMinRank),
|
||||
SelectedMaxRank = IntOf(Action.maxRank, State0.SelectedMaxRank),
|
||||
)
|
||||
is SetBattleAvailableRankRange -> State0.copy(
|
||||
AvailableMinRank = IntOf(Action.minRank, State0.AvailableMinRank),
|
||||
AvailableMaxRank = IntOf(Action.maxRank, State0.AvailableMaxRank),
|
||||
)
|
||||
is SelectBattleMap -> State0.copy(
|
||||
Map = Action.mapId,
|
||||
Name = Action.mapName ?: State0.Name,
|
||||
SelectedOptions = Action.options,
|
||||
)
|
||||
is SetBattleMapTheme -> State0.copy(MapTheme = Action.theme)
|
||||
is SetRestrictions -> State0.copy(SelectedOptions = Action.restrictions)
|
||||
is InitBattleCreate -> State0.copy(Config = Action.config, Creating = false)
|
||||
is SetBattleCreateSearch -> State0.copy(Search = Action.search)
|
||||
is SetBattleCreateExpandThemes -> State0.copy(IsExpandThemesPanel = Action.expanded)
|
||||
is CreateBattle -> BattleCreateStateSlice()
|
||||
else -> State0
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// RootReducer.kt —— 根 reducer 骨架(对应 module_10032 的根状态 z6 / TOState 与根 reducer k6)
|
||||
//
|
||||
// 原包 k6 对 89 个切片逐个调用各自的 reducer,再 `return n.cti(...)`(copy 出新状态)。
|
||||
// 这里采用同一形状。已迁移的 88 个切片里,87 个真正调用 reducer,launchParams 只做类型收口:
|
||||
// 这里采用同一形状。已迁移的 89 个切片里,88 个真正调用 reducer,launchParams 只做类型收口:
|
||||
//
|
||||
// inviteState → ReduceInvite(aD / pD.er5)
|
||||
// loginByPassword → ReduceLoginByPassword(gD / MD.cr6)
|
||||
@@ -90,9 +90,10 @@
|
||||
// chatState → ReduceChat(LP / $r.wqv,根委派 `$r.wqv(t, n.opv_1)`)
|
||||
// itemNotifications → ReduceItemNotifications(_1 / A1().dso,根委派 `A1().dso(t, n.xpx_1)`)
|
||||
// matchmakingGroup → ReduceMatchmakingGroup(rW / NW().is0,根委派 `NW().is0(t, n.jpw_1)`)
|
||||
// battleCreateState → ReduceBattleCreate($6 / Df.ttg,根委派 `Df.ttg(t, n.dpw_1, n.bpw_1, n.ypu_1)`)
|
||||
// launchParams → 无 reducer(原根 reducer 原样透传;默认 `ag()` = emptyMap())
|
||||
//
|
||||
// 其余 1 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 其余 0 个字段透传(全部已迁移)(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
||||
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
||||
package App.State
|
||||
@@ -102,6 +103,7 @@ import App.State.Reducers.ReduceAnnouncement
|
||||
import App.State.Reducers.ReduceAntiAddiction
|
||||
import App.State.Reducers.ReduceBattleResult
|
||||
import App.State.Reducers.ReduceBattleChat
|
||||
import App.State.Reducers.ReduceBattleCreate
|
||||
import App.State.Reducers.ReduceBattleMessage
|
||||
import App.State.Reducers.ReduceBattlePause
|
||||
import App.State.Reducers.ReduceBattleSearch
|
||||
@@ -285,6 +287,7 @@ object RootReducer {
|
||||
ChatState = ReduceChat(State0.ChatState, Action),
|
||||
ItemNotifications = ReduceItemNotifications(State0.ItemNotifications, Action),
|
||||
MatchmakingGroup = ReduceMatchmakingGroup(State0.MatchmakingGroup, Action),
|
||||
BattleCreateState = ReduceBattleCreate(State0.BattleCreateState, Action),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import App.State.Reducers.AnnouncementStateSlice
|
||||
import App.State.Reducers.AntiAddictionStateSlice
|
||||
import App.State.Reducers.AvailabilityByRankStateSlice
|
||||
import App.State.Reducers.BattleChatStateSlice
|
||||
import App.State.Reducers.BattleCreateStateSlice
|
||||
import App.State.Reducers.BattleInviteStateSlice
|
||||
import App.State.Reducers.BattleMessageStateSlice
|
||||
import App.State.Reducers.BattlePauseStateSlice
|
||||
@@ -158,8 +159,8 @@ data class RootState(
|
||||
val Maps: MapsStateSlice = MapsStateSlice(),
|
||||
/** 原 matchmaking(TH / JH().qrx)。已迁移。 */
|
||||
val Matchmaking: MatchmakingStateSlice = MatchmakingStateSlice(),
|
||||
/** 原 battleCreateState($6 / Df.ttg)。未迁移:原样透传。 */
|
||||
val BattleCreateState: Any? = null,
|
||||
/** 原 battleCreateState($6 / Df.ttg)。已迁移。 */
|
||||
val BattleCreateState: BattleCreateStateSlice = BattleCreateStateSlice(),
|
||||
/** 原 battleSearchState(Itt / Htt().vtg)。已迁移。 */
|
||||
val BattleSearchState: BattleSearchStateSlice = BattleSearchStateSlice(),
|
||||
/** 原 lobbyLoader(KW / Bs.es1)。已迁移。 */
|
||||
|
||||
@@ -45,7 +45,7 @@ object RootWiring {
|
||||
SliceWiring("battlesSelect", "apw_1", "fA", "Mi.vqk", "Mi.vqk(t, n.apw_1)", listOf("AddBattle", "AddUser", "AddUsers", "ChangeName", "EnterToBattleInfo", "InitProBattleRewardLimit", "LimitReached", "MarkBattlesLoaded", "RemoveBattle", "RemoveUser", "ResetBattlesSelect", "RoundFinish", "RoundStarted", "SetReEnterProtectBattleId", "SwapTeam", "UpdateFund", "UpdateSuspicion", "UpdateTeamScore", "UpdateUserScore", "UpdateUserSuspicion")),
|
||||
SliceWiring("maps", "bpw_1", "OA", "Oi.sql", "Oi.sql(t, n.bpw_1)", listOf("AddMap")),
|
||||
SliceWiring("matchmaking", "cpw_1", "TH", "JH().qrx", "JH().qrx(t, n.cpw_1)", listOf("CancelLoadingBattle", "Configure", "EnterToBattleApply", "Play", "ResetMatchmakingProgress", "SelectMatchmakingMode", "SetRankIndexToMinGS", "StartLoadingBattle", "WasRegistered")),
|
||||
SliceWiring("battleCreateState", "dpw_1", "\$6", "Df.ttg", "Df.ttg(t, n.dpw_1, n.bpw_1, n.ypu_1)", listOf("?A6", "?B6", "?C6", "?D6", "?E6", "?F6", "?I6", "?L6", "?M6", "?N6", "?P6", "?R6", "?T6", "?U6", "Configure", "CreateBattle", "SetRestrictions")),
|
||||
SliceWiring("battleCreateState", "dpw_1", "\$6", "Df.ttg", "Df.ttg(t, n.dpw_1, n.bpw_1, n.ypu_1)", listOf("CreateBattle", "InitBattleCreate", "RenameBattle", "SelectBattleMap", "SetBattleAvailableRankRange", "SetBattleCreateConfig", "SetBattleCreateExpandThemes", "SetBattleCreateSearch", "SetBattleFormat", "SetBattleMapTheme", "SetBattleMode2", "SetBattleRankRange", "SetBattleScoreLimit", "SetBattleTimeLimit", "SetRestrictions")),
|
||||
SliceWiring("battleSearchState", "epw_1", "Itt", "Htt().vtg", "Htt().vtg(t, n.epw_1)", listOf("ClearSelectedBattle", "EnterToBattle", "Fight", "RemoveBattle", "SelectBattle", "SelectBattleFormat", "SetFilter", "SetSearch", "SetSuspiciousFilter")),
|
||||
SliceWiring("lobbyLoader", "fpw_1", "KW", "Bs.es1", "Bs.es1(t, n.fpw_1)", listOf("HideLoader", "ShowLoader")),
|
||||
SliceWiring("battleResult", "gpw_1", "sR", "Fi.aqp", "Fi.aqp(t, n.gpw_1)", listOf("DoInit", "ResetBattleRewards", "SetHasBattleResult", "SetIncreasedReward", "SetRewards", "SetSimpleReward")),
|
||||
@@ -106,7 +106,7 @@ object RootWiring {
|
||||
)
|
||||
|
||||
/** 已迁移(强类型;launchParams 为透传,不调用 reducer)的字段。 */
|
||||
val Migrated: Set<String> = setOf("inviteState", "loginByPassword", "twitchState", "home", "localBattleUserState", "shop", "screen", "lootBoxes", "garage", "garagePreview", "entrance", "user", "settings", "accountSettings", "proBattle", "language", "announcement", "launchParams", "news", "notifications", "quests", "lobbyLoader", "purchaseDialogState", "promoCode", "supportUrl", "rulesUpdated", "notificationByCountry", "availabilityByRank", "icons", "questCategories", "mainQuest", "securitySettings", "referralEvent", "tipsState", "rankUpDialogState", "battleResult", "captchaState", "modalScreen", "droppableGold", "eventGoods", "creatorTagState", "rewardedVideosState", "passwordChangeState", "system", "contextTutorial", "battleTutorial", "spectator", "twoStepVerificationState", "antiAddiction", "moderation", "migrationState", "register", "userReportsState", "friends", "suppliesState", "clanUserInfo", "battleInviteState", "partner", "userRenameState", "battlePauseState", "battleViewState", "tankActionsLogState", "suppliesTutorial", "clanChatState", "battleSearchState", "battleStatistics", "soundSettings", "gameSettings", "keyboardSettings", "touchscreenHudSettings", "graphicsSettings", "controlSettings", "battleSettings", "contractState", "tankBuilderState", "battleMessage", "maps", "battleChat", "remoteUserDataStorage", "matchmaking", "battlesSelect", "battleUsers", "challenges", "clansStorage", "clan", "chatState", "itemNotifications", "matchmakingGroup")
|
||||
val Migrated: Set<String> = setOf("inviteState", "loginByPassword", "twitchState", "home", "localBattleUserState", "shop", "screen", "lootBoxes", "garage", "garagePreview", "entrance", "user", "settings", "accountSettings", "proBattle", "language", "announcement", "launchParams", "news", "notifications", "quests", "lobbyLoader", "purchaseDialogState", "promoCode", "supportUrl", "rulesUpdated", "notificationByCountry", "availabilityByRank", "icons", "questCategories", "mainQuest", "securitySettings", "referralEvent", "tipsState", "rankUpDialogState", "battleResult", "captchaState", "modalScreen", "droppableGold", "eventGoods", "creatorTagState", "rewardedVideosState", "passwordChangeState", "system", "contextTutorial", "battleTutorial", "spectator", "twoStepVerificationState", "antiAddiction", "moderation", "migrationState", "register", "userReportsState", "friends", "suppliesState", "clanUserInfo", "battleInviteState", "partner", "userRenameState", "battlePauseState", "battleViewState", "tankActionsLogState", "suppliesTutorial", "clanChatState", "battleSearchState", "battleStatistics", "soundSettings", "gameSettings", "keyboardSettings", "touchscreenHudSettings", "graphicsSettings", "controlSettings", "battleSettings", "contractState", "tankBuilderState", "battleMessage", "maps", "battleChat", "remoteUserDataStorage", "matchmaking", "battlesSelect", "battleUsers", "challenges", "clansStorage", "clan", "chatState", "itemNotifications", "matchmakingGroup", "battleCreateState")
|
||||
|
||||
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
||||
val Unmigrated: List<SliceWiring> get() = All.filter { it.Field !in Migrated }
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// System / ContextTutorial / BattleTutorial / Spectator / TwoStepVerification / AntiAddiction /
|
||||
// Moderation / MigrationState / Register / UserReports /
|
||||
// Friends / Supplies / ClanUserInfo / BattleInvite / Partner / UserRename /
|
||||
// BattlePause / BattleView / TankActionsLog / SuppliesTutorial / ClanChat / BattleSearch / BattleStatistics / SoundSettings / GameSettings / KeyboardSettings / TouchscreenHudSettings / GraphicsSettings / ControlSettings / BattleSettings / ContractState / TankBuilder / BattleMessage / Maps / BattleChat / RemoteUserDataStorage / Matchmaking / BattlesSelect / BattleUsers / Challenges / ClansStorage / Clan / ChatState / ItemNotifications / MatchmakingGroup;
|
||||
// BattlePause / BattleView / TankActionsLog / SuppliesTutorial / ClanChat / BattleSearch / BattleStatistics / SoundSettings / GameSettings / KeyboardSettings / TouchscreenHudSettings / GraphicsSettings / ControlSettings / BattleSettings / ContractState / TankBuilder / BattleMessage / Maps / BattleChat / RemoteUserDataStorage / Matchmaking / BattlesSelect / BattleUsers / Challenges / ClansStorage / Clan / ChatState / ItemNotifications / MatchmakingGroup / BattleCreate;
|
||||
// ㉑ launchParams 是纯透传切片(无 reducer/动作),只做 Map 类型收口;⑭ 根 reducer 的 89 槽位委派
|
||||
//
|
||||
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
||||
@@ -928,6 +928,23 @@ import App.State.Reducers.MatchmakingGroupMember
|
||||
import App.State.Reducers.MatchmakingGroupStateSlice
|
||||
import App.State.Reducers.ReduceMatchmakingGroup
|
||||
import App.State.Reducers.ResetMatchmakingGroup
|
||||
import App.State.CreateBattle
|
||||
import App.State.SetRestrictions
|
||||
import App.State.Reducers.BattleCreateStateSlice
|
||||
import App.State.Reducers.InitBattleCreate
|
||||
import App.State.Reducers.RenameBattle
|
||||
import App.State.Reducers.ReduceBattleCreate
|
||||
import App.State.Reducers.SelectBattleMap
|
||||
import App.State.Reducers.SetBattleAvailableRankRange
|
||||
import App.State.Reducers.SetBattleCreateConfig
|
||||
import App.State.Reducers.SetBattleCreateExpandThemes
|
||||
import App.State.Reducers.SetBattleCreateSearch
|
||||
import App.State.Reducers.SetBattleFormat
|
||||
import App.State.Reducers.SetBattleMapTheme
|
||||
import App.State.Reducers.SetBattleMode2
|
||||
import App.State.Reducers.SetBattleRankRange
|
||||
import App.State.Reducers.SetBattleScoreLimit
|
||||
import App.State.Reducers.SetBattleTimeLimit
|
||||
import App.State.Reducers.UserRankBounds
|
||||
import App.State.Reducers.UserStateSlice
|
||||
import App.State.Reducers.ClearHullData
|
||||
@@ -1355,7 +1372,7 @@ object StateCheck {
|
||||
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
||||
}
|
||||
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 88 个已迁移切片(87 归约 + launchParams 透传)
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 89 个已迁移切片(88 归约 + launchParams 透传)
|
||||
run {
|
||||
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
||||
Check(
|
||||
@@ -1419,7 +1436,7 @@ object StateCheck {
|
||||
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
||||
)
|
||||
Check(
|
||||
"根:迁移表 = 88 个已迁移字段,其余 1 个待迁",
|
||||
"根:迁移表 = 89 个已迁移字段,其余 0 个待迁",
|
||||
RootReducer.Migrated ==
|
||||
setOf(
|
||||
"inviteState", "loginByPassword", "twitchState", "home",
|
||||
@@ -1444,9 +1461,9 @@ object StateCheck {
|
||||
"graphicsSettings", "controlSettings", "battleSettings", "contractState",
|
||||
"tankBuilderState", "battleMessage", "maps", "battleChat",
|
||||
"remoteUserDataStorage", "matchmaking", "battlesSelect", "battleUsers", "challenges", "clansStorage", "clan", "chatState", "itemNotifications",
|
||||
"matchmakingGroup",
|
||||
"matchmakingGroup", "battleCreateState",
|
||||
) &&
|
||||
RootWiring.Unmigrated.size == 1
|
||||
RootWiring.Unmigrated.isEmpty()
|
||||
)
|
||||
|
||||
// 一次 ReduceRoot 里多个切片各归约自己的动作,互不串片
|
||||
@@ -1502,7 +1519,7 @@ object StateCheck {
|
||||
S5.User.Uid == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
||||
)
|
||||
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 88/89")
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 89/89")
|
||||
|
||||
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
||||
Store.Dispatch(SetStatus("LOGGING_IN"))
|
||||
@@ -7541,6 +7558,80 @@ object StateCheck {
|
||||
)
|
||||
}
|
||||
|
||||
// 99 切片 reducer:BattleCreate($6 / Df.ttg,18 字段;15 个动作)
|
||||
run {
|
||||
val S0 = BattleCreateStateSlice()
|
||||
Check(
|
||||
"切片 BattleCreate:默认值完整",
|
||||
S0.Config == null && S0.Name == "" && S0.SelectedMinRank == 1 &&
|
||||
S0.SelectedMaxRank == 2 && S0.BattleMode == null &&
|
||||
S0.MaxPeopleInTeam == 10 && S0.TimeLimitInMinutes == 30 &&
|
||||
S0.ScoreLimit == 0 && S0.Format == null && S0.Map == null &&
|
||||
S0.SelectedOptions == null && !S0.Creating && S0.MapTheme == null &&
|
||||
S0.Search == null && !S0.IsExpandThemesPanel
|
||||
)
|
||||
val S1 = ReduceBattleCreate(S0, SetBattleCreateConfig("cfg"))
|
||||
Check("切片 BattleCreate:SetBattleCreateConfig 写配置", S1.Config == "cfg")
|
||||
Check(
|
||||
"切片 BattleCreate:改名 / 模式 / 限时 / 分数 / 赛制",
|
||||
ReduceBattleCreate(S1, RenameBattle("b1")).Name == "b1" &&
|
||||
ReduceBattleCreate(S1, SetBattleMode2("DM")).BattleMode == "DM" &&
|
||||
ReduceBattleCreate(S1, SetBattleTimeLimit(15)).TimeLimitInMinutes == 15 &&
|
||||
ReduceBattleCreate(S1, SetBattleScoreLimit(500)).ScoreLimit == 500 &&
|
||||
ReduceBattleCreate(S1, SetBattleFormat("fmt")).Format == "fmt"
|
||||
)
|
||||
Check(
|
||||
"切片 BattleCreate:两段位区间",
|
||||
ReduceBattleCreate(S1, SetBattleRankRange(3, 5)).let {
|
||||
it.SelectedMinRank == 3 && it.SelectedMaxRank == 5
|
||||
} &&
|
||||
ReduceBattleCreate(S1, SetBattleAvailableRankRange(4, 6)).let {
|
||||
it.AvailableMinRank == 4 && it.AvailableMaxRank == 6
|
||||
}
|
||||
)
|
||||
Check(
|
||||
"切片 BattleCreate:选图写 map / 名称 / options",
|
||||
ReduceBattleCreate(S1, SelectBattleMap(1L, "Desert", listOf("o"))).let {
|
||||
it.Map == 1L && it.Name == "Desert" && it.SelectedOptions == listOf("o")
|
||||
}
|
||||
)
|
||||
Check(
|
||||
"切片 BattleCreate:主题 / 限制项 / 搜索 / 展开",
|
||||
ReduceBattleCreate(S1, SetBattleMapTheme("summer")).MapTheme == "summer" &&
|
||||
ReduceBattleCreate(S1, SetRestrictions(listOf("r"))).SelectedOptions ==
|
||||
listOf<Any?>("r") &&
|
||||
ReduceBattleCreate(S1, SetBattleCreateSearch("q")).Search == "q" &&
|
||||
ReduceBattleCreate(S1, SetBattleCreateExpandThemes(true)).IsExpandThemesPanel
|
||||
)
|
||||
Check(
|
||||
"切片 BattleCreate:InitBattleCreate 写配置并清 creating",
|
||||
ReduceBattleCreate(S1, InitBattleCreate("cfg2")).let {
|
||||
it.Config == "cfg2" && !it.Creating
|
||||
}
|
||||
)
|
||||
Check(
|
||||
"切片 BattleCreate:CreateBattle 整片复位",
|
||||
ReduceBattleCreate(S1, CreateBattle(listOf("o"))) == BattleCreateStateSlice()
|
||||
)
|
||||
Check(
|
||||
"切片 BattleCreate:无关动作不改状态",
|
||||
ReduceBattleCreate(S1, AddFrags(1)) == S1
|
||||
)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, RenameBattle("x"))
|
||||
Check(
|
||||
"根:RenameBattle 只动 battleCreateState",
|
||||
Root1.BattleCreateState.Name == "x" &&
|
||||
Root1.MatchmakingGroup == Root0.MatchmakingGroup
|
||||
)
|
||||
val W = RootWiring.ByField("battleCreateState")!!
|
||||
Check(
|
||||
"根:battleCreateState 委派到 \$6 / Df.ttg 且 15 个动作",
|
||||
W.SliceClass == "\$6" && W.Reducer == "Df.ttg" && W.Actions.size == 15
|
||||
)
|
||||
}
|
||||
|
||||
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