feat(state): 迁移 contractState
This commit is contained in:
1 parent
0d1e2d00c5
commit
6a1c8b4306
8 files changed
+224
-22
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` 动作名。
|
||||
- 已迁移切片 **73/89**:
|
||||
- 已迁移切片 **74/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)
|
||||
@@ -370,12 +370,17 @@
|
||||
`u2`(原名 `UpdateSettings`)改名为 `ApplyControlSettings`。
|
||||
- `battleSettings` → `W0` / `X0().esq`(`BattleSettingsReducer.kt`):11 字段,2 个分支。
|
||||
`K0`(原名 `UpdateSettings`)改名为 `ApplyBattleSettings`;`_C` 的旧键迁移属 storage port,保留现状态。
|
||||
- `contractState` → `Ont` / `xv.bti`(`ContractStateReducer.kt`):3 字段,7 个分支。
|
||||
合同模型跨模块(id / progress / rewards),收口为 `ContractEntry`;`SetContract` 是**合并**(`putAll`);
|
||||
`UpdateProgress` / `GetReward` 复制单条合同再放回;`Fnt`(原名 `GetReward`,与任务切片同名)改名
|
||||
`ClaimContractReward`,`Hnt`→`RemoveCompletedContracts` 只留还有奖励的合同;
|
||||
`InitBattle` 只把 `lastBattleProgress` 归零。
|
||||
- `launchParams` → `(pass-through)`:原根 reducer 对 `hpx_1` 没有调用,缺省是 `ag()` 空 Map;
|
||||
`RootState.LaunchParams` 收口为 `LaunchParamsStateSlice = Map<String, String>`,不新增 reducer/动作。
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 72 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **16 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 73/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **804 项全绿**,含 89 槽位完整性、72 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 73 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **15 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 74/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **815 项全绿**,含 89 槽位完整性、73 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||
@@ -400,6 +405,7 @@
|
||||
设置类切片的 `_C`(共用重载)+ `Bet`/`Fet`/`Uet`/`v2`/`C7`/`E7`/`Iut` 也已登记,
|
||||
其中原名都是 `UpdateSettings` 的类按切片改名为 `Apply*`,避免生成物同名冲突
|
||||
(`Bet`/`v2`/`B2`/`u2`/`K0`/`C7` 共 6 个)。
|
||||
contractState 的 `Fnt`/`Hnt` 也已登记(`Fnt` 因与任务切片同名改名为 `ClaimContractReward`)。
|
||||
|
||||
### S4 引擎核心
|
||||
- 模块:32088(3D 数学)、92980(渲染)、61378(ECS)、55088(物理)、36659 + 71105(资源)、36734(音频)、3569(输入)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generatedAt": "2026-10-24T09:19:04.205Z",
|
||||
"generatedAt": "2026-10-24T09:26:08.293Z",
|
||||
"module": "module_10032.js",
|
||||
"RootState": {
|
||||
"Class": "z6",
|
||||
@@ -79,7 +79,8 @@
|
||||
"touchscreenHudSettings",
|
||||
"graphicsSettings",
|
||||
"controlSettings",
|
||||
"battleSettings"
|
||||
"battleSettings",
|
||||
"contractState"
|
||||
],
|
||||
"AnonymousActions": [
|
||||
{
|
||||
@@ -1354,6 +1355,18 @@
|
||||
"Name": "ApplyBattleSettings",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "战斗显示设置整体替换(原名 UpdateSettings)"
|
||||
},
|
||||
{
|
||||
"Local": "Fnt",
|
||||
"Name": "ClaimContractReward",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "复制该合同并把 rewards 清空(原名 GetReward,与任务切片同名)"
|
||||
},
|
||||
{
|
||||
"Local": "Hnt",
|
||||
"Name": "RemoveCompletedContracts",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "只保留 rewards 非空的合同"
|
||||
}
|
||||
],
|
||||
"Markers": [
|
||||
@@ -3054,16 +3067,16 @@
|
||||
"Reducer": "xv.bti",
|
||||
"Delegate": "xv.bti(t, n.fpy_1)",
|
||||
"Actions": [
|
||||
"?Hnt",
|
||||
"GetReward",
|
||||
"ClaimContractReward",
|
||||
"InitBattle",
|
||||
"RemoveCompletedContracts",
|
||||
"SetActiveContract",
|
||||
"SetBattleProgress",
|
||||
"SetContract",
|
||||
"UpdateProgress"
|
||||
],
|
||||
"Default": "new Ont()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "promoCode",
|
||||
|
||||
@@ -311,6 +311,9 @@ const AnonymousActionNames = new Map([
|
||||
['B2', 'ApplyGraphicsSettings'],
|
||||
['u2', 'ApplyControlSettings'],
|
||||
['K0', 'ApplyBattleSettings'],
|
||||
// contractState 切片(Ont / Wnt.bti):Fnt 的 GetReward 与任务切片同名,Hnt 没有 toString。
|
||||
['Fnt', 'ClaimContractReward'],
|
||||
['Hnt', 'RemoveCompletedContracts'],
|
||||
]);
|
||||
|
||||
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
||||
@@ -785,6 +788,7 @@ const Migrated = {
|
||||
},
|
||||
controlSettings: { Type: 'ControlSettingsStateSlice', Reduce: 'ReduceControlSettings' },
|
||||
battleSettings: { Type: 'BattleSettingsStateSlice', Reduce: 'ReduceBattleSettings' },
|
||||
contractState: { Type: 'ContractStateSlice', Reduce: 'ReduceContractState' },
|
||||
};
|
||||
|
||||
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
||||
@@ -1188,6 +1192,8 @@ const AppSettingsAnonymousEffects = {
|
||||
B2: '画质设置整体替换(原名 UpdateSettings)',
|
||||
u2: '操作设置整体替换(原名 UpdateSettings)',
|
||||
K0: '战斗显示设置整体替换(原名 UpdateSettings)',
|
||||
Fnt: '复制该合同并把 rewards 清空(原名 GetReward,与任务切片同名)',
|
||||
Hnt: '只保留 rewards 非空的合同',
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// ContractStateReducer.kt —— 合同(contract)切片(对应 module_10032 的 Ont 状态 + Wnt.bti)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 Ont:3 个字段,toString 名 "ContractState(…)";copy 是 ftq(3 字段 + 回调)。
|
||||
// 默认:activeContractId=null、contracts=emptyMap()、lastBattleProgress=0。
|
||||
// 根委派:`xv.bti(t, n.fpy_1)`。
|
||||
// reducer(7 个实例臂):
|
||||
// Dnt(SetActiveContract)→ activeContractId
|
||||
// Lnt(SetContract) → contracts 合并(`jm` = copy + `putAll`,键是合同 id)
|
||||
// Bnt(UpdateProgress) → 复制该合同、写 progress 后放回
|
||||
// Unt(SetBattleProgress)→ lastBattleProgress
|
||||
// Fnt(GetReward) → 复制该合同、把 rewards 清空后放回
|
||||
// Hnt(无 toString) → 只保留 rewards 非空的合同
|
||||
// InitBattle(原 `FR`) → 只把 lastBattleProgress 归零
|
||||
//
|
||||
// 合同模型在另一个模块(字段 `fdv_1`=id / `ldv_1`=progress / `odv_1`=rewards,`tdv()` 返回 rewards),
|
||||
// 这里收口成 `ContractEntry(contractId, progress, rewards)`。
|
||||
// `Fnt` 的生成类 `GetReward` 撞到了任务切片的同名动作(字段是 quests),改名 `ClaimContractReward`。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.SetActiveContract
|
||||
import App.State.SetBattleProgress
|
||||
import App.State.SetContract
|
||||
import App.State.UpdateProgress
|
||||
|
||||
/* ------------------------------------------------------------------ 动作 */
|
||||
|
||||
/** 原 `Fnt`(原名 `GetReward`,与任务切片的同名类冲突):领取该合同的奖励。 */
|
||||
data class ClaimContractReward(val contractId: Any?)
|
||||
|
||||
/** 原 `Hnt`:战斗结束后清掉已经没有奖励的合同。 */
|
||||
object RemoveCompletedContracts
|
||||
|
||||
/* ------------------------------------------------------------------ 模型 */
|
||||
|
||||
data class ContractEntry(
|
||||
val ContractId: Any?,
|
||||
val Progress: Any? = null,
|
||||
val Rewards: List<Any?> = emptyList(),
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class ContractStateSlice(
|
||||
val ActiveContractId: Any? = null,
|
||||
val Contracts: Map<Any?, Any?> = emptyMap(),
|
||||
val LastBattleProgress: Any? = 0,
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
private fun UpdateEntry(
|
||||
Contracts: Map<Any?, Any?>,
|
||||
ContractId: Any?,
|
||||
Transform: (ContractEntry) -> ContractEntry,
|
||||
): Map<Any?, Any?> {
|
||||
val Entry = Contracts[ContractId] as? ContractEntry ?: return Contracts
|
||||
return Contracts + (ContractId to Transform(Entry))
|
||||
}
|
||||
|
||||
fun ReduceContractState(
|
||||
State0: ContractStateSlice,
|
||||
Action: Any,
|
||||
): ContractStateSlice = when (Action) {
|
||||
is SetActiveContract -> State0.copy(ActiveContractId = Action.contractId)
|
||||
is SetContract -> {
|
||||
val Incoming = Action.contract as? List<*> ?: listOfNotNull(Action.contract)
|
||||
val Merged = LinkedHashMap<Any?, Any?>(State0.Contracts)
|
||||
for (Item in Incoming) {
|
||||
val Entry = Item as? ContractEntry ?: continue
|
||||
Merged[Entry.ContractId] = Entry
|
||||
}
|
||||
State0.copy(Contracts = Merged)
|
||||
}
|
||||
is UpdateProgress -> State0.copy(
|
||||
Contracts = UpdateEntry(State0.Contracts, Action.contactId) {
|
||||
it.copy(Progress = Action.progress)
|
||||
},
|
||||
)
|
||||
is SetBattleProgress -> State0.copy(LastBattleProgress = Action.progress)
|
||||
is ClaimContractReward -> State0.copy(
|
||||
Contracts = UpdateEntry(State0.Contracts, Action.contractId) {
|
||||
it.copy(Rewards = emptyList())
|
||||
},
|
||||
)
|
||||
is RemoveCompletedContracts -> State0.copy(
|
||||
Contracts = State0.Contracts.filterValues {
|
||||
(it as? ContractEntry)?.Rewards?.isNotEmpty() == true
|
||||
},
|
||||
)
|
||||
is InitBattle -> State0.copy(LastBattleProgress = 0)
|
||||
else -> State0
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// RootReducer.kt —— 根 reducer 骨架(对应 module_10032 的根状态 z6 / TOState 与根 reducer k6)
|
||||
//
|
||||
// 原包 k6 对 89 个切片逐个调用各自的 reducer,再 `return n.cti(...)`(copy 出新状态)。
|
||||
// 这里采用同一形状。已迁移的 73 个切片里,72 个真正调用 reducer,launchParams 只做类型收口:
|
||||
// 这里采用同一形状。已迁移的 74 个切片里,73 个真正调用 reducer,launchParams 只做类型收口:
|
||||
//
|
||||
// inviteState → ReduceInvite(aD / pD.er5)
|
||||
// loginByPassword → ReduceLoginByPassword(gD / MD.cr6)
|
||||
@@ -75,9 +75,10 @@
|
||||
// graphicsSettings → ReduceGraphicsSettings(L2 / lc.isu,根委派 `lc.isu(t, n.ypw_1)`)
|
||||
// controlSettings → ReduceControlSettings(i2 / _2().ess,根委派 `_2().ess(t, n.zpw_1)`)
|
||||
// battleSettings → ReduceBattleSettings(W0 / X0().esq,根委派 `X0().esq(t, n.xpw_1)`)
|
||||
// contractState → ReduceContractState(Ont / xv.bti,根委派 `xv.bti(t, n.fpy_1)`)
|
||||
// launchParams → 无 reducer(原根 reducer 原样透传;默认 `ag()` = emptyMap())
|
||||
//
|
||||
// 其余 16 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 其余 15 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
||||
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
||||
package App.State
|
||||
@@ -97,6 +98,7 @@ import App.State.Reducers.ReduceCaptcha
|
||||
import App.State.Reducers.ReduceClanUserInfo
|
||||
import App.State.Reducers.ReduceClanChat
|
||||
import App.State.Reducers.ReduceContextTutorial
|
||||
import App.State.Reducers.ReduceContractState
|
||||
import App.State.Reducers.ReduceControlSettings
|
||||
import App.State.Reducers.ReduceCreatorTag
|
||||
import App.State.Reducers.ReduceDroppableGold
|
||||
@@ -240,6 +242,7 @@ object RootReducer {
|
||||
GraphicsSettings = ReduceGraphicsSettings(State0.GraphicsSettings, Action),
|
||||
ControlSettings = ReduceControlSettings(State0.ControlSettings, Action),
|
||||
BattleSettings = ReduceBattleSettings(State0.BattleSettings, Action),
|
||||
ContractState = ReduceContractState(State0.ContractState, Action),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import App.State.Reducers.CaptchaStateSlice
|
||||
import App.State.Reducers.ClanChatStateSlice
|
||||
import App.State.Reducers.ClanUserInfoStateSlice
|
||||
import App.State.Reducers.ContextTutorialStateSlice
|
||||
import App.State.Reducers.ContractStateSlice
|
||||
import App.State.Reducers.ControlSettingsStateSlice
|
||||
import App.State.Reducers.CreatorTagStateSlice
|
||||
import App.State.Reducers.DroppableGoldStateSlice
|
||||
@@ -251,8 +252,8 @@ data class RootState(
|
||||
val UserReportsState: UserReportsStateSlice = UserReportsStateSlice(),
|
||||
/** 原 tankBuilderState(brt / wp.ati)。未迁移:原样透传。 */
|
||||
val TankBuilderState: Any? = null,
|
||||
/** 原 contractState(Ont / xv.bti)。未迁移:原样透传。 */
|
||||
val ContractState: Any? = null,
|
||||
/** 原 contractState(Ont / xv.bti)。已迁移。 */
|
||||
val ContractState: ContractStateSlice = ContractStateSlice(),
|
||||
/** 原 promoCode(cZ / Q_.ysg)。已迁移。 */
|
||||
val PromoCode: PromoCodeStateSlice = PromoCodeStateSlice(),
|
||||
/** 原 referralEvent(pQ / lh.osk)。已迁移。 */
|
||||
|
||||
@@ -99,14 +99,14 @@ object RootWiring {
|
||||
SliceWiring("availabilityByRank", "cpy_1", "tet", "\$p.xth", "\$p.xth(t, n.cpy_1)", listOf("SetLoadedData")),
|
||||
SliceWiring("userReportsState", "dpy_1", "Zst", "qot.zth", "(null == sd && new qot(), sd).zth(t, n.dpy_1)", listOf("InitUserReports", "ReportBattleChatMessage", "ReportLobbyChatMessage", "ReportProBattleName", "SetAvailableGameReports", "SetAvailableReports")),
|
||||
SliceWiring("tankBuilderState", "epy_1", "brt", "wp.ati", "wp.ati(t, n.epy_1)", listOf("?Trt", "SetKode", "SetParts", "SetPartsInfo")),
|
||||
SliceWiring("contractState", "fpy_1", "Ont", "xv.bti", "xv.bti(t, n.fpy_1)", listOf("?Hnt", "GetReward", "InitBattle", "SetActiveContract", "SetBattleProgress", "SetContract", "UpdateProgress")),
|
||||
SliceWiring("contractState", "fpy_1", "Ont", "xv.bti", "xv.bti(t, n.fpy_1)", listOf("ClaimContractReward", "InitBattle", "RemoveCompletedContracts", "SetActiveContract", "SetBattleProgress", "SetContract", "UpdateProgress")),
|
||||
SliceWiring("promoCode", "gpy_1", "cZ", "Q_.ysg", "Q_.ysg(t, n.gpy_1)", listOf("ActivatePromoCode", "SetCodeValidateStatus")),
|
||||
SliceWiring("referralEvent", "hpy_1", "pQ", "lh.osk", "lh.osk(t, n.hpy_1)", listOf("SetPromoCode", "SetReferralEventData", "SetReferrals", "SetReferrer")),
|
||||
SliceWiring("supportUrl", "ipy_1", "I4", "Yl.ct7", "Yl.ct7(t, n.ipy_1)", listOf("ClearSupportUrl", "SetUrl")),
|
||||
)
|
||||
|
||||
/** 已迁移(强类型;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")
|
||||
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")
|
||||
|
||||
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
||||
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;
|
||||
// BattlePause / BattleView / TankActionsLog / SuppliesTutorial / ClanChat / BattleSearch / BattleStatistics / SoundSettings / GameSettings / KeyboardSettings / TouchscreenHudSettings / GraphicsSettings / ControlSettings / BattleSettings / ContractState;
|
||||
// ㉑ launchParams 是纯透传切片(无 reducer/动作),只做 Map 类型收口;⑭ 根 reducer 的 89 槽位委派
|
||||
//
|
||||
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
||||
@@ -698,6 +698,15 @@ import App.State.Reducers.GraphicsSettingsStateSlice
|
||||
import App.State.Reducers.ReduceBattleSettings
|
||||
import App.State.Reducers.ReduceControlSettings
|
||||
import App.State.Reducers.ReduceGraphicsSettings
|
||||
import App.State.SetActiveContract
|
||||
import App.State.SetBattleProgress
|
||||
import App.State.SetContract
|
||||
import App.State.UpdateProgress
|
||||
import App.State.Reducers.ClaimContractReward
|
||||
import App.State.Reducers.ContractEntry
|
||||
import App.State.Reducers.ContractStateSlice
|
||||
import App.State.Reducers.ReduceContractState
|
||||
import App.State.Reducers.RemoveCompletedContracts
|
||||
import App.State.Reducers.UserRankBounds
|
||||
import App.State.Reducers.UserStateSlice
|
||||
import App.State.Reducers.ClearHullData
|
||||
@@ -1125,7 +1134,7 @@ object StateCheck {
|
||||
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
||||
}
|
||||
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 73 个已迁移切片(72 归约 + launchParams 透传)
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 74 个已迁移切片(73 归约 + launchParams 透传)
|
||||
run {
|
||||
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
||||
Check(
|
||||
@@ -1189,7 +1198,7 @@ object StateCheck {
|
||||
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
||||
)
|
||||
Check(
|
||||
"根:迁移表 = 73 个已迁移字段,其余 16 个待迁",
|
||||
"根:迁移表 = 74 个已迁移字段,其余 15 个待迁",
|
||||
RootReducer.Migrated ==
|
||||
setOf(
|
||||
"inviteState", "loginByPassword", "twitchState", "home",
|
||||
@@ -1211,9 +1220,9 @@ object StateCheck {
|
||||
"battlePauseState", "battleViewState", "tankActionsLogState", "suppliesTutorial",
|
||||
"clanChatState", "battleSearchState", "battleStatistics",
|
||||
"soundSettings", "gameSettings", "keyboardSettings", "touchscreenHudSettings",
|
||||
"graphicsSettings", "controlSettings", "battleSettings",
|
||||
"graphicsSettings", "controlSettings", "battleSettings", "contractState",
|
||||
) &&
|
||||
RootWiring.Unmigrated.size == 16
|
||||
RootWiring.Unmigrated.size == 15
|
||||
)
|
||||
|
||||
// 一次 ReduceRoot 里多个切片各归约自己的动作,互不串片
|
||||
@@ -1269,7 +1278,7 @@ object StateCheck {
|
||||
S5.User.Uid == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
||||
)
|
||||
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 73/89")
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 74/89")
|
||||
|
||||
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
||||
Store.Dispatch(SetStatus("LOGGING_IN"))
|
||||
@@ -6116,6 +6125,77 @@ object StateCheck {
|
||||
)
|
||||
}
|
||||
|
||||
// 84 切片 reducer:ContractState(Ont / xv.bti,3 字段;7 个动作)
|
||||
run {
|
||||
fun Contract(Id: Any?, Progress: Any? = 0, Rewards: List<Any?> = emptyList()) =
|
||||
ContractEntry(ContractId = Id, Progress = Progress, Rewards = Rewards)
|
||||
|
||||
val S0 = ContractStateSlice()
|
||||
Check(
|
||||
"切片 ContractState:默认值完整",
|
||||
S0.ActiveContractId == null && S0.Contracts.isEmpty() &&
|
||||
S0.LastBattleProgress == 0
|
||||
)
|
||||
val S1 = ReduceContractState(S0, SetActiveContract("c1"))
|
||||
Check("切片 ContractState:SetActiveContract 写 id", S1.ActiveContractId == "c1")
|
||||
val S2 = ReduceContractState(S1, SetContract(listOf(Contract("c1"), Contract("c2"))))
|
||||
Check(
|
||||
"切片 ContractState:SetContract 按合同 id 合并",
|
||||
S2.Contracts.keys == setOf<Any?>("c1", "c2")
|
||||
)
|
||||
Check(
|
||||
"切片 ContractState:UpdateProgress 复制该合同",
|
||||
ReduceContractState(S2, UpdateProgress("c1", 5))
|
||||
.let { (it.Contracts["c1"] as ContractEntry).Progress == 5 }
|
||||
)
|
||||
Check(
|
||||
"切片 ContractState:SetBattleProgress 写战斗进度",
|
||||
ReduceContractState(S2, SetBattleProgress(7)).LastBattleProgress == 7
|
||||
)
|
||||
val S3 = ReduceContractState(
|
||||
ReduceContractState(S2, SetContract(listOf(Contract("c2", 1, listOf("r"))))),
|
||||
ClaimContractReward("c2"),
|
||||
)
|
||||
Check(
|
||||
"切片 ContractState:ClaimContractReward 清空该合同奖励",
|
||||
(S3.Contracts["c2"] as ContractEntry).Rewards.isEmpty() &&
|
||||
(S3.Contracts["c1"] as ContractEntry).Rewards.isEmpty()
|
||||
)
|
||||
Check(
|
||||
"切片 ContractState:RemoveCompletedContracts 只留还有奖励的",
|
||||
ReduceContractState(
|
||||
ReduceContractState(
|
||||
S2,
|
||||
SetContract(listOf(Contract("c1", 2, listOf("r")))),
|
||||
),
|
||||
RemoveCompletedContracts,
|
||||
).Contracts.keys == setOf<Any?>("c1")
|
||||
)
|
||||
Check(
|
||||
"切片 ContractState:InitBattle 只把战斗进度归零",
|
||||
ReduceContractState(S3, InitBattle()).let {
|
||||
it.LastBattleProgress == 0 && it.Contracts.keys == setOf<Any?>("c1", "c2")
|
||||
}
|
||||
)
|
||||
Check(
|
||||
"切片 ContractState:无关动作不改状态",
|
||||
ReduceContractState(S3, AddFrags(1)) == S3
|
||||
)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, SetActiveContract("x"))
|
||||
Check(
|
||||
"根:SetActiveContract 只动 contractState",
|
||||
Root1.ContractState.ActiveContractId == "x" &&
|
||||
Root1.BattleSettings == Root0.BattleSettings
|
||||
)
|
||||
val W = RootWiring.ByField("contractState")!!
|
||||
Check(
|
||||
"根:contractState 委派到 Ont / xv.bti 且 7 个动作",
|
||||
W.SliceClass == "Ont" && W.Reducer == "xv.bti" && W.Actions.size == 7
|
||||
)
|
||||
}
|
||||
|
||||
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