feat(state): 迁移 battleUsers(复用 RemoteUserData/UserStat/TankInfoCC)
This commit is contained in:
1 parent
ddb3ef324b
commit
0ae39eebcd
8 files changed
+366
-26
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` 动作名。
|
||||
- 已迁移切片 **81/89**:
|
||||
- 已迁移切片 **82/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)
|
||||
@@ -409,12 +409,16 @@
|
||||
`SwapTeam` 换队并把该战斗内用户分数归零;`RemoveBattle` / `RemoveUser` 清对应的四张子表;
|
||||
其余为名字 / 可疑度 / 队伍分 / 个人分 / 资金 / 奖励上限 / 观战标记。
|
||||
模型全部复用生成物:`BattleParams` / `BattleInfoUser` / `BattleCreateParameters` / `ProBattleRewardLimitData`。
|
||||
- `battleUsers` → `uP` / `sr.hqs`(`BattleUsersReducer.kt`):13 字段,18 个分支。
|
||||
用户加入时同时写 onlineUsers / uids / ranks / clanTags / usersPremium / teams / stats;
|
||||
stats 值是生成物 `UserStat`(deaths / killScore / kills / score / user);
|
||||
坦克信息与抗性复用 `TankInfoCC` / `TankResistance`;`sP`(旧队伍枚举迁移)按 no-op 收口。
|
||||
- `launchParams` → `(pass-through)`:原根 reducer 对 `hpx_1` 没有调用,缺省是 `ag()` 空 Map;
|
||||
`RootState.LaunchParams` 收口为 `LaunchParamsStateSlice = Map<String, String>`,不新增 reducer/动作。
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 80 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **8 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 81/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **888 项全绿**,含 89 槽位完整性、80 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 81 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **7 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 82/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **902 项全绿**,含 89 槽位完整性、81 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generatedAt": "2026-10-24T12:57:54.249Z",
|
||||
"generatedAt": "2026-10-24T13:07:20.497Z",
|
||||
"module": "module_10032.js",
|
||||
"RootState": {
|
||||
"Class": "z6",
|
||||
@@ -87,7 +87,8 @@
|
||||
"battleChat",
|
||||
"remoteUserDataStorage",
|
||||
"matchmaking",
|
||||
"battlesSelect"
|
||||
"battlesSelect",
|
||||
"battleUsers"
|
||||
],
|
||||
"AnonymousActions": [
|
||||
{
|
||||
@@ -1445,6 +1446,42 @@
|
||||
"Name": "ResetBattlesSelect",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "new fA() 整片复位"
|
||||
},
|
||||
{
|
||||
"Local": "oP",
|
||||
"Name": "ResetBattleUsers",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "new uP() 整片复位"
|
||||
},
|
||||
{
|
||||
"Local": "_P",
|
||||
"Name": "AddBattleUser",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "单个用户写 onlineUsers / uids / ranks / clanTags / usersPremium / teams / stats"
|
||||
},
|
||||
{
|
||||
"Local": "hP",
|
||||
"Name": "AddBattleUsers",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "批量用户同上(循环调用 `_P` 的逻辑)"
|
||||
},
|
||||
{
|
||||
"Local": "qP",
|
||||
"Name": "RemoveOnlineUser",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "onlineUsers -= userId(`n.hqr(Jg(n.iqa_1, t.gqs_1))`)"
|
||||
},
|
||||
{
|
||||
"Local": "lP",
|
||||
"Name": "SetUserPremium",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "usersPremium[userId](`cg(n.mqa_1, Vd(t.iqs_1, t.jqs_1))`)"
|
||||
},
|
||||
{
|
||||
"Local": "sP",
|
||||
"Name": "MigrateBattleUserTeams",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "旧队伍枚举迁移(`qm/bm/em` 映射),离线重建按 no-op 收口"
|
||||
}
|
||||
],
|
||||
"Markers": [
|
||||
@@ -2310,18 +2347,18 @@
|
||||
"Reducer": "sr.hqs",
|
||||
"Delegate": "sr.hqs(t, n.hpw_1)",
|
||||
"Actions": [
|
||||
"?_P",
|
||||
"?hP",
|
||||
"?lP",
|
||||
"?oP",
|
||||
"?qP",
|
||||
"?sP",
|
||||
"AddBattleUser",
|
||||
"AddBattleUsers",
|
||||
"InitSuspiciousState",
|
||||
"InitUserLevels",
|
||||
"MigrateBattleUserTeams",
|
||||
"RemoveOnlineUser",
|
||||
"RemoveTankInfo",
|
||||
"ResetBattleUsers",
|
||||
"SetGearScore",
|
||||
"SetTankInfo",
|
||||
"SetTankResistance",
|
||||
"SetUserPremium",
|
||||
"UpdateUserLevel",
|
||||
"UpdateUserRank",
|
||||
"UpdateUserScoreKillsAndDeaths",
|
||||
@@ -2330,7 +2367,7 @@
|
||||
"UpdateUsersScoreKillsAndDeaths"
|
||||
],
|
||||
"Default": "new uP()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "suppliesState",
|
||||
|
||||
@@ -330,6 +330,13 @@ const AnonymousActionNames = new Map([
|
||||
// battlesSelect 切片(fA / MA.vqk):gA/dA 没有 toString。
|
||||
['gA', 'MarkBattlesLoaded'],
|
||||
['dA', 'ResetBattlesSelect'],
|
||||
// battleUsers 切片(uP / yP.hqs):oP/_P/hP/qP/lP/sP 没有 toString。
|
||||
['oP', 'ResetBattleUsers'],
|
||||
['_P', 'AddBattleUser'],
|
||||
['hP', 'AddBattleUsers'],
|
||||
['qP', 'RemoveOnlineUser'],
|
||||
['lP', 'SetUserPremium'],
|
||||
['sP', 'MigrateBattleUserTeams'],
|
||||
]);
|
||||
|
||||
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
||||
@@ -815,6 +822,7 @@ const Migrated = {
|
||||
},
|
||||
matchmaking: { Type: 'MatchmakingStateSlice', Reduce: 'ReduceMatchmaking' },
|
||||
battlesSelect: { Type: 'BattlesSelectStateSlice', Reduce: 'ReduceBattlesSelect' },
|
||||
battleUsers: { Type: 'BattleUsersStateSlice', Reduce: 'ReduceBattleUsers' },
|
||||
};
|
||||
|
||||
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
||||
@@ -1232,6 +1240,12 @@ const AppSettingsAnonymousEffects = {
|
||||
nW: 'startLoadingBattle=false(`n.brw(cd, cd, cd, cd, !1)`)',
|
||||
gA: 'loaded=true(`n.hqj(!0)`)',
|
||||
dA: 'new fA() 整片复位',
|
||||
oP: 'new uP() 整片复位',
|
||||
_P: '单个用户写 onlineUsers / uids / ranks / clanTags / usersPremium / teams / stats',
|
||||
hP: '批量用户同上(循环调用 `_P` 的逻辑)',
|
||||
qP: 'onlineUsers -= userId(`n.hqr(Jg(n.iqa_1, t.gqs_1))`)',
|
||||
lP: 'usersPremium[userId](`cg(n.mqa_1, Vd(t.iqs_1, t.jqs_1))`)',
|
||||
sP: '旧队伍枚举迁移(`qm/bm/em` 映射),离线重建按 no-op 收口',
|
||||
};
|
||||
fs.writeFileSync(
|
||||
path.join(P, 'names', 'root_wiring.json'),
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
// BattleUsersReducer.kt —— 战斗内用户表切片(对应 module_10032 的 uP 状态 + yP.hqs)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 uP:13 个字段,toString 名 "BattleUsers(…)";copy 是 hqr(13 字段 + 回调)。
|
||||
// 根委派:`sr.hqs(t, n.hpw_1)`。
|
||||
// reducer(18 个实例臂):
|
||||
// oP(无 toString) → `new uP()` 整片复位
|
||||
// _P / hP(无 toString) → 单个 / 批量把用户写进 onlineUsers / uids / ranks /
|
||||
// clanTags / usersPremium / teams / stats
|
||||
// aP(UpdateUserRank) → ranks[id]
|
||||
// cP(UpdateUsersClanTag) → clanTags 合并
|
||||
// dP / gP(UpdateUserScoreKillsAndDeaths / …Users…)→ stats[id] = userStat
|
||||
// mP(SetGearScore) → gearScores[user]
|
||||
// bP(SetTankResistance) → tankResistance[user]
|
||||
// qP(无 toString) → onlineUsers -= userId
|
||||
// lP(无 toString) → usersPremium[userId]
|
||||
// fP(UpdateUserSuspiciousState)→ suspiciousUsers / suspiciousByIpUsers 按开关增删
|
||||
// vP(InitSuspiciousState) → 两个集合整体替换
|
||||
// sP(无 toString) → 队伍枚举迁移(原 `qm/bm/em` 映射):离线重建按 no-op 收口
|
||||
// pP(InitUserLevels) → tankLevels 合并
|
||||
// wP(UpdateUserLevel) → tankLevels[userId]
|
||||
// kP(SetTankInfo) → tankInfo[user]
|
||||
// zP(RemoveTankInfo) → tankInfo -= user
|
||||
//
|
||||
// 用户模型复用生成物 `RemoteUserData`(userId / uid / rank / hasPremium / clanTag / …);
|
||||
// 坦克信息与抗性复用 `TankInfoCC` / `TankResistance`。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.InitSuspiciousState
|
||||
import App.State.InitUserLevels
|
||||
import App.State.RemoteUserData
|
||||
import App.State.SetGearScore
|
||||
import App.State.RemoveTankInfo
|
||||
import App.State.SetTankInfo
|
||||
import App.State.SetTankResistance
|
||||
import App.State.TankInfoCC
|
||||
import App.State.TankResistance
|
||||
import App.State.UpdateUserLevel
|
||||
import App.State.UpdateUserRank
|
||||
import App.State.UpdateUserScoreKillsAndDeaths
|
||||
import App.State.UpdateUserSuspiciousState
|
||||
import App.State.UpdateUsersClanTag
|
||||
import App.State.UpdateUsersScoreKillsAndDeaths
|
||||
import App.State.UserStat
|
||||
|
||||
/* ------------------------------------------------------------------ 匿名动作 */
|
||||
|
||||
/** 原 `oP`:整片复位(`new uP()`)。 */
|
||||
object ResetBattleUsers
|
||||
|
||||
/** 原 `_P`:加入一个战斗用户。 */
|
||||
data class AddBattleUser(val user: RemoteUserData, val team: Any?)
|
||||
|
||||
/** 原 `hP`:批量加入战斗用户。 */
|
||||
data class AddBattleUsers(val users: List<Any?>, val team: Any?)
|
||||
|
||||
/** 原 `qP`:把用户从在线列表移除。 */
|
||||
data class RemoveOnlineUser(val userId: Any?)
|
||||
|
||||
/** 原 `lP`:写用户的会员标记。 */
|
||||
data class SetUserPremium(val userId: Any?, val premium: Any?)
|
||||
|
||||
/** 原 `sP`:旧队伍枚举迁移(离线重建按 no-op)。 */
|
||||
object MigrateBattleUserTeams
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class BattleUsersStateSlice(
|
||||
val OnlineUsers: Set<Any?> = emptySet(),
|
||||
val Uids: Map<Any?, Any?> = emptyMap(),
|
||||
val Ranks: Map<Any?, Any?> = emptyMap(),
|
||||
val ClanTags: Map<Any?, Any?> = emptyMap(),
|
||||
val UsersPremium: Map<Any?, Any?> = emptyMap(),
|
||||
val Teams: Map<Any?, Any?> = emptyMap(),
|
||||
val Stats: Map<Any?, Any?> = emptyMap(),
|
||||
val GearScores: Map<Any?, Any?> = emptyMap(),
|
||||
val TankInfo: Map<Any?, Any?> = emptyMap(),
|
||||
val TankResistance: Map<Any?, Any?> = emptyMap(),
|
||||
val TankLevels: Map<Any?, Any?> = emptyMap(),
|
||||
val SuspiciousUsers: Set<Any?> = emptySet(),
|
||||
val SuspiciousByIpUsers: Set<Any?> = emptySet(),
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
private fun ApplyUser(
|
||||
State0: BattleUsersStateSlice,
|
||||
User: RemoteUserData,
|
||||
Team: Any?,
|
||||
): BattleUsersStateSlice {
|
||||
val Id = User.userId
|
||||
return State0.copy(
|
||||
OnlineUsers = State0.OnlineUsers + Id,
|
||||
Uids = State0.Uids + (Id to User.uid),
|
||||
Ranks = State0.Ranks + (Id to User.rank),
|
||||
ClanTags = State0.ClanTags + (Id to User.clanTag),
|
||||
UsersPremium = State0.UsersPremium + (Id to User.hasPremium),
|
||||
Teams = State0.Teams + (Id to Team),
|
||||
Stats = State0.Stats + (Id to User),
|
||||
)
|
||||
}
|
||||
|
||||
fun ReduceBattleUsers(
|
||||
State0: BattleUsersStateSlice,
|
||||
Action: Any,
|
||||
): BattleUsersStateSlice = when (Action) {
|
||||
is ResetBattleUsers -> BattleUsersStateSlice()
|
||||
is AddBattleUser -> ApplyUser(State0, Action.user, Action.team)
|
||||
is AddBattleUsers -> {
|
||||
var Result = State0
|
||||
for (Item in Action.users) {
|
||||
val User = Item as? RemoteUserData ?: continue
|
||||
Result = ApplyUser(Result, User, Action.team)
|
||||
}
|
||||
Result
|
||||
}
|
||||
is UpdateUserRank -> State0.copy(Ranks = State0.Ranks + (Action.id to Action.rank))
|
||||
is UpdateUsersClanTag -> {
|
||||
val Incoming = Action.clans as? Map<Any?, Any?> ?: emptyMap()
|
||||
State0.copy(ClanTags = State0.ClanTags + Incoming)
|
||||
}
|
||||
is UpdateUserScoreKillsAndDeaths ->
|
||||
State0.copy(Stats = State0.Stats + (Action.userStat.user to Action.userStat))
|
||||
is UpdateUsersScoreKillsAndDeaths -> {
|
||||
var Stats = State0.Stats
|
||||
for (Item in (Action.userScores as? Iterable<*> ?: emptyList<Any?>())) {
|
||||
val Stat = Item as? UserStat ?: continue
|
||||
Stats = Stats + (Stat.user to Stat)
|
||||
}
|
||||
State0.copy(Stats = Stats)
|
||||
}
|
||||
is SetGearScore -> State0.copy(GearScores = State0.GearScores + (Action.user to Action.score))
|
||||
is SetTankResistance -> State0.copy(
|
||||
TankResistance = State0.TankResistance + (Action.user to Action.tankResistance),
|
||||
)
|
||||
is RemoveOnlineUser -> State0.copy(OnlineUsers = State0.OnlineUsers - Action.userId)
|
||||
is SetUserPremium -> State0.copy(
|
||||
UsersPremium = State0.UsersPremium + (Action.userId to Action.premium),
|
||||
)
|
||||
is UpdateUserSuspiciousState -> State0.copy(
|
||||
SuspiciousUsers =
|
||||
if (Action.suspicious == true) State0.SuspiciousUsers + Action.id
|
||||
else State0.SuspiciousUsers - Action.id,
|
||||
SuspiciousByIpUsers =
|
||||
if (Action.suspiciousByIp == true) State0.SuspiciousByIpUsers + Action.id
|
||||
else State0.SuspiciousByIpUsers - Action.id,
|
||||
)
|
||||
is InitSuspiciousState -> State0.copy(
|
||||
SuspiciousUsers = (Action.suspiciousUserIds as? Iterable<*>)?.toSet() ?: emptySet(),
|
||||
SuspiciousByIpUsers =
|
||||
(Action.suspiciousByIpUserIds as? Iterable<*>)?.toSet() ?: emptySet(),
|
||||
)
|
||||
is MigrateBattleUserTeams -> State0
|
||||
is InitUserLevels -> {
|
||||
val Incoming = (Action.levels as? Map<Any?, Any?>) ?: emptyMap()
|
||||
State0.copy(TankLevels = State0.TankLevels + Incoming)
|
||||
}
|
||||
is UpdateUserLevel -> State0.copy(
|
||||
TankLevels = State0.TankLevels + (Action.userId to Action.level),
|
||||
)
|
||||
is SetTankInfo -> State0.copy(TankInfo = State0.TankInfo + (Action.user to Action.info))
|
||||
is RemoveTankInfo -> State0.copy(TankInfo = State0.TankInfo - Action.user)
|
||||
else -> State0
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// RootReducer.kt —— 根 reducer 骨架(对应 module_10032 的根状态 z6 / TOState 与根 reducer k6)
|
||||
//
|
||||
// 原包 k6 对 89 个切片逐个调用各自的 reducer,再 `return n.cti(...)`(copy 出新状态)。
|
||||
// 这里采用同一形状。已迁移的 81 个切片里,80 个真正调用 reducer,launchParams 只做类型收口:
|
||||
// 这里采用同一形状。已迁移的 82 个切片里,81 个真正调用 reducer,launchParams 只做类型收口:
|
||||
//
|
||||
// inviteState → ReduceInvite(aD / pD.er5)
|
||||
// loginByPassword → ReduceLoginByPassword(gD / MD.cr6)
|
||||
@@ -83,9 +83,10 @@
|
||||
// remoteUserDataStorage → ReduceRemoteUserDataStorage($Q / vh.isl,根委派 `vh.isl(t, n.zpv_1)`)
|
||||
// matchmaking → ReduceMatchmaking(TH / JH().qrx,根委派 `JH().qrx(t, n.cpw_1)`)
|
||||
// battlesSelect → ReduceBattlesSelect(fA / Mi.vqk,根委派 `Mi.vqk(t, n.apw_1)`)
|
||||
// battleUsers → ReduceBattleUsers(uP / sr.hqs,根委派 `sr.hqs(t, n.hpw_1)`)
|
||||
// launchParams → 无 reducer(原根 reducer 原样透传;默认 `ag()` = emptyMap())
|
||||
//
|
||||
// 其余 8 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 其余 7 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
||||
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
||||
package App.State
|
||||
@@ -102,6 +103,7 @@ import App.State.Reducers.ReduceBattlesSelect
|
||||
import App.State.Reducers.ReduceBattleSettings
|
||||
import App.State.Reducers.ReduceBattleStatistics
|
||||
import App.State.Reducers.ReduceBattleTutorial
|
||||
import App.State.Reducers.ReduceBattleUsers
|
||||
import App.State.Reducers.ReduceBattleView
|
||||
import App.State.Reducers.ReduceBattleInvite
|
||||
import App.State.Reducers.ReduceCaptcha
|
||||
@@ -264,6 +266,7 @@ object RootReducer {
|
||||
RemoteUserDataStorage = ReduceRemoteUserDataStorage(State0.RemoteUserDataStorage, Action),
|
||||
Matchmaking = ReduceMatchmaking(State0.Matchmaking, Action),
|
||||
BattlesSelect = ReduceBattlesSelect(State0.BattlesSelect, Action),
|
||||
BattleUsers = ReduceBattleUsers(State0.BattleUsers, Action),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import App.State.Reducers.BattleSearchStateSlice
|
||||
import App.State.Reducers.BattleSettingsStateSlice
|
||||
import App.State.Reducers.BattleStatisticsStateSlice
|
||||
import App.State.Reducers.BattleTutorialStateSlice
|
||||
import App.State.Reducers.BattleUsersStateSlice
|
||||
import App.State.Reducers.BattleViewStateSlice
|
||||
import App.State.Reducers.BattlesSelectStateSlice
|
||||
import App.State.Reducers.CaptchaStateSlice
|
||||
@@ -159,8 +160,8 @@ data class RootState(
|
||||
val LobbyLoader: LobbyLoaderStateSlice = LobbyLoaderStateSlice(),
|
||||
/** 原 battleResult(sR / Fi.aqp)。已迁移。 */
|
||||
val BattleResult: BattleResultStateSlice = BattleResultStateSlice(),
|
||||
/** 原 battleUsers(uP / sr.hqs)。未迁移:原样透传。 */
|
||||
val BattleUsers: Any? = null,
|
||||
/** 原 battleUsers(uP / sr.hqs)。已迁移。 */
|
||||
val BattleUsers: BattleUsersStateSlice = BattleUsersStateSlice(),
|
||||
/** 原 suppliesState(wE / $t.fq9)。已迁移。 */
|
||||
val SuppliesState: SuppliesStateSlice = SuppliesStateSlice(),
|
||||
/** 原 matchmakingGroup(rW / NW().is0)。未迁移:原样透传。 */
|
||||
|
||||
@@ -49,7 +49,7 @@ object RootWiring {
|
||||
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")),
|
||||
SliceWiring("battleUsers", "hpw_1", "uP", "sr.hqs", "sr.hqs(t, n.hpw_1)", listOf("AddBattleUser", "AddBattleUsers", "InitSuspiciousState", "InitUserLevels", "MigrateBattleUserTeams", "RemoveOnlineUser", "RemoveTankInfo", "ResetBattleUsers", "SetGearScore", "SetTankInfo", "SetTankResistance", "SetUserPremium", "UpdateUserLevel", "UpdateUserRank", "UpdateUserScoreKillsAndDeaths", "UpdateUserSuspiciousState", "UpdateUsersClanTag", "UpdateUsersScoreKillsAndDeaths")),
|
||||
SliceWiring("suppliesState", "ipw_1", "wE", "\$t.fq9", "\$t.fq9(t, n.ipw_1)", listOf("SetSupplyCount")),
|
||||
SliceWiring("matchmakingGroup", "jpw_1", "rW", "NW().is0", "NW().is0(t, n.jpw_1)", listOf("?zW", "AcceptedInviteToGroup", "AddUser", "AddUserToSelected", "InitMatchmakingGroup", "Invite", "RejectedInviteToGroup", "RemoveUserToSelected", "SetAllowedFromFriends", "SetSelectedUsers", "UpdateMountItems", "UpdateUserReadiness", "UserRemoved")),
|
||||
SliceWiring("shop", "kpw_1", "j4", "(inline@shop)", "(function (t, n) { var i; if (t instanceof w4) i = n.qt6(cd, cd, cd, cd, cd, cd, cd, t.lt6_1); else if (t instanceof Yut) i = n.qt6(cd, cd, cd, cd, !0); else if (t instanceof F5) i = new j4(cd, cd, cd, cd, cd, cd, cd, n.qq3_1); else if (t instanceof h4) i = n.qt6(cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, t.st5_1); else if (t instanceof c4) i = n.qt6(cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, cd, t.ut5_1); else if (t instanceof u4) i = n.qt6( cd, cd, cd, cd, cd, cd, …", listOf("?x4", "AddCategoriesWithBonus", "AddItemToOrderProcessing", "BlockBackButton", "BraintreeLoadingInterrupt", "ClearPreviousScreen", "ClearTargetCategory", "ClearTargetProductId", "CurrentPayMode", "DeleteOneTimePurchaseItem", "InitAdditionalDescription", "InitAmountString", "InitCategory", "InitCoinPackage", "InitCompensation", "InitCrystalKitPackage", "InitFeatureItem", "InitGroup", "InitItemViewType", "InitKeysPackage", "InitKitBundle", "InitKitPackage", "InitLootBoxAndPaint", "InitOneTimePurchaseItem", "InitPayModeAction", "InitPaymentModeAsShopItem", "InitPaymentProviderItems", "InitPaymentViewType", "InitRestrictionByPayMode", "InitRewardedVideosBlocks", "InitShopCard", "InitShopCardDiscount", "InitShopCardView", "InitShopItem", "InitShopItemName", "InitSingleItemKit", "InitSpecialKitPackage", "MobilePaymentStateChanged", "PaymentProviderFinishFail", "PaymentProviderFinishSuccess", "PaymentProviderInProgress", "PaymentUrlReceiveFailed", "PaymentUrlReceived", "RemoveDiscountItemForItem", "RemoveItemFromOrderProcessing", "ResetPaymentState", "ResetShop", "SavePreviousScreen", "SaveTargetProductId", "SaveTargetVisitedCategory", "SelectCategory", "SelectCategoryId", "SelectItem", "SetBraintreeToken", "SetCoinPaymentProviderUrl", "SetGoToHomeAfterBuy", "SetInitShopItemId", "SetPurchaseCompleted", "SetStripeIntentParams", "SetupDiscountCategoryByItem", "SetupDiscountItem", "SetupDiscountItemForItem", "ShopCardExpired", "ShopCardRemoved", "ShopCardSold", "ShopLoaded", "ToggleShopActivity", "TryToBuyOneTimePurchase", "UnblockBackButton")),
|
||||
@@ -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")
|
||||
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")
|
||||
|
||||
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
||||
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;
|
||||
// BattlePause / BattleView / TankActionsLog / SuppliesTutorial / ClanChat / BattleSearch / BattleStatistics / SoundSettings / GameSettings / KeyboardSettings / TouchscreenHudSettings / GraphicsSettings / ControlSettings / BattleSettings / ContractState / TankBuilder / BattleMessage / Maps / BattleChat / RemoteUserDataStorage / Matchmaking / BattlesSelect / BattleUsers;
|
||||
// ㉑ launchParams 是纯透传切片(无 reducer/动作),只做 Map 类型收口;⑭ 根 reducer 的 89 槽位委派
|
||||
//
|
||||
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
||||
@@ -791,6 +791,29 @@ import App.State.Reducers.BattlesSelectStateSlice
|
||||
import App.State.Reducers.MarkBattlesLoaded
|
||||
import App.State.Reducers.ReduceBattlesSelect
|
||||
import App.State.Reducers.ResetBattlesSelect
|
||||
import App.State.InitSuspiciousState
|
||||
import App.State.InitUserLevels
|
||||
import App.State.SetGearScore
|
||||
import App.State.SetTankInfo
|
||||
import App.State.SetTankResistance
|
||||
import App.State.TankInfoCC
|
||||
import App.State.TankResistance
|
||||
import App.State.UpdateUserLevel
|
||||
import App.State.UpdateUserRank
|
||||
import App.State.UpdateUserScoreKillsAndDeaths
|
||||
import App.State.UpdateUserSuspiciousState
|
||||
import App.State.UpdateUsersClanTag
|
||||
import App.State.UpdateUsersScoreKillsAndDeaths
|
||||
import App.State.Reducers.AddBattleUser
|
||||
import App.State.Reducers.AddBattleUsers
|
||||
import App.State.Reducers.BattleUsersStateSlice
|
||||
import App.State.Reducers.MigrateBattleUserTeams
|
||||
import App.State.Reducers.ReduceBattleUsers
|
||||
import App.State.Reducers.RemoveOnlineUser
|
||||
import App.State.Reducers.ResetBattleUsers
|
||||
import App.State.Reducers.SetUserPremium
|
||||
import App.State.RemoveTankInfo
|
||||
import App.State.UserStat
|
||||
import App.State.Reducers.UserRankBounds
|
||||
import App.State.Reducers.UserStateSlice
|
||||
import App.State.Reducers.ClearHullData
|
||||
@@ -1218,7 +1241,7 @@ object StateCheck {
|
||||
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
||||
}
|
||||
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 81 个已迁移切片(80 归约 + launchParams 透传)
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 82 个已迁移切片(81 归约 + launchParams 透传)
|
||||
run {
|
||||
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
||||
Check(
|
||||
@@ -1282,7 +1305,7 @@ object StateCheck {
|
||||
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
||||
)
|
||||
Check(
|
||||
"根:迁移表 = 81 个已迁移字段,其余 8 个待迁",
|
||||
"根:迁移表 = 82 个已迁移字段,其余 7 个待迁",
|
||||
RootReducer.Migrated ==
|
||||
setOf(
|
||||
"inviteState", "loginByPassword", "twitchState", "home",
|
||||
@@ -1306,9 +1329,9 @@ object StateCheck {
|
||||
"soundSettings", "gameSettings", "keyboardSettings", "touchscreenHudSettings",
|
||||
"graphicsSettings", "controlSettings", "battleSettings", "contractState",
|
||||
"tankBuilderState", "battleMessage", "maps", "battleChat",
|
||||
"remoteUserDataStorage", "matchmaking", "battlesSelect",
|
||||
"remoteUserDataStorage", "matchmaking", "battlesSelect", "battleUsers",
|
||||
) &&
|
||||
RootWiring.Unmigrated.size == 8
|
||||
RootWiring.Unmigrated.size == 7
|
||||
)
|
||||
|
||||
// 一次 ReduceRoot 里多个切片各归约自己的动作,互不串片
|
||||
@@ -1364,7 +1387,7 @@ object StateCheck {
|
||||
S5.User.Uid == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
||||
)
|
||||
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 81/89")
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 82/89")
|
||||
|
||||
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
||||
Store.Dispatch(SetStatus("LOGGING_IN"))
|
||||
@@ -6797,6 +6820,100 @@ object StateCheck {
|
||||
)
|
||||
}
|
||||
|
||||
// 92 切片 reducer:BattleUsers(uP / sr.hqs,13 字段;18 个动作)
|
||||
run {
|
||||
fun User(Id: Long): RemoteUserData = RemoteUserData(
|
||||
userId = Id, uid = "u$Id", rank = 5, hasPremium = true,
|
||||
clanTag = "T", onlineStatus = "online", battle = null,
|
||||
)
|
||||
val TankInfo = TankInfoCC(1L, null, 2L, 3L, null, 4L)
|
||||
val Resistance = TankResistance(10, "fire")
|
||||
|
||||
val S0 = BattleUsersStateSlice()
|
||||
Check("切片 BattleUsers:默认值完整", S0.OnlineUsers.isEmpty() && S0.Stats.isEmpty())
|
||||
val S1 = ReduceBattleUsers(S0, AddBattleUser(User(1L), "RED"))
|
||||
Check(
|
||||
"切片 BattleUsers:AddBattleUser 写七张表",
|
||||
S1.OnlineUsers == setOf<Any?>(1L) && S1.Uids[1L] == "u1" &&
|
||||
S1.Ranks[1L] == 5 && S1.ClanTags[1L] == "T" &&
|
||||
S1.UsersPremium[1L] == true && S1.Teams[1L] == "RED" &&
|
||||
S1.Stats[1L] == User(1L)
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:AddBattleUsers 批量加入",
|
||||
ReduceBattleUsers(S1, AddBattleUsers(listOf(User(2L), User(3L)), "BLUE"))
|
||||
.OnlineUsers == setOf<Any?>(1L, 2L, 3L)
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:UpdateUserRank / UpdateUsersClanTag",
|
||||
ReduceBattleUsers(S1, UpdateUserRank(1L, 9)).Ranks[1L] == 9 &&
|
||||
ReduceBattleUsers(S1, UpdateUsersClanTag(mapOf(1L to "X")))
|
||||
.ClanTags[1L] == "X"
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:两种 stats 写入",
|
||||
ReduceBattleUsers(S1, UpdateUserScoreKillsAndDeaths(UserStat(0, 0, 0, 0, 4L)))
|
||||
.Stats[4L] == UserStat(0, 0, 0, 0, 4L) &&
|
||||
ReduceBattleUsers(S1, UpdateUsersScoreKillsAndDeaths(listOf(UserStat(0, 0, 0, 0, 5L))))
|
||||
.Stats[5L] == UserStat(0, 0, 0, 0, 5L)
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:SetGearScore / SetTankResistance",
|
||||
ReduceBattleUsers(S1, SetGearScore(1L, 100)).GearScores[1L] == 100 &&
|
||||
ReduceBattleUsers(S1, SetTankResistance(1L, listOf(Resistance)))
|
||||
.TankResistance[1L] == listOf(Resistance)
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:RemoveOnlineUser / SetUserPremium",
|
||||
ReduceBattleUsers(S1, RemoveOnlineUser(1L)).OnlineUsers.isEmpty() &&
|
||||
ReduceBattleUsers(S1, SetUserPremium(1L, false)).UsersPremium[1L] == false
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:可疑用户开关与整体替换",
|
||||
ReduceBattleUsers(S1, UpdateUserSuspiciousState(1L, true, false))
|
||||
.let { it.SuspiciousUsers == setOf<Any?>(1L) && it.SuspiciousByIpUsers.isEmpty() } &&
|
||||
ReduceBattleUsers(S1, InitSuspiciousState(listOf(2L), listOf(3L)))
|
||||
.let {
|
||||
it.SuspiciousUsers == setOf<Any?>(2L) &&
|
||||
it.SuspiciousByIpUsers == setOf<Any?>(3L)
|
||||
}
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:等级两臂",
|
||||
ReduceBattleUsers(S1, InitUserLevels(mapOf(1L to 3))).TankLevels[1L] == 3 &&
|
||||
ReduceBattleUsers(S1, UpdateUserLevel(1L, 4)).TankLevels[1L] == 4
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:坦克信息写入与移除",
|
||||
ReduceBattleUsers(S1, SetTankInfo(1L, TankInfo)).TankInfo[1L] == TankInfo &&
|
||||
ReduceBattleUsers(S1, SetTankInfo(1L, TankInfo)).let {
|
||||
ReduceBattleUsers(it, RemoveTankInfo(1L)).TankInfo.isEmpty()
|
||||
}
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:枚举迁移是 no-op、复位清空",
|
||||
ReduceBattleUsers(S1, MigrateBattleUserTeams) == S1 &&
|
||||
ReduceBattleUsers(S1, ResetBattleUsers) == BattleUsersStateSlice()
|
||||
)
|
||||
Check(
|
||||
"切片 BattleUsers:无关动作不改状态",
|
||||
ReduceBattleUsers(S1, AddFrags(1)) == S1
|
||||
)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, AddBattleUser(User(7L), "RED"))
|
||||
Check(
|
||||
"根:AddBattleUser 只动 battleUsers",
|
||||
Root1.BattleUsers.OnlineUsers == setOf<Any?>(7L) &&
|
||||
Root1.BattlesSelect == Root0.BattlesSelect
|
||||
)
|
||||
val W = RootWiring.ByField("battleUsers")!!
|
||||
Check(
|
||||
"根:battleUsers 委派到 uP / sr.hqs 且 18 个动作",
|
||||
W.SliceClass == "uP" && W.Reducer == "sr.hqs" && W.Actions.size == 18
|
||||
)
|
||||
}
|
||||
|
||||
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