feat(state): 迁移 battleChat(复用 ChatMessage 协议模型)
This commit is contained in:
1 parent
8dac8d96e8
commit
5327312b13
8 files changed
+214
-25
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` 动作名。
|
||||
- 已迁移切片 **77/89**:
|
||||
- 已迁移切片 **78/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)
|
||||
@@ -388,12 +388,16 @@
|
||||
`AddMap` 的动作载荷就是生成物里的 `MapInfoCC`(11 个字段,与源码 properties 一致),
|
||||
直接复用;reducer 以 `info.mapId` 为键新建 / 复用 `MapsDescriptionEntry`,
|
||||
再把 `MapsThemeEntry` 写进 `themes[info.theme]`(同地图多主题是合并)。
|
||||
- `battleChat` → `Q6` / `Hf.wtg`(`BattleChatStateReducer.kt`):6 字段,6 个分支。
|
||||
`ChatLoaded` 写两个频道开关并置 `loaded`;`AddMessage` 只保留最后 120 条再追加;
|
||||
`ett`/`utt` 开关输入框、`stt` 取反历史面板、`rtt`→`ResetBattleChat` 整片复位。
|
||||
消息类型直接复用生成物里的协议模型 `ChatMessage`(13 字段)。
|
||||
- `launchParams` → `(pass-through)`:原根 reducer 对 `hpx_1` 没有调用,缺省是 `ag()` 空 Map;
|
||||
`RootState.LaunchParams` 收口为 `LaunchParamsStateSlice = Map<String, String>`,不新增 reducer/动作。
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 76 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **12 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 77/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **838 项全绿**,含 89 槽位完整性、76 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 77 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **11 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 78/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **848 项全绿**,含 89 槽位完整性、77 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generatedAt": "2026-10-24T11:49:38.715Z",
|
||||
"generatedAt": "2026-10-24T12:02:07.703Z",
|
||||
"module": "module_10032.js",
|
||||
"RootState": {
|
||||
"Class": "z6",
|
||||
@@ -83,7 +83,8 @@
|
||||
"contractState",
|
||||
"tankBuilderState",
|
||||
"battleMessage",
|
||||
"maps"
|
||||
"maps",
|
||||
"battleChat"
|
||||
],
|
||||
"AnonymousActions": [
|
||||
{
|
||||
@@ -1387,6 +1388,30 @@
|
||||
"Local": "FA",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "按 info.mapId 新建/复用 MapDescription,并把 MapInfo 写进 themes[themeId](原名 AddMap)"
|
||||
},
|
||||
{
|
||||
"Local": "ett",
|
||||
"Name": "OpenBattleChatInput",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "isInputActive=true(`n.ctl(cd, cd, cd, cd, !0)`)"
|
||||
},
|
||||
{
|
||||
"Local": "utt",
|
||||
"Name": "CloseBattleChatInput",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "isInputActive=false(`n.ctl(cd, cd, cd, cd, !1)`)"
|
||||
},
|
||||
{
|
||||
"Local": "stt",
|
||||
"Name": "ToggleBattleChatHistory",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "isHistoryOpen=!isHistoryOpen(`n.ctl(cd, cd, cd, cd, cd, !n.atl_1)`)"
|
||||
},
|
||||
{
|
||||
"Local": "rtt",
|
||||
"Name": "ResetBattleChat",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "new Q6() 整片复位"
|
||||
}
|
||||
],
|
||||
"Markers": [
|
||||
@@ -2495,15 +2520,15 @@
|
||||
"Reducer": "Hf.wtg",
|
||||
"Delegate": "Hf.wtg(t, n.rpw_1)",
|
||||
"Actions": [
|
||||
"?ett",
|
||||
"?rtt",
|
||||
"?stt",
|
||||
"?utt",
|
||||
"AddMessage",
|
||||
"ChatLoaded"
|
||||
"ChatLoaded",
|
||||
"CloseBattleChatInput",
|
||||
"OpenBattleChatInput",
|
||||
"ResetBattleChat",
|
||||
"ToggleBattleChatHistory"
|
||||
],
|
||||
"Default": "new Q6()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "droppableGold",
|
||||
|
||||
@@ -318,6 +318,11 @@ const AnonymousActionNames = new Map([
|
||||
['Trt', 'ResetTankBuilder'],
|
||||
// battleMessage 切片(FE / fT.rqb):sT 没有 toString。
|
||||
['sT', 'ResetBattleMessages'],
|
||||
// battleChat 切片(Q6 / htt.wtg):ett/utt/stt/rtt 没有 toString。
|
||||
['ett', 'OpenBattleChatInput'],
|
||||
['utt', 'CloseBattleChatInput'],
|
||||
['stt', 'ToggleBattleChatHistory'],
|
||||
['rtt', 'ResetBattleChat'],
|
||||
]);
|
||||
|
||||
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
||||
@@ -796,6 +801,7 @@ const Migrated = {
|
||||
tankBuilderState: { Type: 'TankBuilderStateSlice', Reduce: 'ReduceTankBuilder' },
|
||||
battleMessage: { Type: 'BattleMessageStateSlice', Reduce: 'ReduceBattleMessage' },
|
||||
maps: { Type: 'MapsStateSlice', Reduce: 'ReduceMaps' },
|
||||
battleChat: { Type: 'BattleChatStateSlice', Reduce: 'ReduceBattleChat' },
|
||||
};
|
||||
|
||||
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
||||
@@ -1204,6 +1210,10 @@ const AppSettingsAnonymousEffects = {
|
||||
Trt: 'new brt() 整片复位',
|
||||
sT: 'new FE() 整片复位',
|
||||
FA: '按 info.mapId 新建/复用 MapDescription,并把 MapInfo 写进 themes[themeId](原名 AddMap)',
|
||||
ett: 'isInputActive=true(`n.ctl(cd, cd, cd, cd, !0)`)',
|
||||
utt: 'isInputActive=false(`n.ctl(cd, cd, cd, cd, !1)`)',
|
||||
stt: 'isHistoryOpen=!isHistoryOpen(`n.ctl(cd, cd, cd, cd, cd, !n.atl_1)`)',
|
||||
rtt: 'new Q6() 整片复位',
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// BattleChatStateReducer.kt —— 战斗聊天切片(对应 module_10032 的 Q6 状态 + htt.wtg)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 Q6:6 个字段,toString 名 "BattleChatState(…)"。
|
||||
// 默认:commonBattleChatEnabled=true、teamBattleChatEnabled=true、loaded=false、
|
||||
// messages=emptyList()、isInputActive=false、isHistoryOpen=false。
|
||||
// 根委派:`Hf.wtg(t, n.rpw_1)`。
|
||||
// reducer(6 个实例臂):
|
||||
// itt(ChatLoaded) → 两个频道开关 + loaded=true
|
||||
// ntt(AddMessage) → messages 只保留最后 120 条再追加(`r.q1(max(size-120,0), size)`)
|
||||
// ett(无 toString) → isInputActive=true
|
||||
// utt(无 toString) → isInputActive=false
|
||||
// stt(无 toString) → isHistoryOpen 取反
|
||||
// rtt(无 toString) → `new Q6()` 整片复位
|
||||
//
|
||||
// 消息类型复用生成物里的协议模型 `ChatMessage`(addressMode / channel / id / messageType /
|
||||
// sourceUser / text / userId / timePassedInSec 等 13 个字段)。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.AddMessage
|
||||
import App.State.ChatLoaded
|
||||
|
||||
/* ------------------------------------------------------------------ 匿名动作 */
|
||||
|
||||
/** 原 `ett`:打开输入框。 */
|
||||
object OpenBattleChatInput
|
||||
|
||||
/** 原 `utt`:收起输入框。 */
|
||||
object CloseBattleChatInput
|
||||
|
||||
/** 原 `stt`:切换历史记录面板。 */
|
||||
object ToggleBattleChatHistory
|
||||
|
||||
/** 原 `rtt`:整片复位(`new Q6()`)。 */
|
||||
object ResetBattleChat
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class BattleChatStateSlice(
|
||||
val CommonBattleChatEnabled: Boolean = true,
|
||||
val TeamBattleChatEnabled: Boolean = true,
|
||||
val Loaded: Boolean = false,
|
||||
val Messages: List<Any?> = emptyList(),
|
||||
val IsInputActive: Boolean = false,
|
||||
val IsHistoryOpen: Boolean = false,
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
/** 原 `r.q1(max(0, size - 120), size)`:只保留最后 120 条。 */
|
||||
private const val MaxMessages = 120
|
||||
|
||||
private fun AppendMessage(Current: List<Any?>, Message: Any?): List<Any?> {
|
||||
val Added = Current + Message
|
||||
return if (Added.size <= MaxMessages) Added
|
||||
else Added.subList(Added.size - MaxMessages, Added.size)
|
||||
}
|
||||
|
||||
fun ReduceBattleChat(
|
||||
State0: BattleChatStateSlice,
|
||||
Action: Any,
|
||||
): BattleChatStateSlice = when (Action) {
|
||||
is ChatLoaded -> State0.copy(
|
||||
CommonBattleChatEnabled = Action.commonBattleChatEnabled,
|
||||
TeamBattleChatEnabled = Action.teamBattleChatEnabled,
|
||||
Loaded = true,
|
||||
)
|
||||
is AddMessage -> State0.copy(Messages = AppendMessage(State0.Messages, Action.message))
|
||||
is OpenBattleChatInput -> State0.copy(IsInputActive = true)
|
||||
is CloseBattleChatInput -> State0.copy(IsInputActive = false)
|
||||
is ToggleBattleChatHistory -> State0.copy(IsHistoryOpen = !State0.IsHistoryOpen)
|
||||
is ResetBattleChat -> BattleChatStateSlice()
|
||||
else -> State0
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// RootReducer.kt —— 根 reducer 骨架(对应 module_10032 的根状态 z6 / TOState 与根 reducer k6)
|
||||
//
|
||||
// 原包 k6 对 89 个切片逐个调用各自的 reducer,再 `return n.cti(...)`(copy 出新状态)。
|
||||
// 这里采用同一形状。已迁移的 77 个切片里,76 个真正调用 reducer,launchParams 只做类型收口:
|
||||
// 这里采用同一形状。已迁移的 78 个切片里,77 个真正调用 reducer,launchParams 只做类型收口:
|
||||
//
|
||||
// inviteState → ReduceInvite(aD / pD.er5)
|
||||
// loginByPassword → ReduceLoginByPassword(gD / MD.cr6)
|
||||
@@ -79,9 +79,10 @@
|
||||
// tankBuilderState → ReduceTankBuilder(brt / wp.ati,根委派 `wp.ati(t, n.epy_1)`)
|
||||
// battleMessage → ReduceBattleMessage(FE / vT().rqb,根委派 `vT().rqb(t, n.qpw_1)`)
|
||||
// maps → ReduceMaps(OA / Oi.sql,根委派 `Oi.sql(t, n.bpw_1)`)
|
||||
// battleChat → ReduceBattleChat(Q6 / Hf.wtg,根委派 `Hf.wtg(t, n.rpw_1)`)
|
||||
// launchParams → 无 reducer(原根 reducer 原样透传;默认 `ag()` = emptyMap())
|
||||
//
|
||||
// 其余 12 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 其余 11 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
||||
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
||||
package App.State
|
||||
@@ -90,6 +91,7 @@ import App.State.Reducers.ReduceAccountSettings
|
||||
import App.State.Reducers.ReduceAnnouncement
|
||||
import App.State.Reducers.ReduceAntiAddiction
|
||||
import App.State.Reducers.ReduceBattleResult
|
||||
import App.State.Reducers.ReduceBattleChat
|
||||
import App.State.Reducers.ReduceBattleMessage
|
||||
import App.State.Reducers.ReduceBattlePause
|
||||
import App.State.Reducers.ReduceBattleSearch
|
||||
@@ -252,6 +254,7 @@ object RootReducer {
|
||||
TankBuilderState = ReduceTankBuilder(State0.TankBuilderState, Action),
|
||||
BattleMessage = ReduceBattleMessage(State0.BattleMessage, Action),
|
||||
Maps = ReduceMaps(State0.Maps, Action),
|
||||
BattleChat = ReduceBattleChat(State0.BattleChat, Action),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import App.State.Reducers.AccountSettingsStateSlice
|
||||
import App.State.Reducers.AnnouncementStateSlice
|
||||
import App.State.Reducers.AntiAddictionStateSlice
|
||||
import App.State.Reducers.AvailabilityByRankStateSlice
|
||||
import App.State.Reducers.BattleChatStateSlice
|
||||
import App.State.Reducers.BattleInviteStateSlice
|
||||
import App.State.Reducers.BattleMessageStateSlice
|
||||
import App.State.Reducers.BattlePauseStateSlice
|
||||
@@ -175,8 +176,8 @@ data class RootState(
|
||||
val TankActionsLogState: TankActionsLogStateSlice = TankActionsLogStateSlice(),
|
||||
/** 原 battleMessage(FE / vT().rqb)。已迁移。 */
|
||||
val BattleMessage: BattleMessageStateSlice = BattleMessageStateSlice(),
|
||||
/** 原 battleChat(Q6 / Hf.wtg)。未迁移:原样透传。 */
|
||||
val BattleChat: Any? = null,
|
||||
/** 原 battleChat(Q6 / Hf.wtg)。已迁移。 */
|
||||
val BattleChat: BattleChatStateSlice = BattleChatStateSlice(),
|
||||
/** 原 droppableGold(Vet / Wp.kth)。已迁移。 */
|
||||
val DroppableGold: DroppableGoldStateSlice = DroppableGoldStateSlice(),
|
||||
/** 原 home(s1 / (inline@home))。已迁移。 */
|
||||
|
||||
@@ -59,7 +59,7 @@ object RootWiring {
|
||||
SliceWiring("clanUserInfo", "opw_1", "hO", "de.gr1", "de.gr1(t, n.opw_1)", listOf("Loaded")),
|
||||
SliceWiring("tankActionsLogState", "ppw_1", "vI", "wi.gqe", "wi.gqe(t, n.ppw_1)", listOf("OnUserJoinTheBattle", "OnUserLeaveTheBattle", "ResetTankActionsLog", "UpdateLog")),
|
||||
SliceWiring("battleMessage", "qpw_1", "FE", "vT().rqb", "vT().rqb(t, n.qpw_1)", listOf("DoAddLocalizedMessage", "DoAddLocalizedTeamMessage", "DoAddLocalizedUserMessage", "DoAddTextMessage", "HideMessage", "RemoveMessage", "ResetBattleMessages")),
|
||||
SliceWiring("battleChat", "rpw_1", "Q6", "Hf.wtg", "Hf.wtg(t, n.rpw_1)", listOf("?ett", "?rtt", "?stt", "?utt", "AddMessage", "ChatLoaded")),
|
||||
SliceWiring("battleChat", "rpw_1", "Q6", "Hf.wtg", "Hf.wtg(t, n.rpw_1)", listOf("AddMessage", "ChatLoaded", "CloseBattleChatInput", "OpenBattleChatInput", "ResetBattleChat", "ToggleBattleChatHistory")),
|
||||
SliceWiring("droppableGold", "spw_1", "Vet", "Wp.kth", "Wp.kth(t, n.spw_1)", listOf("HideDroppableGoldAuthor", "ShowDroppableGoldAuthor")),
|
||||
SliceWiring("home", "tpw_1", "s1", "(inline@home)", "(function (t, n) { return t instanceof o1 ? n.f7j(!0) : n; })(t, n.tpw_1)", listOf("ShowShopDiscountNotification")),
|
||||
SliceWiring("localBattleUserState", "upw_1", "lE", "(inline@localBattleUserState)", "(function (t, n) { return t instanceof fE ? n.xq8(t.yq8_1) : t instanceof vE ? n.xq8(cd, t.zq8_1) : n; })(t, n.upw_1)", listOf("SetLocalWeaponResistanceProperty", "SetReArmorTemporaryDisabled")),
|
||||
@@ -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")
|
||||
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")
|
||||
|
||||
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
||||
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;
|
||||
// BattlePause / BattleView / TankActionsLog / SuppliesTutorial / ClanChat / BattleSearch / BattleStatistics / SoundSettings / GameSettings / KeyboardSettings / TouchscreenHudSettings / GraphicsSettings / ControlSettings / BattleSettings / ContractState / TankBuilder / BattleMessage / Maps / BattleChat;
|
||||
// ㉑ launchParams 是纯透传切片(无 reducer/动作),只做 Map 类型收口;⑭ 根 reducer 的 89 槽位委派
|
||||
//
|
||||
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
||||
@@ -736,6 +736,15 @@ import App.State.Reducers.MapsDescriptionEntry
|
||||
import App.State.Reducers.MapsStateSlice
|
||||
import App.State.Reducers.MapsThemeEntry
|
||||
import App.State.Reducers.ReduceMaps
|
||||
import App.State.AddMessage
|
||||
import App.State.ChatLoaded
|
||||
import App.State.ChatMessage
|
||||
import App.State.Reducers.BattleChatStateSlice
|
||||
import App.State.Reducers.CloseBattleChatInput
|
||||
import App.State.Reducers.OpenBattleChatInput
|
||||
import App.State.Reducers.ReduceBattleChat
|
||||
import App.State.Reducers.ResetBattleChat
|
||||
import App.State.Reducers.ToggleBattleChatHistory
|
||||
import App.State.Reducers.UserRankBounds
|
||||
import App.State.Reducers.UserStateSlice
|
||||
import App.State.Reducers.ClearHullData
|
||||
@@ -1163,7 +1172,7 @@ object StateCheck {
|
||||
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
||||
}
|
||||
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 77 个已迁移切片(76 归约 + launchParams 透传)
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 78 个已迁移切片(77 归约 + launchParams 透传)
|
||||
run {
|
||||
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
||||
Check(
|
||||
@@ -1227,7 +1236,7 @@ object StateCheck {
|
||||
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
||||
)
|
||||
Check(
|
||||
"根:迁移表 = 77 个已迁移字段,其余 12 个待迁",
|
||||
"根:迁移表 = 78 个已迁移字段,其余 11 个待迁",
|
||||
RootReducer.Migrated ==
|
||||
setOf(
|
||||
"inviteState", "loginByPassword", "twitchState", "home",
|
||||
@@ -1250,9 +1259,9 @@ object StateCheck {
|
||||
"clanChatState", "battleSearchState", "battleStatistics",
|
||||
"soundSettings", "gameSettings", "keyboardSettings", "touchscreenHudSettings",
|
||||
"graphicsSettings", "controlSettings", "battleSettings", "contractState",
|
||||
"tankBuilderState", "battleMessage", "maps",
|
||||
"tankBuilderState", "battleMessage", "maps", "battleChat",
|
||||
) &&
|
||||
RootWiring.Unmigrated.size == 12
|
||||
RootWiring.Unmigrated.size == 11
|
||||
)
|
||||
|
||||
// 一次 ReduceRoot 里多个切片各归约自己的动作,互不串片
|
||||
@@ -1308,7 +1317,7 @@ object StateCheck {
|
||||
S5.User.Uid == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
||||
)
|
||||
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 77/89")
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 78/89")
|
||||
|
||||
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
||||
Store.Dispatch(SetStatus("LOGGING_IN"))
|
||||
@@ -6397,6 +6406,69 @@ object StateCheck {
|
||||
)
|
||||
}
|
||||
|
||||
// 88 切片 reducer:BattleChat(Q6 / Hf.wtg,6 字段;6 个动作)
|
||||
run {
|
||||
fun Msg(Id: Int): ChatMessage = ChatMessage(
|
||||
addressMode = "", battleLinks = emptyList(), channel = "battle", id = Id,
|
||||
links = emptyList(), messageType = "text", sourceUser = "u", ip = "",
|
||||
uid = null, userId = "1", targetUser = null, text = "m$Id", timePassedInSec = 0,
|
||||
)
|
||||
|
||||
val S0 = BattleChatStateSlice()
|
||||
Check(
|
||||
"切片 BattleChat:默认两个频道开、未加载",
|
||||
S0.CommonBattleChatEnabled && S0.TeamBattleChatEnabled && !S0.Loaded &&
|
||||
S0.Messages.isEmpty() && !S0.IsInputActive && !S0.IsHistoryOpen
|
||||
)
|
||||
val S1 = ReduceBattleChat(S0, ChatLoaded(false, true))
|
||||
Check(
|
||||
"切片 BattleChat:ChatLoaded 写频道开关并置 loaded",
|
||||
!S1.CommonBattleChatEnabled && S1.TeamBattleChatEnabled && S1.Loaded
|
||||
)
|
||||
val S2 = ReduceBattleChat(S1, AddMessage(Msg(1)))
|
||||
Check(
|
||||
"切片 BattleChat:AddMessage 追加消息",
|
||||
S2.Messages.size == 1 && (S2.Messages[0] as ChatMessage).id == 1
|
||||
)
|
||||
var S3 = S2
|
||||
for (I in 2..130) S3 = ReduceBattleChat(S3, AddMessage(Msg(I)))
|
||||
Check(
|
||||
"切片 BattleChat:超过 120 条只保留最后 120",
|
||||
S3.Messages.size == 120 &&
|
||||
(S3.Messages.last() as ChatMessage).id == 130
|
||||
)
|
||||
Check(
|
||||
"切片 BattleChat:输入框开关两态",
|
||||
ReduceBattleChat(S3, OpenBattleChatInput).IsInputActive &&
|
||||
!ReduceBattleChat(S3, CloseBattleChatInput).IsInputActive
|
||||
)
|
||||
Check(
|
||||
"切片 BattleChat:ToggleBattleChatHistory 取反",
|
||||
ReduceBattleChat(S3, ToggleBattleChatHistory).IsHistoryOpen
|
||||
)
|
||||
Check(
|
||||
"切片 BattleChat:ResetBattleChat 整片复位",
|
||||
ReduceBattleChat(S3, ResetBattleChat) == BattleChatStateSlice()
|
||||
)
|
||||
Check(
|
||||
"切片 BattleChat:无关动作不改状态",
|
||||
ReduceBattleChat(S3, AddFrags(1)) == S3
|
||||
)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, OpenBattleChatInput)
|
||||
Check(
|
||||
"根:OpenBattleChatInput 只动 battleChat",
|
||||
Root1.BattleChat.IsInputActive && Root1.Maps == Root0.Maps
|
||||
)
|
||||
val W = RootWiring.ByField("battleChat")!!
|
||||
Check(
|
||||
"根:battleChat 委派到 Q6 / Hf.wtg 且 6 个动作",
|
||||
W.SliceClass == "Q6" && W.Reducer == "Hf.wtg" &&
|
||||
W.Actions.size == 6
|
||||
)
|
||||
}
|
||||
|
||||
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