feat(state): 迁移 clanChatState/battleSearchState
This commit is contained in:
1 parent
4c11c3e530
commit
437c71ccdb
9 files changed
+360
-28
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` 动作名。
|
||||
- 已迁移切片 **63/89**:
|
||||
- 已迁移切片 **65/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)
|
||||
@@ -341,12 +341,18 @@
|
||||
`OnUserJoinTheBattle` / `OnUserLeaveTheBattle` 增删 `noticed`;`dI`→`ResetTankActionsLog` 整片复位。
|
||||
- `suppliesTutorial` → `ust` / `Uw.uth`(`SuppliesTutorialReducer.kt`):2 字段,2 个分支。
|
||||
生成器认不出切片类(根构造默认值不是 `new ust()`),在迁移表里显式补 `SliceClass: 'ust'`。
|
||||
- `clanChatState` → `qnt` / `yv.qtg`(`ClanChatStateReducer.kt`):3 字段,5 个分支。
|
||||
`$nt`/`xnt` 开关面板,`Configure` 写配置(`ynt` 的 `config` 与 clan 切片同名动作冲突,
|
||||
整条动作对象按配置载荷收口),`DoAddMessages` 追加后只保留最后 100 条,`Tnt` 整片复位。
|
||||
- `battleSearchState` → `Itt` / `Htt().vtg`(`BattleSearchStateReducer.kt`):5 字段,9 个分支。
|
||||
`Fight` 只发副作用、状态不变;`RemoveBattle` 仅当选中 id 匹配时清空;
|
||||
`selectedFormat` 默认值来自服务定位器,按 `null` 收口。
|
||||
- `launchParams` → `(pass-through)`:原根 reducer 对 `hpx_1` 没有调用,缺省是 `ag()` 空 Map;
|
||||
`RootState.LaunchParams` 收口为 `LaunchParamsStateSlice = Map<String, String>`,不新增 reducer/动作。
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 62 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **26 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 63/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **719 项全绿**,含 89 槽位完整性、62 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 64 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **24 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 65/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **741 项全绿**,含 89 槽位完整性、64 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||
@@ -366,6 +372,7 @@
|
||||
friends 的 2 个、suppliesState 的 1 个、battleInviteState 的 2 个、partner 的 4 个、
|
||||
userRenameState 的 5 个也已登记(其中 `mtt` 因同名类冲突改名为 `AddInvitedUser`);
|
||||
battlePauseState 的 2 个、battleViewState 的 12 个、tankActionsLogState 的 1 个同样按效果定名。
|
||||
clanChatState 的 3 个(`$nt`/`xnt`/`Tnt`)、battleSearchState 的 1 个也已登记。
|
||||
|
||||
### S4 引擎核心
|
||||
- 模块:32088(3D 数学)、92980(渲染)、61378(ECS)、55088(物理)、36659 + 71105(资源)、36734(音频)、3569(输入)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generatedAt": "2026-10-24T08:27:50.811Z",
|
||||
"generatedAt": "2026-10-24T08:38:53.378Z",
|
||||
"module": "module_10032.js",
|
||||
"RootState": {
|
||||
"Class": "z6",
|
||||
@@ -69,7 +69,9 @@
|
||||
"battlePauseState",
|
||||
"battleViewState",
|
||||
"tankActionsLogState",
|
||||
"suppliesTutorial"
|
||||
"suppliesTutorial",
|
||||
"clanChatState",
|
||||
"battleSearchState"
|
||||
],
|
||||
"AnonymousActions": [
|
||||
{
|
||||
@@ -1182,6 +1184,30 @@
|
||||
"Name": "ResetTankActionsLog",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "new vI() 整片复位"
|
||||
},
|
||||
{
|
||||
"Local": "$nt",
|
||||
"Name": "OpenClanChat",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "open=true(`n.qtp(!0)`)"
|
||||
},
|
||||
{
|
||||
"Local": "xnt",
|
||||
"Name": "CloseClanChat",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "open=false(`n.qtp(!1)`)"
|
||||
},
|
||||
{
|
||||
"Local": "Tnt",
|
||||
"Name": "ResetClanChat",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "new qnt() 整片复位"
|
||||
},
|
||||
{
|
||||
"Local": "Dtt",
|
||||
"Name": "ClearSelectedBattle",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "selectedBattleId=null(`n.vtn(cd, cd, cd, cd, null)`)"
|
||||
}
|
||||
],
|
||||
"Markers": [
|
||||
@@ -1660,14 +1686,14 @@
|
||||
"Reducer": "yv.qtg",
|
||||
"Delegate": "yv.qtg(t, n.ppv_1)",
|
||||
"Actions": [
|
||||
"?$nt",
|
||||
"?Tnt",
|
||||
"?xnt",
|
||||
"CloseClanChat",
|
||||
"Configure",
|
||||
"DoAddMessages"
|
||||
"DoAddMessages",
|
||||
"OpenClanChat",
|
||||
"ResetClanChat"
|
||||
],
|
||||
"Default": "new qnt()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "clan",
|
||||
@@ -1997,7 +2023,7 @@
|
||||
"Reducer": "Htt().vtg",
|
||||
"Delegate": "Htt().vtg(t, n.epw_1)",
|
||||
"Actions": [
|
||||
"?Dtt",
|
||||
"ClearSelectedBattle",
|
||||
"EnterToBattle",
|
||||
"Fight",
|
||||
"RemoveBattle",
|
||||
@@ -2008,7 +2034,7 @@
|
||||
"SetSuspiciousFilter"
|
||||
],
|
||||
"Default": "new Itt()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "lobbyLoader",
|
||||
|
||||
@@ -275,6 +275,12 @@ const AnonymousActionNames = new Map([
|
||||
['eI', 'LeaveBackground'],
|
||||
// tankActionsLogState 切片(vI / yI.gqe):dI 没有 toString。
|
||||
['dI', 'ResetTankActionsLog'],
|
||||
// clanChatState 切片(qnt / Int.qtg):$nt/xnt/Tnt 没有 toString。
|
||||
['$nt', 'OpenClanChat'],
|
||||
['xnt', 'CloseClanChat'],
|
||||
['Tnt', 'ResetClanChat'],
|
||||
// battleSearchState 切片(Itt / Gtt.vtg):Dtt 没有 toString。
|
||||
['Dtt', 'ClearSelectedBattle'],
|
||||
]);
|
||||
|
||||
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
||||
@@ -731,6 +737,8 @@ const Migrated = {
|
||||
SliceClass: 'ust',
|
||||
Reduce: 'ReduceSuppliesTutorial',
|
||||
},
|
||||
clanChatState: { Type: 'ClanChatStateSlice', Reduce: 'ReduceClanChat' },
|
||||
battleSearchState: { Type: 'BattleSearchStateSlice', Reduce: 'ReduceBattleSearch' },
|
||||
};
|
||||
|
||||
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
||||
@@ -1093,6 +1101,18 @@ const TankActionsLogAnonymousEffects = {
|
||||
dI: 'new vI() 整片复位',
|
||||
};
|
||||
|
||||
// clanChatState 切片(qnt / Int.qtg):$nt/xnt/Tnt 没有 toString。
|
||||
const ClanChatAnonymousEffects = {
|
||||
$nt: 'open=true(`n.qtp(!0)`)',
|
||||
xnt: 'open=false(`n.qtp(!1)`)',
|
||||
Tnt: 'new qnt() 整片复位',
|
||||
};
|
||||
|
||||
// battleSearchState 切片(Itt / Gtt.vtg):Dtt 没有 toString。
|
||||
const BattleSearchAnonymousEffects = {
|
||||
Dtt: 'selectedBattleId=null(`n.vtn(cd, cd, cd, cd, null)`)',
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(P, 'names', 'root_wiring.json'),
|
||||
JSON.stringify(
|
||||
@@ -1337,6 +1357,18 @@ fs.writeFileSync(
|
||||
DispatchedAt: '未在 action_trace_merged.json 中出现;按 reducer 分支效果定名',
|
||||
Effect,
|
||||
})),
|
||||
...Object.entries(ClanChatAnonymousEffects).map(([Local, Effect]) => ({
|
||||
Local,
|
||||
Name: AnonymousActionNames.get(Local),
|
||||
DispatchedAt: '未在 action_trace_merged.json 中出现;按 reducer 分支效果定名',
|
||||
Effect,
|
||||
})),
|
||||
...Object.entries(BattleSearchAnonymousEffects).map(([Local, Effect]) => ({
|
||||
Local,
|
||||
Name: AnonymousActionNames.get(Local),
|
||||
DispatchedAt: '未在 action_trace_merged.json 中出现;按 reducer 分支效果定名',
|
||||
Effect,
|
||||
})),
|
||||
],
|
||||
Markers: [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// BattleSearchStateReducer.kt —— 战斗搜索切片(对应 module_10032 的 Itt 状态 + Gtt.vtg)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 Itt:5 个字段,toString 名 "BattleSearchState(…)"。
|
||||
// 默认:filter=null、selectedFormat=cA().xqh()、search=null、suspiciousBattlesOnly=false、
|
||||
// selectedBattleId=null。
|
||||
// 根委派:`Htt().vtg(t, n.epw_1)`。
|
||||
// reducer(9 个实例臂):
|
||||
// Ntt(SetFilter) → filter
|
||||
// Mtt(SetSearch) → search
|
||||
// Ptt(SetSuspiciousFilter)→ suspiciousBattlesOnly
|
||||
// Vtt(Fight) → 状态不变(原分支只发 `Fy().ven()` 副作用)
|
||||
// FH(EnterToBattle) → search=null
|
||||
// Ott(SelectBattle) → selectedBattleId
|
||||
// Ltt(SelectBattleFormat)→ selectedFormat
|
||||
// kA(RemoveBattle) → 选中的正是该战斗时清空 selectedBattleId
|
||||
// Dtt(无 toString) → selectedBattleId=null
|
||||
//
|
||||
// `selectedFormat` 的默认值 `cA().xqh()` 来自服务定位器,离线重建按 `null` 收口。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.BattleFormat
|
||||
import App.State.EnterToBattle
|
||||
import App.State.Fight
|
||||
import App.State.RemoveBattle
|
||||
import App.State.SelectBattle
|
||||
import App.State.SelectBattleFormat
|
||||
import App.State.SetFilter
|
||||
import App.State.SetSearch
|
||||
import App.State.SetSuspiciousFilter
|
||||
|
||||
/* ------------------------------------------------------------------ 匿名动作 */
|
||||
|
||||
/** 原 `Dtt`:清空当前选中的战斗。 */
|
||||
object ClearSelectedBattle
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class BattleSearchStateSlice(
|
||||
val Filter: Boolean? = null,
|
||||
val SelectedFormat: BattleFormat? = null,
|
||||
val Search: Any? = null,
|
||||
val SuspiciousBattlesOnly: Boolean = false,
|
||||
val SelectedBattleId: Any? = null,
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
fun ReduceBattleSearch(
|
||||
State0: BattleSearchStateSlice,
|
||||
Action: Any,
|
||||
): BattleSearchStateSlice = when (Action) {
|
||||
is SetFilter -> State0.copy(Filter = Action.filter)
|
||||
is SetSearch -> State0.copy(Search = Action.search)
|
||||
is SetSuspiciousFilter ->
|
||||
State0.copy(SuspiciousBattlesOnly = Action.suspiciousBattlesOnly)
|
||||
// 原分支只发 `Fy().ven()`(特效/音效副作用),不改状态。
|
||||
is Fight -> State0
|
||||
is EnterToBattle -> State0.copy(Search = null)
|
||||
is SelectBattle -> State0.copy(SelectedBattleId = Action.battleId)
|
||||
is SelectBattleFormat -> State0.copy(SelectedFormat = Action.format)
|
||||
is RemoveBattle ->
|
||||
if (State0.SelectedBattleId == Action.battleId) State0.copy(SelectedBattleId = null)
|
||||
else State0
|
||||
is ClearSelectedBattle -> State0.copy(SelectedBattleId = null)
|
||||
else -> State0
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// ClanChatStateReducer.kt —— 战队聊天切片(对应 module_10032 的 qnt 状态 + Int.qtg)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 qnt:3 个字段,toString 名 "ClanChatState(…)"。
|
||||
// 默认:open=false、messages=emptyList()、config=null。
|
||||
// 根委派:`yv.qtg(t, n.ppv_1)`。
|
||||
// reducer(5 个实例臂):
|
||||
// $nt(无 toString) → open=true
|
||||
// xnt(无 toString) → open=false
|
||||
// ynt(Configure) → config
|
||||
// Cnt(DoAddMessages) → messages 追加后只保留最后 100 条
|
||||
// Tnt(无 toString) → `new qnt()` 整片复位
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.Configure
|
||||
import App.State.DoAddMessages
|
||||
|
||||
/* ------------------------------------------------------------------ 匿名动作 */
|
||||
|
||||
/** 原 `$nt`:展开战队聊天。 */
|
||||
object OpenClanChat
|
||||
|
||||
/** 原 `xnt`:收起战队聊天。 */
|
||||
object CloseClanChat
|
||||
|
||||
/** 原 `Tnt`:整片复位(`new qnt()`)。 */
|
||||
object ResetClanChat
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class ClanChatStateSlice(
|
||||
val Open: Boolean = false,
|
||||
val Messages: List<Any?> = emptyList(),
|
||||
val Config: Any? = null,
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
/** 原 `e.q1(max(0, size - 100), size)`:只保留最后 100 条。 */
|
||||
private const val MaxMessages = 100
|
||||
|
||||
private fun AppendMessages(Current: List<Any?>, Incoming: Any?): List<Any?> {
|
||||
val Added = if (Incoming is Iterable<*>) Current + Incoming else Current + Incoming
|
||||
return if (Added.size <= MaxMessages) Added
|
||||
else Added.subList(Added.size - MaxMessages, Added.size)
|
||||
}
|
||||
|
||||
fun ReduceClanChat(
|
||||
State0: ClanChatStateSlice,
|
||||
Action: Any,
|
||||
): ClanChatStateSlice = when (Action) {
|
||||
is OpenClanChat -> State0.copy(Open = true)
|
||||
is CloseClanChat -> State0.copy(Open = false)
|
||||
is Configure -> State0.copy(Config = Action)
|
||||
is DoAddMessages -> State0.copy(Messages = AppendMessages(State0.Messages, Action.messages))
|
||||
is ResetClanChat -> ClanChatStateSlice()
|
||||
else -> State0
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// RootReducer.kt —— 根 reducer 骨架(对应 module_10032 的根状态 z6 / TOState 与根 reducer k6)
|
||||
//
|
||||
// 原包 k6 对 89 个切片逐个调用各自的 reducer,再 `return n.cti(...)`(copy 出新状态)。
|
||||
// 这里采用同一形状。已迁移的 63 个切片里,62 个真正调用 reducer,launchParams 只做类型收口:
|
||||
// 这里采用同一形状。已迁移的 65 个切片里,64 个真正调用 reducer,launchParams 只做类型收口:
|
||||
//
|
||||
// inviteState → ReduceInvite(aD / pD.er5)
|
||||
// loginByPassword → ReduceLoginByPassword(gD / MD.cr6)
|
||||
@@ -65,9 +65,11 @@
|
||||
// battleViewState → ReduceBattleView(DT / sI.jqd,根委派 `(null == $n && new sI(), $n).jqd(t, n.mpw_1)`)
|
||||
// tankActionsLogState → ReduceTankActionsLog(vI / wi.gqe,根委派 `wi.gqe(t, n.ppw_1)`)
|
||||
// suppliesTutorial → ReduceSuppliesTutorial(ust / Uw.uth,根委派 `Uw.uth(t, n.zpx_1)`)
|
||||
// clanChatState → ReduceClanChat(qnt / yv.qtg,根委派 `yv.qtg(t, n.ppv_1)`)
|
||||
// battleSearchState → ReduceBattleSearch(Itt / Htt().vtg,根委派 `Htt().vtg(t, n.epw_1)`)
|
||||
// launchParams → 无 reducer(原根 reducer 原样透传;默认 `ag()` = emptyMap())
|
||||
//
|
||||
// 其余 26 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 其余 24 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
||||
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
||||
package App.State
|
||||
@@ -77,11 +79,13 @@ import App.State.Reducers.ReduceAnnouncement
|
||||
import App.State.Reducers.ReduceAntiAddiction
|
||||
import App.State.Reducers.ReduceBattleResult
|
||||
import App.State.Reducers.ReduceBattlePause
|
||||
import App.State.Reducers.ReduceBattleSearch
|
||||
import App.State.Reducers.ReduceBattleTutorial
|
||||
import App.State.Reducers.ReduceBattleView
|
||||
import App.State.Reducers.ReduceBattleInvite
|
||||
import App.State.Reducers.ReduceCaptcha
|
||||
import App.State.Reducers.ReduceClanUserInfo
|
||||
import App.State.Reducers.ReduceClanChat
|
||||
import App.State.Reducers.ReduceContextTutorial
|
||||
import App.State.Reducers.ReduceCreatorTag
|
||||
import App.State.Reducers.ReduceDroppableGold
|
||||
@@ -210,6 +214,8 @@ object RootReducer {
|
||||
BattleViewState = ReduceBattleView(State0.BattleViewState, Action),
|
||||
TankActionsLogState = ReduceTankActionsLog(State0.TankActionsLogState, Action),
|
||||
SuppliesTutorial = ReduceSuppliesTutorial(State0.SuppliesTutorial, Action),
|
||||
ClanChatState = ReduceClanChat(State0.ClanChatState, Action),
|
||||
BattleSearchState = ReduceBattleSearch(State0.BattleSearchState, Action),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@ import App.State.Reducers.AvailabilityByRankStateSlice
|
||||
import App.State.Reducers.BattleInviteStateSlice
|
||||
import App.State.Reducers.BattlePauseStateSlice
|
||||
import App.State.Reducers.BattleResultStateSlice
|
||||
import App.State.Reducers.BattleSearchStateSlice
|
||||
import App.State.Reducers.BattleTutorialStateSlice
|
||||
import App.State.Reducers.BattleViewStateSlice
|
||||
import App.State.Reducers.CaptchaStateSlice
|
||||
import App.State.Reducers.ClanChatStateSlice
|
||||
import App.State.Reducers.ClanUserInfoStateSlice
|
||||
import App.State.Reducers.ContextTutorialStateSlice
|
||||
import App.State.Reducers.CreatorTagStateSlice
|
||||
@@ -105,8 +107,8 @@ data class RootState(
|
||||
val Quests: QuestsStateSlice = QuestsStateSlice(),
|
||||
/** 原 chatState(LP / $r.wqv)。未迁移:原样透传。 */
|
||||
val ChatState: Any? = null,
|
||||
/** 原 clanChatState(qnt / yv.qtg)。未迁移:原样透传。 */
|
||||
val ClanChatState: Any? = null,
|
||||
/** 原 clanChatState(qnt / yv.qtg)。已迁移。 */
|
||||
val ClanChatState: ClanChatStateSlice = ClanChatStateSlice(),
|
||||
/** 原 clan(jN / we.hr0)。未迁移:原样透传。 */
|
||||
val Clan: Any? = null,
|
||||
/** 原 clansStorage(lO / me.vr1)。未迁移:原样透传。 */
|
||||
@@ -135,8 +137,8 @@ data class RootState(
|
||||
val Matchmaking: Any? = null,
|
||||
/** 原 battleCreateState($6 / Df.ttg)。未迁移:原样透传。 */
|
||||
val BattleCreateState: Any? = null,
|
||||
/** 原 battleSearchState(Itt / Htt().vtg)。未迁移:原样透传。 */
|
||||
val BattleSearchState: Any? = null,
|
||||
/** 原 battleSearchState(Itt / Htt().vtg)。已迁移。 */
|
||||
val BattleSearchState: BattleSearchStateSlice = BattleSearchStateSlice(),
|
||||
/** 原 lobbyLoader(KW / Bs.es1)。已迁移。 */
|
||||
val LobbyLoader: LobbyLoaderStateSlice = LobbyLoaderStateSlice(),
|
||||
/** 原 battleResult(sR / Fi.aqp)。已迁移。 */
|
||||
|
||||
@@ -31,7 +31,7 @@ object RootWiring {
|
||||
SliceWiring("system", "mpv_1", "_9", "w9().xt9", "w9().xt9(t, n.mpv_1)", listOf("DoShowMessage", "SetFatalError")),
|
||||
SliceWiring("quests", "npv_1", "Frt", "Yrt.otg", "(null == zp && new Yrt(), zp).otg(t, n.npv_1)", listOf("GoTo", "SetCurrentCategory", "SetNotCompletedQuests")),
|
||||
SliceWiring("chatState", "opv_1", "LP", "\$r.wqv", "\$r.wqv(t, n.opv_1)", listOf("?QP", "?XP", "?_C", "?bN", "?fN", "?lN", "?nN", "?pN", "?qN", "?sN", "?vN", "?wN", "ChangeChannel", "CleanUsersMessage", "Configure", "IgnoreUserMessages", "SaveChatMessage", "SendMessageToServer", "SetMessages", "SetSelectedUid", "ShowContextMenu", "ShowUserMessages", "UpdateTypingSpeedAntifloodParams", "UpdateUsers")),
|
||||
SliceWiring("clanChatState", "ppv_1", "qnt", "yv.qtg", "yv.qtg(t, n.ppv_1)", listOf("?\$nt", "?Tnt", "?xnt", "Configure", "DoAddMessages")),
|
||||
SliceWiring("clanChatState", "ppv_1", "qnt", "yv.qtg", "yv.qtg(t, n.ppv_1)", listOf("CloseClanChat", "Configure", "DoAddMessages", "OpenClanChat", "ResetClanChat")),
|
||||
SliceWiring("clan", "qpv_1", "jN", "we.hr0", "we.hr0(t, n.qpv_1)", listOf("?FM", "?IM", "?KM", "?PM", "?RM", "?VM", "?YM", "?iM", "AcceptedUserViewed", "AddIncomingClan", "AddNewIncoming", "AddNewIncomingClan", "AddOutgoingClan", "AddUsersToAccepted", "AddUsersToNewAccepted", "ClanBanned", "ClanInfoLoaded", "ClanLoaded", "ClanModalVisible", "IncomingAdded", "IncomingRemoved", "IncomingUserViewed", "MembersFetched", "NewAcceptedUserNotification", "NewClanInviteNotification", "NewIncomingUserNotification", "OutgoingAdded", "OutgoingRemoved", "RemoveIncomingClan", "RemoveNewIncoming", "RemoveNewIncomingClan", "RemoveOutgoingClan", "RemoveUserFromAccepted", "RemoveUsersFromNewAccepted", "SetClanEditPrice", "SetMinRankForCreate", "UpdateClanLicense", "UpdateClanNameValidation", "UpdateClanSearchValidation", "UpdateClanTagValidation", "UpdateHasClan", "UpdateTimeToJoinRestriction", "UpdateValidation")),
|
||||
SliceWiring("clansStorage", "rpv_1", "lO", "me.vr1", "me.vr1(t, n.rpv_1)", listOf("?mO", "AddUser", "AddUsersToNewAccepted", "BuyAdditionalPlace", "ClanLoaded", "ClanUnloaded", "ForeignClanLoaded", "MinimalRankChanged", "RecruitmentChanged", "RemoveUser", "RemoveUsersFromNewAccepted", "ShowForeignClan", "UpdateClan")),
|
||||
SliceWiring("tipsState", "spv_1", "dst", "Hw.vth", "Hw.vth(t, n.spv_1)", listOf("UpdateTips")),
|
||||
@@ -46,7 +46,7 @@ object RootWiring {
|
||||
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("?WH", "?nW", "?tW", "Configure", "EnterToBattleApply", "Play", "SelectMatchmakingMode", "SetRankIndexToMinGS", "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("battleSearchState", "epw_1", "Itt", "Htt().vtg", "Htt().vtg(t, n.epw_1)", listOf("?Dtt", "EnterToBattle", "Fight", "RemoveBattle", "SelectBattle", "SelectBattleFormat", "SetFilter", "SetSearch", "SetSuspiciousFilter")),
|
||||
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")),
|
||||
SliceWiring("battleUsers", "hpw_1", "uP", "sr.hqs", "sr.hqs(t, n.hpw_1)", listOf("?_P", "?hP", "?lP", "?oP", "?qP", "?sP", "InitSuspiciousState", "InitUserLevels", "RemoveTankInfo", "SetGearScore", "SetTankInfo", "SetTankResistance", "UpdateUserLevel", "UpdateUserRank", "UpdateUserScoreKillsAndDeaths", "UpdateUserSuspiciousState", "UpdateUsersClanTag", "UpdateUsersScoreKillsAndDeaths")),
|
||||
@@ -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")
|
||||
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")
|
||||
|
||||
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
||||
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;
|
||||
// BattlePause / BattleView / TankActionsLog / SuppliesTutorial / ClanChat / BattleSearch;
|
||||
// ㉑ launchParams 是纯透传切片(无 reducer/动作),只做 Map 类型收口;⑭ 根 reducer 的 89 槽位委派
|
||||
//
|
||||
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
||||
@@ -625,6 +625,24 @@ import App.State.ActivatedInCurrentBattle
|
||||
import App.State.SetLoadedElement
|
||||
import App.State.Reducers.ReduceSuppliesTutorial
|
||||
import App.State.Reducers.SuppliesTutorialStateSlice
|
||||
import App.State.Configure
|
||||
import App.State.DoAddMessages
|
||||
import App.State.Reducers.ClanChatStateSlice
|
||||
import App.State.Reducers.CloseClanChat
|
||||
import App.State.Reducers.OpenClanChat
|
||||
import App.State.Reducers.ReduceClanChat
|
||||
import App.State.Reducers.ResetClanChat
|
||||
import App.State.BattleFormat
|
||||
import App.State.EnterToBattle
|
||||
import App.State.RemoveBattle
|
||||
import App.State.SelectBattle
|
||||
import App.State.SelectBattleFormat
|
||||
import App.State.SetFilter
|
||||
import App.State.SetSearch
|
||||
import App.State.SetSuspiciousFilter
|
||||
import App.State.Reducers.BattleSearchStateSlice
|
||||
import App.State.Reducers.ClearSelectedBattle
|
||||
import App.State.Reducers.ReduceBattleSearch
|
||||
import App.State.Reducers.UserRankBounds
|
||||
import App.State.Reducers.UserStateSlice
|
||||
import App.State.Reducers.ClearHullData
|
||||
@@ -1052,7 +1070,7 @@ object StateCheck {
|
||||
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
||||
}
|
||||
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 63 个已迁移切片(62 归约 + launchParams 透传)
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 65 个已迁移切片(64 归约 + launchParams 透传)
|
||||
run {
|
||||
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
||||
Check(
|
||||
@@ -1116,7 +1134,7 @@ object StateCheck {
|
||||
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
||||
)
|
||||
Check(
|
||||
"根:迁移表 = 63 个已迁移字段,其余 26 个待迁",
|
||||
"根:迁移表 = 65 个已迁移字段,其余 24 个待迁",
|
||||
RootReducer.Migrated ==
|
||||
setOf(
|
||||
"inviteState", "loginByPassword", "twitchState", "home",
|
||||
@@ -1136,8 +1154,9 @@ object StateCheck {
|
||||
"friends", "suppliesState", "clanUserInfo", "battleInviteState",
|
||||
"partner", "userRenameState",
|
||||
"battlePauseState", "battleViewState", "tankActionsLogState", "suppliesTutorial",
|
||||
"clanChatState", "battleSearchState",
|
||||
) &&
|
||||
RootWiring.Unmigrated.size == 26
|
||||
RootWiring.Unmigrated.size == 24
|
||||
)
|
||||
|
||||
// 一次 ReduceRoot 里多个切片各归约自己的动作,互不串片
|
||||
@@ -1193,7 +1212,7 @@ object StateCheck {
|
||||
S5.User.Uid == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
||||
)
|
||||
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 63/89")
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 65/89")
|
||||
|
||||
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
||||
Store.Dispatch(SetStatus("LOGGING_IN"))
|
||||
@@ -5476,6 +5495,121 @@ object StateCheck {
|
||||
)
|
||||
}
|
||||
|
||||
// 74 切片 reducer:ClanChat(qnt / yv.qtg,3 字段;5 个动作)
|
||||
run {
|
||||
val S0 = ClanChatStateSlice()
|
||||
Check(
|
||||
"切片 ClanChat:默认关闭、无消息、无配置",
|
||||
!S0.Open && S0.Messages.isEmpty() && S0.Config == null
|
||||
)
|
||||
val S1 = ReduceClanChat(S0, OpenClanChat)
|
||||
Check("切片 ClanChat:OpenClanChat 打开", S1.Open)
|
||||
Check(
|
||||
"切片 ClanChat:CloseClanChat 关闭",
|
||||
!ReduceClanChat(S1, CloseClanChat).Open
|
||||
)
|
||||
val S2 = ReduceClanChat(S1, DoAddMessages(listOf("m1", "m2")))
|
||||
Check(
|
||||
"切片 ClanChat:DoAddMessages 追加消息",
|
||||
S2.Messages == listOf<Any?>("m1", "m2")
|
||||
)
|
||||
var S3 = S2
|
||||
for (I in 1..120) S3 = ReduceClanChat(S3, DoAddMessages(listOf("x$I")))
|
||||
Check(
|
||||
"切片 ClanChat:超过 100 条只保留最后 100",
|
||||
S3.Messages.size == 100 && S3.Messages.last() == "x120"
|
||||
)
|
||||
Check(
|
||||
"切片 ClanChat:Configure 写配置",
|
||||
ReduceClanChat(S1, Configure(emptyList(), emptyList(), false, "", null, null, "", 0, 0, false, null, ""))
|
||||
.Config != null
|
||||
)
|
||||
Check(
|
||||
"切片 ClanChat:ResetClanChat 整片复位",
|
||||
ReduceClanChat(S3, ResetClanChat) == ClanChatStateSlice()
|
||||
)
|
||||
Check(
|
||||
"切片 ClanChat:无关动作不改状态",
|
||||
ReduceClanChat(S3, AddFrags(1)) == S3
|
||||
)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, OpenClanChat)
|
||||
Check(
|
||||
"根:OpenClanChat 只动 clanChatState",
|
||||
Root1.ClanChatState.Open &&
|
||||
Root1.BattleSearchState == Root0.BattleSearchState
|
||||
)
|
||||
val W = RootWiring.ByField("clanChatState")!!
|
||||
Check(
|
||||
"根:clanChatState 委派到 qnt / yv.qtg 且 5 个动作",
|
||||
W.SliceClass == "qnt" && W.Reducer == "yv.qtg" &&
|
||||
W.Actions.toSet() == setOf(
|
||||
"OpenClanChat", "CloseClanChat", "Configure", "DoAddMessages",
|
||||
"ResetClanChat",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 75 切片 reducer:BattleSearch(Itt / Htt().vtg,5 字段;9 个动作)
|
||||
run {
|
||||
val Format = BattleFormat("fmt", "name", "desc", null, null)
|
||||
val S0 = BattleSearchStateSlice()
|
||||
Check(
|
||||
"切片 BattleSearch:默认值完整",
|
||||
S0.Filter == null && S0.SelectedFormat == null && S0.Search == null &&
|
||||
!S0.SuspiciousBattlesOnly && S0.SelectedBattleId == null
|
||||
)
|
||||
val S1 = ReduceBattleSearch(S0, SetFilter(true))
|
||||
Check("切片 BattleSearch:SetFilter 写过滤位", S1.Filter == true)
|
||||
val S2 = ReduceBattleSearch(S1, SetSearch("abc"))
|
||||
Check("切片 BattleSearch:SetSearch 写搜索串", S2.Search == "abc")
|
||||
Check(
|
||||
"切片 BattleSearch:SetSuspiciousFilter 写布尔",
|
||||
ReduceBattleSearch(S2, SetSuspiciousFilter(true)).SuspiciousBattlesOnly
|
||||
)
|
||||
Check(
|
||||
"切片 BattleSearch:EnterToBattle 清空搜索串",
|
||||
ReduceBattleSearch(S2, EnterToBattle(7L)).Search == null
|
||||
)
|
||||
Check(
|
||||
"切片 BattleSearch:SelectBattle / SelectBattleFormat",
|
||||
ReduceBattleSearch(S2, SelectBattle(7L)).SelectedBattleId == 7L &&
|
||||
ReduceBattleSearch(S2, SelectBattleFormat(Format)).SelectedFormat == Format
|
||||
)
|
||||
Check(
|
||||
"切片 BattleSearch:RemoveBattle 只清匹配的那条",
|
||||
ReduceBattleSearch(ReduceBattleSearch(S2, SelectBattle(7L)), RemoveBattle(7L))
|
||||
.SelectedBattleId == null &&
|
||||
ReduceBattleSearch(
|
||||
ReduceBattleSearch(S2, SelectBattle(7L)),
|
||||
RemoveBattle(8L),
|
||||
).SelectedBattleId == 7L
|
||||
)
|
||||
Check(
|
||||
"切片 BattleSearch:ClearSelectedBattle 清空选中",
|
||||
ReduceBattleSearch(S2, ClearSelectedBattle).SelectedBattleId == null
|
||||
)
|
||||
Check("切片 BattleSearch:Fight 不改状态", ReduceBattleSearch(S2, Fight(1L, BattleTeam.NONE)) == S2)
|
||||
Check(
|
||||
"切片 BattleSearch:无关动作不改状态",
|
||||
ReduceBattleSearch(S2, AddFrags(1)) == S2
|
||||
)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, SetSearch("q"))
|
||||
Check(
|
||||
"根:SetSearch 只动 battleSearchState",
|
||||
Root1.BattleSearchState.Search == "q" &&
|
||||
Root1.ClanChatState == Root0.ClanChatState
|
||||
)
|
||||
val W = RootWiring.ByField("battleSearchState")!!
|
||||
Check(
|
||||
"根:battleSearchState 委派到 Itt / Htt().vtg 且 9 个动作",
|
||||
W.SliceClass == "Itt" && W.Reducer == "Htt().vtg" && W.Actions.size == 9
|
||||
)
|
||||
}
|
||||
|
||||
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