feat(state): 迁移 clansStorage(复用 ClanInfo 模型)
This commit is contained in:
1 parent
25f8cd431e
commit
ad5686241d
8 files changed
+310
-24
No files matched your search
@@ -143,7 +143,7 @@
|
|||||||
`names/root_wiring.json` + `TankiOffline/.../App/State/RootState.kt`、`RootWiring.kt`。
|
`names/root_wiring.json` + `TankiOffline/.../App/State/RootState.kt`、`RootWiring.kt`。
|
||||||
- 根状态 `z6`(`TOState`)的 **89 个槽位**全部入表;字段顺序取 `toString`,槽位取构造函数 `<名>_1`。
|
- 根状态 `z6`(`TOState`)的 **89 个槽位**全部入表;字段顺序取 `toString`,槽位取构造函数 `<名>_1`。
|
||||||
- 根 reducer `k6` 的逐切片委派记全:reducer 引用、委派表达式、顶层 `instanceof` 动作名。
|
- 根 reducer `k6` 的逐切片委派记全:reducer 引用、委派表达式、顶层 `instanceof` 动作名。
|
||||||
- 已迁移切片 **83/89**:
|
- 已迁移切片 **84/89**:
|
||||||
- `inviteState` → `aD` / `pD.er5`(`InviteReducer.kt`)
|
- `inviteState` → `aD` / `pD.er5`(`InviteReducer.kt`)
|
||||||
- `loginByPassword` → `gD` / `MD.cr6`(`LoginReducer.kt`,含 `SetLogin`/`SetPassword` 把 status 打回 `NONE` 的原语义)
|
- `loginByPassword` → `gD` / `MD.cr6`(`LoginReducer.kt`,含 `SetLogin`/`SetPassword` 把 status 打回 `NONE` 的原语义)
|
||||||
- `twitchState` → `g9` / `y9.gta`(`TwitchReducer.kt`;`SetAccount` 是 Twitch 账号,不是 UID)
|
- `twitchState` → `g9` / `y9.gta`(`TwitchReducer.kt`;`SetAccount` 是 Twitch 账号,不是 UID)
|
||||||
@@ -418,12 +418,19 @@
|
|||||||
`SetBattlePass(flavor)` 追加一个 `Challenge` 战令条目,两个「已领取索引」动作按 flavor 命中后 copy;
|
`SetBattlePass(flavor)` 追加一个 `Challenge` 战令条目,两个「已领取索引」动作按 flavor 命中后 copy;
|
||||||
`SetRewardForDialog` / `LZ` 依赖 `FZ`/`GZ` 构造与外部刷新,纯 reducer 里按 no-op 收口。
|
`SetRewardForDialog` / `LZ` 依赖 `FZ`/`GZ` 构造与外部刷新,纯 reducer 里按 no-op 收口。
|
||||||
`Challenge` 直接复用生成物模型(9 字段)。
|
`Challenge` 直接复用生成物模型(9 字段)。
|
||||||
|
- `clansStorage` → `lO` / `me.vr1`(`ClanStorageReducer.kt`):3 字段,13 个分支。
|
||||||
|
列表项复用生成物 `ClanInfo`(16 字段);各分支都是对 `ClanInfo` 的 copy:
|
||||||
|
`MinimalRankChanged`(第 5 参) / `RecruitmentChanged`(第 6 参) / 成员与待审用户(第 9/16 参) /
|
||||||
|
`UpdateClan`(name/tag/description) / `BuyAdditionalPlace`(maxMembers+1)。
|
||||||
|
`vO`(原名 `ClanLoaded`,与 clan 切片的 `isLoaded` 同名)改名 `LoadClanIntoStorage`;
|
||||||
|
`dO`/`gO`(原名 `AddUser`/`RemoveUser`,与战斗列表同名)改名 `AddClanUser`/`RemoveClanUser`;
|
||||||
|
查找时兼容 Int/Long 两种 clanId。
|
||||||
- `launchParams` → `(pass-through)`:原根 reducer 对 `hpx_1` 没有调用,缺省是 `ag()` 空 Map;
|
- `launchParams` → `(pass-through)`:原根 reducer 对 `hpx_1` 没有调用,缺省是 `ag()` 空 Map;
|
||||||
`RootState.LaunchParams` 收口为 `LaunchParamsStateSlice = Map<String, String>`,不新增 reducer/动作。
|
`RootState.LaunchParams` 收口为 `LaunchParamsStateSlice = Map<String, String>`,不新增 reducer/动作。
|
||||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 82 个有 reducer 的切片,
|
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 83 个有 reducer 的切片,
|
||||||
`launchParams` 与其余 **6 个字段原样透传**;
|
`launchParams` 与其余 **5 个字段原样透传**;
|
||||||
迁移进度用 `RootReducer.Coverage`(`已迁移 83/89`)与 `RootWiring.Unmigrated` 暴露。
|
迁移进度用 `RootReducer.Coverage`(`已迁移 84/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **913 项全绿**,含 89 槽位完整性、82 个归约切片一次归约互不串片、未迁移字段透传,
|
- 自检:`TankiOffline/tools/RunStateTest.ps1` **924 项全绿**,含 89 槽位完整性、83 个归约切片一次归约互不串片、未迁移字段透传,
|
||||||
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
||||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"generatedAt": "2026-10-24T13:23:52.900Z",
|
"generatedAt": "2026-10-24T13:56:08.668Z",
|
||||||
"module": "module_10032.js",
|
"module": "module_10032.js",
|
||||||
"RootState": {
|
"RootState": {
|
||||||
"Class": "z6",
|
"Class": "z6",
|
||||||
@@ -89,7 +89,8 @@
|
|||||||
"matchmaking",
|
"matchmaking",
|
||||||
"battlesSelect",
|
"battlesSelect",
|
||||||
"battleUsers",
|
"battleUsers",
|
||||||
"challenges"
|
"challenges",
|
||||||
|
"clansStorage"
|
||||||
],
|
],
|
||||||
"AnonymousActions": [
|
"AnonymousActions": [
|
||||||
{
|
{
|
||||||
@@ -1489,6 +1490,30 @@
|
|||||||
"Name": "RefreshBattlePasses",
|
"Name": "RefreshBattlePasses",
|
||||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||||
"Effect": "战令条目批量刷新(`GZ`),离线重建按 no-op 收口"
|
"Effect": "战令条目批量刷新(`GZ`),离线重建按 no-op 收口"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Local": "mO",
|
||||||
|
"Name": "ClearForeignClan",
|
||||||
|
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||||
|
"Effect": "foreignClan=null(`n.lr1(cd, cd, null)`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Local": "vO",
|
||||||
|
"Name": "LoadClanIntoStorage",
|
||||||
|
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||||
|
"Effect": "clans[clan.id]=clan(原名 ClanLoaded,与 clan 切片同名类冲突,改名 LoadClanIntoStorage)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Local": "dO",
|
||||||
|
"Name": "AddClanUser",
|
||||||
|
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||||
|
"Effect": "clan.users += userId(原名 AddUser,与战斗列表同名类冲突,改名 AddClanUser)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Local": "gO",
|
||||||
|
"Name": "RemoveClanUser",
|
||||||
|
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||||
|
"Effect": "clan.users -= userId(原名 RemoveUser,同上改名 RemoveClanUser)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Markers": [
|
"Markers": [
|
||||||
@@ -2037,22 +2062,22 @@
|
|||||||
"Reducer": "me.vr1",
|
"Reducer": "me.vr1",
|
||||||
"Delegate": "me.vr1(t, n.rpv_1)",
|
"Delegate": "me.vr1(t, n.rpv_1)",
|
||||||
"Actions": [
|
"Actions": [
|
||||||
"?mO",
|
"AddClanUser",
|
||||||
"AddUser",
|
|
||||||
"AddUsersToNewAccepted",
|
"AddUsersToNewAccepted",
|
||||||
"BuyAdditionalPlace",
|
"BuyAdditionalPlace",
|
||||||
"ClanLoaded",
|
|
||||||
"ClanUnloaded",
|
"ClanUnloaded",
|
||||||
|
"ClearForeignClan",
|
||||||
"ForeignClanLoaded",
|
"ForeignClanLoaded",
|
||||||
|
"LoadClanIntoStorage",
|
||||||
"MinimalRankChanged",
|
"MinimalRankChanged",
|
||||||
"RecruitmentChanged",
|
"RecruitmentChanged",
|
||||||
"RemoveUser",
|
"RemoveClanUser",
|
||||||
"RemoveUsersFromNewAccepted",
|
"RemoveUsersFromNewAccepted",
|
||||||
"ShowForeignClan",
|
"ShowForeignClan",
|
||||||
"UpdateClan"
|
"UpdateClan"
|
||||||
],
|
],
|
||||||
"Default": "new lO()",
|
"Default": "new lO()",
|
||||||
"Migrated": false
|
"Migrated": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Field": "tipsState",
|
"Field": "tipsState",
|
||||||
|
|||||||
@@ -339,6 +339,12 @@ const AnonymousActionNames = new Map([
|
|||||||
['sP', 'MigrateBattleUserTeams'],
|
['sP', 'MigrateBattleUserTeams'],
|
||||||
// challenges 切片(CZ / nh.hsj):LZ 没有 toString。
|
// challenges 切片(CZ / nh.hsj):LZ 没有 toString。
|
||||||
['LZ', 'RefreshBattlePasses'],
|
['LZ', 'RefreshBattlePasses'],
|
||||||
|
// clansStorage 切片(lO / zO.vr1):mO 没有 toString;dO/gO 与战斗列表的同名类冲突,改名避免字段错配。
|
||||||
|
['mO', 'ClearForeignClan'],
|
||||||
|
['dO', 'AddClanUser'],
|
||||||
|
['gO', 'RemoveClanUser'],
|
||||||
|
// vO 的 toString 名 ClanLoaded 与 clan 切片的 isLoaded 动作同名冲突,改名避免字段错配。
|
||||||
|
['vO', 'LoadClanIntoStorage'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
||||||
@@ -826,6 +832,7 @@ const Migrated = {
|
|||||||
battlesSelect: { Type: 'BattlesSelectStateSlice', Reduce: 'ReduceBattlesSelect' },
|
battlesSelect: { Type: 'BattlesSelectStateSlice', Reduce: 'ReduceBattlesSelect' },
|
||||||
battleUsers: { Type: 'BattleUsersStateSlice', Reduce: 'ReduceBattleUsers' },
|
battleUsers: { Type: 'BattleUsersStateSlice', Reduce: 'ReduceBattleUsers' },
|
||||||
challenges: { Type: 'ChallengesStateSlice', Reduce: 'ReduceChallenges' },
|
challenges: { Type: 'ChallengesStateSlice', Reduce: 'ReduceChallenges' },
|
||||||
|
clansStorage: { Type: 'ClanStorageStateSlice', Reduce: 'ReduceClanStorage' },
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
||||||
@@ -1250,6 +1257,10 @@ const AppSettingsAnonymousEffects = {
|
|||||||
lP: 'usersPremium[userId](`cg(n.mqa_1, Vd(t.iqs_1, t.jqs_1))`)',
|
lP: 'usersPremium[userId](`cg(n.mqa_1, Vd(t.iqs_1, t.jqs_1))`)',
|
||||||
sP: '旧队伍枚举迁移(`qm/bm/em` 映射),离线重建按 no-op 收口',
|
sP: '旧队伍枚举迁移(`qm/bm/em` 映射),离线重建按 no-op 收口',
|
||||||
LZ: '战令条目批量刷新(`GZ`),离线重建按 no-op 收口',
|
LZ: '战令条目批量刷新(`GZ`),离线重建按 no-op 收口',
|
||||||
|
mO: 'foreignClan=null(`n.lr1(cd, cd, null)`)',
|
||||||
|
vO: 'clans[clan.id]=clan(原名 ClanLoaded,与 clan 切片同名类冲突,改名 LoadClanIntoStorage)',
|
||||||
|
dO: 'clan.users += userId(原名 AddUser,与战斗列表同名类冲突,改名 AddClanUser)',
|
||||||
|
gO: 'clan.users -= userId(原名 RemoveUser,同上改名 RemoveClanUser)',
|
||||||
};
|
};
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(P, 'names', 'root_wiring.json'),
|
path.join(P, 'names', 'root_wiring.json'),
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
// ClanStorageReducer.kt —— 战队列表缓存切片(对应 module_10032 的 lO 状态 + zO.vr1)
|
||||||
|
//
|
||||||
|
// 证据链:
|
||||||
|
// 状态类 lO:3 个字段,toString 名 "ClansStorage(clans=…, foreignClanId=…, foreignClan=…)"。
|
||||||
|
// 默认:clans=emptyMap()、foreignClanId=null、foreignClan=null。
|
||||||
|
// 根委派:`me.vr1(t, n.rpv_1)`。
|
||||||
|
// reducer(13 个实例臂,全部围绕 ClanInfo 的 copy `nr1`):
|
||||||
|
// vO(ClanLoaded) → clans[clan.id] = clan
|
||||||
|
// pO(ClanUnloaded) → clans -= clanId
|
||||||
|
// TM(MinimalRankChanged) → copy(minRankIndexForAddClan) // `nr1` 第 5 参
|
||||||
|
// AM(RecruitmentChanged) → copy(incomingRequestEnabled) // 第 6 参
|
||||||
|
// BN(AddUsersToNewAccepted)→ copy(newUsers += userIds) // 第 16 参
|
||||||
|
// FN(RemoveUsersFromNewAccepted)→ copy(newUsers -= userId) // 第 16 参
|
||||||
|
// dO(AddUser) → copy(users += userId) // 第 9 参
|
||||||
|
// gO(RemoveUser) → copy(users -= userId) // 第 9 参
|
||||||
|
// wO(ForeignClanLoaded) → foreignClan
|
||||||
|
// mO(无 toString) → foreignClan = null
|
||||||
|
// OM(ShowForeignClan) → foreignClanId
|
||||||
|
// nO(UpdateClan) → copy(name / tag / description,null 时保留原值)
|
||||||
|
// iO(BuyAdditionalPlace) → copy(maxMembers + 1) // 第 15 参
|
||||||
|
//
|
||||||
|
// 列表里的战队摘要直接复用生成物 `ClanInfo`(16 字段)。
|
||||||
|
package App.State.Reducers
|
||||||
|
|
||||||
|
import App.State.AddUsersToNewAccepted
|
||||||
|
import App.State.BuyAdditionalPlace
|
||||||
|
import App.State.ClanInfo
|
||||||
|
import App.State.ClanUnloaded
|
||||||
|
import App.State.ForeignClanLoaded
|
||||||
|
import App.State.MinimalRankChanged
|
||||||
|
import App.State.RecruitmentChanged
|
||||||
|
import App.State.RemoveUsersFromNewAccepted
|
||||||
|
import App.State.ShowForeignClan
|
||||||
|
import App.State.UpdateClan
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ 动作 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原 `vO`(原名 `ClanLoaded`,与 clan 切片的 `isLoaded` 动作同名冲突):把战队摘要写进缓存。
|
||||||
|
*/
|
||||||
|
data class LoadClanIntoStorage(val clan: ClanInfo)
|
||||||
|
|
||||||
|
/** 原 `dO`(原名 `AddUser`,与战斗列表的同名类冲突):把用户加入战队成员表。 */
|
||||||
|
data class AddClanUser(val clanId: Any?, val userId: Any?)
|
||||||
|
|
||||||
|
/** 原 `gO`(原名 `RemoveUser`,与战斗列表的同名类冲突):把用户移出战队成员表。 */
|
||||||
|
data class RemoveClanUser(val clanId: Any?, val userId: Any?)
|
||||||
|
|
||||||
|
/** 原 `mO`:清空外战队详情。 */
|
||||||
|
object ClearForeignClan
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ 状态 */
|
||||||
|
|
||||||
|
data class ClanStorageStateSlice(
|
||||||
|
val Clans: Map<Any?, Any?> = emptyMap(),
|
||||||
|
val ForeignClanId: Any? = null,
|
||||||
|
val ForeignClan: Any? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ reducer */
|
||||||
|
|
||||||
|
private fun Plus(Target: Any?, Value: Any?): Any? = when (Target) {
|
||||||
|
is Set<*> -> if (Value is Iterable<*>) Target + Value.toSet() else Target + Value
|
||||||
|
is List<*> -> if (Value is Iterable<*>) Target + Value.toList() else Target + Value
|
||||||
|
else -> if (Value is Iterable<*>) Value.toSet() else setOf(Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Minus(Target: Any?, Value: Any?): Any? = when (Target) {
|
||||||
|
is Set<*> -> if (Value is Iterable<*>) Target - Value.toSet() else Target - Value
|
||||||
|
is List<*> -> if (Value is Iterable<*>) Target - Value.toList() else Target - Value
|
||||||
|
else -> emptySet<Any?>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 原 key 是 Long,部分动作字段是 Int;按数值兼容查一次。 */
|
||||||
|
private fun Lookup(Clans: Map<Any?, Any?>, ClanId: Any?): Pair<Any?, ClanInfo>? {
|
||||||
|
(Clans[ClanId] as? ClanInfo)?.let { return ClanId to it }
|
||||||
|
val Number = ClanId as? Number ?: return null
|
||||||
|
(Clans[Number.toLong()] as? ClanInfo)?.let { return Number.toLong() to it }
|
||||||
|
(Clans[Number.toInt()] as? ClanInfo)?.let { return Number.toInt() to it }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Update(
|
||||||
|
Clans: Map<Any?, Any?>,
|
||||||
|
ClanId: Any?,
|
||||||
|
Transform: (ClanInfo) -> ClanInfo,
|
||||||
|
): Map<Any?, Any?> {
|
||||||
|
val (Key, Clan) = Lookup(Clans, ClanId) ?: return Clans
|
||||||
|
return Clans + (Key to Transform(Clan))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ReduceClanStorage(
|
||||||
|
State0: ClanStorageStateSlice,
|
||||||
|
Action: Any,
|
||||||
|
): ClanStorageStateSlice = when (Action) {
|
||||||
|
is LoadClanIntoStorage -> State0.copy(
|
||||||
|
Clans = State0.Clans + (Action.clan.id to Action.clan),
|
||||||
|
)
|
||||||
|
is ClanUnloaded -> State0.copy(Clans = State0.Clans - Action.clanId)
|
||||||
|
is MinimalRankChanged -> State0.copy(
|
||||||
|
Clans = Update(State0.Clans, Action.clanId) {
|
||||||
|
it.copy(minRankIndexForAddClan = (Action.rankIndex as? Int) ?: it.minRankIndexForAddClan)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is RecruitmentChanged -> State0.copy(
|
||||||
|
Clans = Update(State0.Clans, Action.clanId) {
|
||||||
|
it.copy(incomingRequestEnabled = Action.enabled == true)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is AddUsersToNewAccepted -> State0.copy(
|
||||||
|
Clans = Update(State0.Clans, Action.clanId) {
|
||||||
|
it.copy(newUsers = Plus(it.newUsers, Action.userIds))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is RemoveUsersFromNewAccepted -> State0.copy(
|
||||||
|
Clans = Update(State0.Clans, Action.clanId) {
|
||||||
|
it.copy(newUsers = Minus(it.newUsers, Action.userId))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is AddClanUser -> State0.copy(
|
||||||
|
Clans = Update(State0.Clans, Action.clanId) {
|
||||||
|
it.copy(users = Plus(it.users, Action.userId))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is RemoveClanUser -> State0.copy(
|
||||||
|
Clans = Update(State0.Clans, Action.clanId) {
|
||||||
|
it.copy(users = Minus(it.users, Action.userId))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is ForeignClanLoaded -> State0.copy(ForeignClan = Action.clan)
|
||||||
|
is ClearForeignClan -> State0.copy(ForeignClan = null)
|
||||||
|
is ShowForeignClan -> State0.copy(ForeignClanId = Action.clanId)
|
||||||
|
is UpdateClan -> State0.copy(
|
||||||
|
Clans = Update(State0.Clans, Action.clanId) {
|
||||||
|
it.copy(
|
||||||
|
name = Action.name ?: it.name,
|
||||||
|
tag = Action.tag ?: it.tag,
|
||||||
|
description = (Action.description as? String) ?: it.description,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
is BuyAdditionalPlace -> State0.copy(
|
||||||
|
Clans = Update(State0.Clans, Action.clanId) {
|
||||||
|
it.copy(maxMembers = it.maxMembers + 1)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else -> State0
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// RootReducer.kt —— 根 reducer 骨架(对应 module_10032 的根状态 z6 / TOState 与根 reducer k6)
|
// RootReducer.kt —— 根 reducer 骨架(对应 module_10032 的根状态 z6 / TOState 与根 reducer k6)
|
||||||
//
|
//
|
||||||
// 原包 k6 对 89 个切片逐个调用各自的 reducer,再 `return n.cti(...)`(copy 出新状态)。
|
// 原包 k6 对 89 个切片逐个调用各自的 reducer,再 `return n.cti(...)`(copy 出新状态)。
|
||||||
// 这里采用同一形状。已迁移的 83 个切片里,82 个真正调用 reducer,launchParams 只做类型收口:
|
// 这里采用同一形状。已迁移的 84 个切片里,83 个真正调用 reducer,launchParams 只做类型收口:
|
||||||
//
|
//
|
||||||
// inviteState → ReduceInvite(aD / pD.er5)
|
// inviteState → ReduceInvite(aD / pD.er5)
|
||||||
// loginByPassword → ReduceLoginByPassword(gD / MD.cr6)
|
// loginByPassword → ReduceLoginByPassword(gD / MD.cr6)
|
||||||
@@ -85,9 +85,10 @@
|
|||||||
// battlesSelect → ReduceBattlesSelect(fA / Mi.vqk,根委派 `Mi.vqk(t, n.apw_1)`)
|
// battlesSelect → ReduceBattlesSelect(fA / Mi.vqk,根委派 `Mi.vqk(t, n.apw_1)`)
|
||||||
// battleUsers → ReduceBattleUsers(uP / sr.hqs,根委派 `sr.hqs(t, n.hpw_1)`)
|
// battleUsers → ReduceBattleUsers(uP / sr.hqs,根委派 `sr.hqs(t, n.hpw_1)`)
|
||||||
// challenges → ReduceChallenges(CZ / nh.hsj,根委派 `nh.hsj(t, n.fpv_1)`)
|
// challenges → ReduceChallenges(CZ / nh.hsj,根委派 `nh.hsj(t, n.fpv_1)`)
|
||||||
|
// clansStorage → ReduceClanStorage(lO / me.vr1,根委派 `me.vr1(t, n.rpv_1)`)
|
||||||
// launchParams → 无 reducer(原根 reducer 原样透传;默认 `ag()` = emptyMap())
|
// launchParams → 无 reducer(原根 reducer 原样透传;默认 `ag()` = emptyMap())
|
||||||
//
|
//
|
||||||
// 其余 6 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
// 其余 5 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||||
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
||||||
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
||||||
package App.State
|
package App.State
|
||||||
@@ -109,6 +110,7 @@ import App.State.Reducers.ReduceBattleView
|
|||||||
import App.State.Reducers.ReduceBattleInvite
|
import App.State.Reducers.ReduceBattleInvite
|
||||||
import App.State.Reducers.ReduceCaptcha
|
import App.State.Reducers.ReduceCaptcha
|
||||||
import App.State.Reducers.ReduceChallenges
|
import App.State.Reducers.ReduceChallenges
|
||||||
|
import App.State.Reducers.ReduceClanStorage
|
||||||
import App.State.Reducers.ReduceClanUserInfo
|
import App.State.Reducers.ReduceClanUserInfo
|
||||||
import App.State.Reducers.ReduceClanChat
|
import App.State.Reducers.ReduceClanChat
|
||||||
import App.State.Reducers.ReduceContextTutorial
|
import App.State.Reducers.ReduceContextTutorial
|
||||||
@@ -270,6 +272,7 @@ object RootReducer {
|
|||||||
BattlesSelect = ReduceBattlesSelect(State0.BattlesSelect, Action),
|
BattlesSelect = ReduceBattlesSelect(State0.BattlesSelect, Action),
|
||||||
BattleUsers = ReduceBattleUsers(State0.BattleUsers, Action),
|
BattleUsers = ReduceBattleUsers(State0.BattleUsers, Action),
|
||||||
Challenges = ReduceChallenges(State0.Challenges, Action),
|
Challenges = ReduceChallenges(State0.Challenges, Action),
|
||||||
|
ClansStorage = ReduceClanStorage(State0.ClansStorage, Action),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import App.State.Reducers.CaptchaStateSlice
|
|||||||
import App.State.Reducers.ChallengesStateSlice
|
import App.State.Reducers.ChallengesStateSlice
|
||||||
import App.State.Reducers.ClanChatStateSlice
|
import App.State.Reducers.ClanChatStateSlice
|
||||||
import App.State.Reducers.ClanUserInfoStateSlice
|
import App.State.Reducers.ClanUserInfoStateSlice
|
||||||
|
import App.State.Reducers.ClanStorageStateSlice
|
||||||
import App.State.Reducers.ContextTutorialStateSlice
|
import App.State.Reducers.ContextTutorialStateSlice
|
||||||
import App.State.Reducers.ContractStateSlice
|
import App.State.Reducers.ContractStateSlice
|
||||||
import App.State.Reducers.ControlSettingsStateSlice
|
import App.State.Reducers.ControlSettingsStateSlice
|
||||||
@@ -129,8 +130,8 @@ data class RootState(
|
|||||||
val ClanChatState: ClanChatStateSlice = ClanChatStateSlice(),
|
val ClanChatState: ClanChatStateSlice = ClanChatStateSlice(),
|
||||||
/** 原 clan(jN / we.hr0)。未迁移:原样透传。 */
|
/** 原 clan(jN / we.hr0)。未迁移:原样透传。 */
|
||||||
val Clan: Any? = null,
|
val Clan: Any? = null,
|
||||||
/** 原 clansStorage(lO / me.vr1)。未迁移:原样透传。 */
|
/** 原 clansStorage(lO / me.vr1)。已迁移。 */
|
||||||
val ClansStorage: Any? = null,
|
val ClansStorage: ClanStorageStateSlice = ClanStorageStateSlice(),
|
||||||
/** 原 tipsState(dst / Hw.vth)。已迁移。 */
|
/** 原 tipsState(dst / Hw.vth)。已迁移。 */
|
||||||
val TipsState: TipsStateSlice = TipsStateSlice(),
|
val TipsState: TipsStateSlice = TipsStateSlice(),
|
||||||
/** 原 news(ZX / E_.asd)。已迁移。 */
|
/** 原 news(ZX / E_.asd)。已迁移。 */
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ object RootWiring {
|
|||||||
SliceWiring("chatState", "opv_1", "LP", "\$r.wqv", "\$r.wqv(t, n.opv_1)", listOf("?QP", "?XP", "?bN", "?fN", "?lN", "?nN", "?pN", "?qN", "?sN", "?vN", "?wN", "ChangeChannel", "CleanUsersMessage", "Configure", "IgnoreUserMessages", "ResetSettingsFromStorage", "SaveChatMessage", "SendMessageToServer", "SetMessages", "SetSelectedUid", "ShowContextMenu", "ShowUserMessages", "UpdateTypingSpeedAntifloodParams", "UpdateUsers")),
|
SliceWiring("chatState", "opv_1", "LP", "\$r.wqv", "\$r.wqv(t, n.opv_1)", listOf("?QP", "?XP", "?bN", "?fN", "?lN", "?nN", "?pN", "?qN", "?sN", "?vN", "?wN", "ChangeChannel", "CleanUsersMessage", "Configure", "IgnoreUserMessages", "ResetSettingsFromStorage", "SaveChatMessage", "SendMessageToServer", "SetMessages", "SetSelectedUid", "ShowContextMenu", "ShowUserMessages", "UpdateTypingSpeedAntifloodParams", "UpdateUsers")),
|
||||||
SliceWiring("clanChatState", "ppv_1", "qnt", "yv.qtg", "yv.qtg(t, n.ppv_1)", listOf("CloseClanChat", "Configure", "DoAddMessages", "OpenClanChat", "ResetClanChat")),
|
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("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("clansStorage", "rpv_1", "lO", "me.vr1", "me.vr1(t, n.rpv_1)", listOf("AddClanUser", "AddUsersToNewAccepted", "BuyAdditionalPlace", "ClanUnloaded", "ClearForeignClan", "ForeignClanLoaded", "LoadClanIntoStorage", "MinimalRankChanged", "RecruitmentChanged", "RemoveClanUser", "RemoveUsersFromNewAccepted", "ShowForeignClan", "UpdateClan")),
|
||||||
SliceWiring("tipsState", "spv_1", "dst", "Hw.vth", "Hw.vth(t, n.spv_1)", listOf("UpdateTips")),
|
SliceWiring("tipsState", "spv_1", "dst", "Hw.vth", "Hw.vth(t, n.spv_1)", listOf("UpdateTips")),
|
||||||
SliceWiring("news", "tpv_1", "ZX", "E_.asd", "E_.asd(t, n.tpv_1)", listOf("AddNewsItemAction", "RemoveNewsItemAction", "SetNewsFlag", "SetNewsItemAction", "SetUnreadNewsCounter")),
|
SliceWiring("news", "tpv_1", "ZX", "E_.asd", "E_.asd(t, n.tpv_1)", listOf("AddNewsItemAction", "RemoveNewsItemAction", "SetNewsFlag", "SetNewsItemAction", "SetUnreadNewsCounter")),
|
||||||
SliceWiring("settings", "upv_1", "Uut", "xw.ltg", "xw.ltg(t, n.upv_1)", listOf("DisableAccountSettings", "SetSettingsCategory")),
|
SliceWiring("settings", "upv_1", "Uut", "xw.ltg", "xw.ltg(t, n.upv_1)", listOf("DisableAccountSettings", "SetSettingsCategory")),
|
||||||
@@ -106,7 +106,7 @@ object RootWiring {
|
|||||||
)
|
)
|
||||||
|
|
||||||
/** 已迁移(强类型;launchParams 为透传,不调用 reducer)的字段。 */
|
/** 已迁移(强类型;launchParams 为透传,不调用 reducer)的字段。 */
|
||||||
val Migrated: Set<String> = setOf("inviteState", "loginByPassword", "twitchState", "home", "localBattleUserState", "shop", "screen", "lootBoxes", "garage", "garagePreview", "entrance", "user", "settings", "accountSettings", "proBattle", "language", "announcement", "launchParams", "news", "notifications", "quests", "lobbyLoader", "purchaseDialogState", "promoCode", "supportUrl", "rulesUpdated", "notificationByCountry", "availabilityByRank", "icons", "questCategories", "mainQuest", "securitySettings", "referralEvent", "tipsState", "rankUpDialogState", "battleResult", "captchaState", "modalScreen", "droppableGold", "eventGoods", "creatorTagState", "rewardedVideosState", "passwordChangeState", "system", "contextTutorial", "battleTutorial", "spectator", "twoStepVerificationState", "antiAddiction", "moderation", "migrationState", "register", "userReportsState", "friends", "suppliesState", "clanUserInfo", "battleInviteState", "partner", "userRenameState", "battlePauseState", "battleViewState", "tankActionsLogState", "suppliesTutorial", "clanChatState", "battleSearchState", "battleStatistics", "soundSettings", "gameSettings", "keyboardSettings", "touchscreenHudSettings", "graphicsSettings", "controlSettings", "battleSettings", "contractState", "tankBuilderState", "battleMessage", "maps", "battleChat", "remoteUserDataStorage", "matchmaking", "battlesSelect", "battleUsers", "challenges")
|
val Migrated: Set<String> = setOf("inviteState", "loginByPassword", "twitchState", "home", "localBattleUserState", "shop", "screen", "lootBoxes", "garage", "garagePreview", "entrance", "user", "settings", "accountSettings", "proBattle", "language", "announcement", "launchParams", "news", "notifications", "quests", "lobbyLoader", "purchaseDialogState", "promoCode", "supportUrl", "rulesUpdated", "notificationByCountry", "availabilityByRank", "icons", "questCategories", "mainQuest", "securitySettings", "referralEvent", "tipsState", "rankUpDialogState", "battleResult", "captchaState", "modalScreen", "droppableGold", "eventGoods", "creatorTagState", "rewardedVideosState", "passwordChangeState", "system", "contextTutorial", "battleTutorial", "spectator", "twoStepVerificationState", "antiAddiction", "moderation", "migrationState", "register", "userReportsState", "friends", "suppliesState", "clanUserInfo", "battleInviteState", "partner", "userRenameState", "battlePauseState", "battleViewState", "tankActionsLogState", "suppliesTutorial", "clanChatState", "battleSearchState", "battleStatistics", "soundSettings", "gameSettings", "keyboardSettings", "touchscreenHudSettings", "graphicsSettings", "controlSettings", "battleSettings", "contractState", "tankBuilderState", "battleMessage", "maps", "battleChat", "remoteUserDataStorage", "matchmaking", "battlesSelect", "battleUsers", "challenges", "clansStorage")
|
||||||
|
|
||||||
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
||||||
val Unmigrated: List<SliceWiring> get() = All.filter { it.Field !in Migrated }
|
val Unmigrated: List<SliceWiring> get() = All.filter { it.Field !in Migrated }
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
// System / ContextTutorial / BattleTutorial / Spectator / TwoStepVerification / AntiAddiction /
|
// System / ContextTutorial / BattleTutorial / Spectator / TwoStepVerification / AntiAddiction /
|
||||||
// Moderation / MigrationState / Register / UserReports /
|
// Moderation / MigrationState / Register / UserReports /
|
||||||
// Friends / Supplies / ClanUserInfo / BattleInvite / Partner / UserRename /
|
// Friends / Supplies / ClanUserInfo / BattleInvite / Partner / UserRename /
|
||||||
// BattlePause / BattleView / TankActionsLog / SuppliesTutorial / ClanChat / BattleSearch / BattleStatistics / SoundSettings / GameSettings / KeyboardSettings / TouchscreenHudSettings / GraphicsSettings / ControlSettings / BattleSettings / ContractState / TankBuilder / BattleMessage / Maps / BattleChat / RemoteUserDataStorage / Matchmaking / BattlesSelect / BattleUsers / Challenges;
|
// BattlePause / BattleView / TankActionsLog / SuppliesTutorial / ClanChat / BattleSearch / BattleStatistics / SoundSettings / GameSettings / KeyboardSettings / TouchscreenHudSettings / GraphicsSettings / ControlSettings / BattleSettings / ContractState / TankBuilder / BattleMessage / Maps / BattleChat / RemoteUserDataStorage / Matchmaking / BattlesSelect / BattleUsers / Challenges / ClansStorage;
|
||||||
// ㉑ launchParams 是纯透传切片(无 reducer/动作),只做 Map 类型收口;⑭ 根 reducer 的 89 槽位委派
|
// ㉑ launchParams 是纯透传切片(无 reducer/动作),只做 Map 类型收口;⑭ 根 reducer 的 89 槽位委派
|
||||||
//
|
//
|
||||||
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
||||||
@@ -826,6 +826,20 @@ import App.State.UpdateStars
|
|||||||
import App.State.Reducers.ChallengesStateSlice
|
import App.State.Reducers.ChallengesStateSlice
|
||||||
import App.State.Reducers.ReduceChallenges
|
import App.State.Reducers.ReduceChallenges
|
||||||
import App.State.Reducers.RefreshBattlePasses
|
import App.State.Reducers.RefreshBattlePasses
|
||||||
|
import App.State.ClanInfo
|
||||||
|
import App.State.ClanUnloaded
|
||||||
|
import App.State.BuyAdditionalPlace
|
||||||
|
import App.State.ForeignClanLoaded
|
||||||
|
import App.State.MinimalRankChanged
|
||||||
|
import App.State.RecruitmentChanged
|
||||||
|
import App.State.ShowForeignClan
|
||||||
|
import App.State.UpdateClan
|
||||||
|
import App.State.Reducers.AddClanUser
|
||||||
|
import App.State.Reducers.LoadClanIntoStorage
|
||||||
|
import App.State.Reducers.ClanStorageStateSlice
|
||||||
|
import App.State.Reducers.ClearForeignClan
|
||||||
|
import App.State.Reducers.ReduceClanStorage
|
||||||
|
import App.State.Reducers.RemoveClanUser
|
||||||
import App.State.Reducers.UserRankBounds
|
import App.State.Reducers.UserRankBounds
|
||||||
import App.State.Reducers.UserStateSlice
|
import App.State.Reducers.UserStateSlice
|
||||||
import App.State.Reducers.ClearHullData
|
import App.State.Reducers.ClearHullData
|
||||||
@@ -1253,7 +1267,7 @@ object StateCheck {
|
|||||||
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ⑭ 根 reducer:89 个槽位的委派表 + 83 个已迁移切片(82 归约 + launchParams 透传)
|
// ⑭ 根 reducer:89 个槽位的委派表 + 84 个已迁移切片(83 归约 + launchParams 透传)
|
||||||
run {
|
run {
|
||||||
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
||||||
Check(
|
Check(
|
||||||
@@ -1317,7 +1331,7 @@ object StateCheck {
|
|||||||
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
||||||
)
|
)
|
||||||
Check(
|
Check(
|
||||||
"根:迁移表 = 83 个已迁移字段,其余 6 个待迁",
|
"根:迁移表 = 84 个已迁移字段,其余 5 个待迁",
|
||||||
RootReducer.Migrated ==
|
RootReducer.Migrated ==
|
||||||
setOf(
|
setOf(
|
||||||
"inviteState", "loginByPassword", "twitchState", "home",
|
"inviteState", "loginByPassword", "twitchState", "home",
|
||||||
@@ -1341,9 +1355,9 @@ object StateCheck {
|
|||||||
"soundSettings", "gameSettings", "keyboardSettings", "touchscreenHudSettings",
|
"soundSettings", "gameSettings", "keyboardSettings", "touchscreenHudSettings",
|
||||||
"graphicsSettings", "controlSettings", "battleSettings", "contractState",
|
"graphicsSettings", "controlSettings", "battleSettings", "contractState",
|
||||||
"tankBuilderState", "battleMessage", "maps", "battleChat",
|
"tankBuilderState", "battleMessage", "maps", "battleChat",
|
||||||
"remoteUserDataStorage", "matchmaking", "battlesSelect", "battleUsers", "challenges",
|
"remoteUserDataStorage", "matchmaking", "battlesSelect", "battleUsers", "challenges", "clansStorage",
|
||||||
) &&
|
) &&
|
||||||
RootWiring.Unmigrated.size == 6
|
RootWiring.Unmigrated.size == 5
|
||||||
)
|
)
|
||||||
|
|
||||||
// 一次 ReduceRoot 里多个切片各归约自己的动作,互不串片
|
// 一次 ReduceRoot 里多个切片各归约自己的动作,互不串片
|
||||||
@@ -1399,7 +1413,7 @@ object StateCheck {
|
|||||||
S5.User.Uid == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
S5.User.Uid == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
||||||
)
|
)
|
||||||
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
||||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 83/89")
|
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 84/89")
|
||||||
|
|
||||||
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
||||||
Store.Dispatch(SetStatus("LOGGING_IN"))
|
Store.Dispatch(SetStatus("LOGGING_IN"))
|
||||||
@@ -6991,6 +7005,83 @@ object StateCheck {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 94 切片 reducer:ClansStorage(lO / me.vr1,3 字段;13 个动作)
|
||||||
|
run {
|
||||||
|
fun Clan(Id: Any? = 1L): ClanInfo = ClanInfo(
|
||||||
|
id = Id, name = "n", tag = "t", description = "d",
|
||||||
|
minRankIndexForAddClan = 1, incomingRequestEnabled = true,
|
||||||
|
creatorId = 9L, createTime = 0L, users = emptySet<Any?>(),
|
||||||
|
gameObject = null, maxCharactersDescription = 100, blocked = false,
|
||||||
|
reasonForBlocking = "", self = false, maxMembers = 10,
|
||||||
|
newUsers = emptySet<Any?>(),
|
||||||
|
)
|
||||||
|
|
||||||
|
val S0 = ClanStorageStateSlice()
|
||||||
|
Check("切片 ClansStorage:默认值完整", S0.Clans.isEmpty() && S0.ForeignClan == null)
|
||||||
|
val S1 = ReduceClanStorage(S0, LoadClanIntoStorage(Clan()))
|
||||||
|
Check(
|
||||||
|
"切片 ClansStorage:ClanLoaded 按 id 入表",
|
||||||
|
(S1.Clans[1L] as ClanInfo).name == "n"
|
||||||
|
)
|
||||||
|
Check(
|
||||||
|
"切片 ClansStorage:MinimalRankChanged / RecruitmentChanged 就地 copy",
|
||||||
|
(ReduceClanStorage(S1, MinimalRankChanged(1L, 5)).Clans[1L] as ClanInfo)
|
||||||
|
.minRankIndexForAddClan == 5 &&
|
||||||
|
!(ReduceClanStorage(S1, RecruitmentChanged(1L, false)).Clans[1L] as ClanInfo)
|
||||||
|
.incomingRequestEnabled
|
||||||
|
)
|
||||||
|
Check(
|
||||||
|
"切片 ClansStorage:成员与待审用户的增删",
|
||||||
|
(ReduceClanStorage(
|
||||||
|
ReduceClanStorage(S1, AddClanUser(1L, 7L)),
|
||||||
|
AddUsersToNewAccepted(1, listOf(8L)),
|
||||||
|
).Clans[1L] as ClanInfo).let {
|
||||||
|
it.users == setOf<Any?>(7L) && it.newUsers == setOf<Any?>(8L)
|
||||||
|
} &&
|
||||||
|
(ReduceClanStorage(
|
||||||
|
ReduceClanStorage(S1, AddClanUser(1L, 7L)),
|
||||||
|
RemoveClanUser(1L, 7L),
|
||||||
|
).Clans[1L] as ClanInfo).users == emptySet<Any?>()
|
||||||
|
)
|
||||||
|
Check(
|
||||||
|
"切片 ClansStorage:UpdateClan 用 null 保留原值",
|
||||||
|
(ReduceClanStorage(S1, UpdateClan(1L, "n2", null, null))
|
||||||
|
.Clans[1L] as ClanInfo).let { it.name == "n2" && it.tag == "t" }
|
||||||
|
)
|
||||||
|
Check(
|
||||||
|
"切片 ClansStorage:BuyAdditionalPlace 让 maxMembers +1",
|
||||||
|
(ReduceClanStorage(S1, BuyAdditionalPlace(1L)).Clans[1L] as ClanInfo)
|
||||||
|
.maxMembers == 11
|
||||||
|
)
|
||||||
|
Check(
|
||||||
|
"切片 ClansStorage:外战队三臂",
|
||||||
|
ReduceClanStorage(S1, ForeignClanLoaded(Clan(2L))).ForeignClan != null &&
|
||||||
|
ReduceClanStorage(S1, ClearForeignClan).ForeignClan == null &&
|
||||||
|
ReduceClanStorage(S1, ShowForeignClan(2L)).ForeignClanId == 2L
|
||||||
|
)
|
||||||
|
Check(
|
||||||
|
"切片 ClansStorage:ClanUnloaded 删表",
|
||||||
|
ReduceClanStorage(S1, ClanUnloaded(1L)).Clans.isEmpty()
|
||||||
|
)
|
||||||
|
Check(
|
||||||
|
"切片 ClansStorage:无关动作不改状态",
|
||||||
|
ReduceClanStorage(S1, AddFrags(1)) == S1
|
||||||
|
)
|
||||||
|
|
||||||
|
val Root0 = RootState()
|
||||||
|
val Root1 = ReduceRoot(Root0, LoadClanIntoStorage(Clan()))
|
||||||
|
Check(
|
||||||
|
"根:ClanLoaded 只动 clansStorage",
|
||||||
|
Root1.ClansStorage.Clans.keys == setOf<Any?>(1L) &&
|
||||||
|
Root1.Challenges == Root0.Challenges
|
||||||
|
)
|
||||||
|
val W = RootWiring.ByField("clansStorage")!!
|
||||||
|
Check(
|
||||||
|
"根:clansStorage 委派到 lO / me.vr1 且 13 个动作",
|
||||||
|
W.SliceClass == "lO" && W.Reducer == "me.vr1" && W.Actions.size == 13
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val Failed = Results.filter { !it.second }
|
val Failed = Results.filter { !it.second }
|
||||||
println("TankiOffline 状态层自检:${Results.size} 项")
|
println("TankiOffline 状态层自检:${Results.size} 项")
|
||||||
for ((Name, Ok) in Results) println((if (Ok) " ✓ " else " ✗ ") + Name)
|
for ((Name, Ok) in Results) println((if (Ok) " ✓ " else " ✗ ") + Name)
|
||||||
|
|||||||
Reference in new issue
Block a user