feat(state): 迁移 icons/questCategories/mainQuest/securitySettings/referralEvent
This commit is contained in:
1 parent
49e8c1efc4
commit
6d2487d9ea
12 files changed
+664
-34
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` 动作名。
|
||||
- 已迁移切片 **28/89**:
|
||||
- 已迁移切片 **33/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)
|
||||
@@ -240,12 +240,28 @@
|
||||
`Init` 写三条国家提示消息,`qJ`→`MarkHomeScreenDialogShown` 只把 `homeScreenDialogShown` 置 true。
|
||||
- `availabilityByRank` → `tet` / `$p.xth`(`AvailabilityByRankReducer.kt`):1 字段,
|
||||
`SetLoadedData` 整体替换等级可购买表,缺省空 Map。
|
||||
- `icons` → `oH` / `vs.kru`(`IconsReducer.kt`):1 字段,2 个分支。
|
||||
`SetIcons` 把 `List<IconData>` 收成 `icon → resource` 的 Map(原 `HashMap.put`),缺省空 Map。
|
||||
- `questCategories` → `zZ` / `th.lsh`(`QuestCategoriesReducer.kt`):3 字段,5 个分支。
|
||||
`SetQuestCategories` 按 `index` 升序;`RemoveQuestCategory` 按对象删除;
|
||||
`RequestQuestCategoriesStatistic` 在 `isHiddenUpdate=false` 时把 `statisticLoadedTime` 推到 `Long.MAX_VALUE`;
|
||||
`SetQuestCategoriesStatistic` 按 `questCategoryId` 建索引并写 `Date.now()`。
|
||||
- `mainQuest` → `WZ` / `ih.bsk`(`MainQuestReducer.kt`):5 字段,7 个实例臂。
|
||||
`SetQuests` 把任务按 `completedCount` 展开(`completed && count != 0` 的原始项丢弃,
|
||||
再为 `1..count` 生成 `completed=true` 的副本),最后按 `completed` 降序稳定排序,并清空已领奖;
|
||||
`UpdateQuests` 按 `id` 就地替换/追加;`AddRewardedQuest` 里的 `questId` 实际是任务对象;
|
||||
`VZ`→`ResetQuestsLoaded`(无 `toString`,只 `isLoaded=false`),`KZ`→`QuestsLoaded` 只置 `isLoaded=true`。
|
||||
- `securitySettings` → `V2` / `pc.qsv`(`SecuritySettingsReducer.kt`):1 字段,缺省 `isProfileBlocked=true`,
|
||||
`SetProfileBlockStatus` 直接写布尔。
|
||||
- `referralEvent` → `pQ` / `lh.osk`(`ReferralEventReducer.kt`):14 字段,4 个实例臂。
|
||||
`SetReferrer` 写前 2 字段、`SetReferrals` 写人数与明细、`SetPromoCode` 写邀请码;
|
||||
`SetReferralEventData` 一次写后 9 个字段(面板标题 / 弹窗图与背景 / 两个分类 id / 任务数 / 两个隐藏标志 / 公告时间)。
|
||||
- `launchParams` → `(pass-through)`:原根 reducer 对 `hpx_1` 没有调用,缺省是 `ag()` 空 Map;
|
||||
`RootState.LaunchParams` 收口为 `LaunchParamsStateSlice = Map<String, String>`,不新增 reducer/动作。
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 27 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **61 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 28/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **419 项全绿**,含 89 槽位完整性、27 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
- `App/State/RootReducer.kt`:`ReduceRoot(State0, Action)` 归约上述 32 个有 reducer 的切片,
|
||||
`launchParams` 与其余 **56 个字段原样透传**;
|
||||
迁移进度用 `RootReducer.Coverage`(`已迁移 33/89`)与 `RootWiring.Unmigrated` 暴露。
|
||||
- 自检:`TankiOffline/tools/RunStateTest.ps1` **457 项全绿**,含 89 槽位完整性、32 个归约切片一次归约互不串片、未迁移字段透传,
|
||||
以及用 `action_trace_merged.json` 真实派发的两条商店动作(`SetCoinPaymentProviderUrl` / `ToggleShopActivity`)回放。
|
||||
- 委派表里的已知形态:`shop` / `home` / `localBattleUserState` / `partner` 是内联 IIFE,
|
||||
已按字段具名为 `(inline@<field>)` 并从函数体抓到顶层动作名(69 / 1 / 2 / 11 个);
|
||||
@@ -258,7 +274,7 @@
|
||||
entrance 的 6 个、user 的 3 个、settings 的 2 个、accountSettings 的 11 个、
|
||||
language 的 1 个、announcement 的 3 个、news 的 3 个(含两个单例)、notifications 的 2 个、
|
||||
quests 的 1 个、lobbyLoader 的 2 个、purchaseDialogState 的 1 个、supportUrl 的 1 个、
|
||||
notificationByCountry 的 1 个匿名类 / 单例同样按效果定名并登记。
|
||||
notificationByCountry 的 1 个、mainQuest 的 1 个匿名类 / 单例同样按效果定名并登记。
|
||||
|
||||
### S4 引擎核心
|
||||
- 模块:32088(3D 数学)、92980(渲染)、61378(ECS)、55088(物理)、36659 + 71105(资源)、36734(音频)、3569(输入)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generatedAt": "2026-10-24T05:17:45.346Z",
|
||||
"generatedAt": "2026-10-24T06:01:37.203Z",
|
||||
"module": "module_10032.js",
|
||||
"RootState": {
|
||||
"Class": "z6",
|
||||
@@ -34,7 +34,12 @@
|
||||
"supportUrl",
|
||||
"rulesUpdated",
|
||||
"notificationByCountry",
|
||||
"availabilityByRank"
|
||||
"availabilityByRank",
|
||||
"icons",
|
||||
"questCategories",
|
||||
"mainQuest",
|
||||
"securitySettings",
|
||||
"referralEvent"
|
||||
],
|
||||
"AnonymousActions": [
|
||||
{
|
||||
@@ -697,6 +702,12 @@
|
||||
"Name": "MarkHomeScreenDialogShown",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "homeScreenDialogShown=true(`n.isd(cd, cd, cd, !0)`)"
|
||||
},
|
||||
{
|
||||
"Local": "VZ",
|
||||
"Name": "ResetQuestsLoaded",
|
||||
"DispatchedAt": "未在 action_trace_merged.json 中出现;按 reducer 分支效果定名",
|
||||
"Effect": "isLoaded=false(`n.qsj(!1)`;动作类 rsj_1 在 reducer 里未被读取)"
|
||||
}
|
||||
],
|
||||
"Markers": [
|
||||
@@ -1929,7 +1940,7 @@
|
||||
"SetProfileBlockStatus"
|
||||
],
|
||||
"Default": "new V2()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "purchaseDialogState",
|
||||
@@ -1999,16 +2010,16 @@
|
||||
"Reducer": "ih.bsk",
|
||||
"Delegate": "ih.bsk(t, n.fpx_1)",
|
||||
"Actions": [
|
||||
"?VZ",
|
||||
"AddRewardedQuest",
|
||||
"QuestsLoaded",
|
||||
"ResetQuestsLoaded",
|
||||
"SetBattleUpdatedQuests",
|
||||
"SetEventPassShopItemId",
|
||||
"SetQuests",
|
||||
"UpdateQuests"
|
||||
],
|
||||
"Default": "new WZ()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "language",
|
||||
@@ -2270,7 +2281,7 @@
|
||||
"SetIcons"
|
||||
],
|
||||
"Default": "new oH()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "itemNotifications",
|
||||
@@ -2331,7 +2342,7 @@
|
||||
"SetQuestCategoriesStatistic"
|
||||
],
|
||||
"Default": "new zZ()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "proBattle",
|
||||
@@ -2434,7 +2445,7 @@
|
||||
"SetReferrer"
|
||||
],
|
||||
"Default": "new pQ()",
|
||||
"Migrated": false
|
||||
"Migrated": true
|
||||
},
|
||||
{
|
||||
"Field": "supportUrl",
|
||||
|
||||
@@ -179,6 +179,8 @@ const AnonymousActionNames = new Map([
|
||||
['R4', 'ClearSupportUrl'],
|
||||
// notificationByCountry 切片(gJ / $J.ssd):qJ 没有 toString,按 reducer 效果定名。
|
||||
['qJ', 'MarkHomeScreenDialogShown'],
|
||||
// mainQuest 切片(WZ / ih.bsk):VZ 没有 toString,按 reducer 效果定名。
|
||||
['VZ', 'ResetQuestsLoaded'],
|
||||
]);
|
||||
|
||||
// 非动作的 `instanceof`:屏幕标识类,用于 GoTo 分支判断(不是 dispatch 的动作)。
|
||||
@@ -592,6 +594,11 @@ const Migrated = {
|
||||
Reduce: 'ReduceNotificationByCountry',
|
||||
},
|
||||
availabilityByRank: { Type: 'AvailabilityByRankStateSlice', Reduce: 'ReduceAvailabilityByRank' },
|
||||
icons: { Type: 'IconsStateSlice', Reduce: 'ReduceIcons' },
|
||||
questCategories: { Type: 'QuestCategoriesStateSlice', Reduce: 'ReduceQuestCategories' },
|
||||
mainQuest: { Type: 'MainQuestStateSlice', Reduce: 'ReduceMainQuest' },
|
||||
securitySettings: { Type: 'SecuritySettingsStateSlice', Reduce: 'ReduceSecuritySettings' },
|
||||
referralEvent: { Type: 'ReferralEventStateSlice', Reduce: 'ReduceReferralEvent' },
|
||||
};
|
||||
|
||||
for (const R of Rows) R.Migrated = Object.prototype.hasOwnProperty.call(Migrated, R.Field);
|
||||
@@ -799,6 +806,11 @@ const NotificationByCountryAnonymousEffects = {
|
||||
qJ: 'homeScreenDialogShown=true(`n.isd(cd, cd, cd, !0)`)',
|
||||
};
|
||||
|
||||
// mainQuest 切片(WZ / ih.bsk):VZ 没有 toString / 不在 action_inventory,按 reducer 分支效果定名。
|
||||
const MainQuestAnonymousEffects = {
|
||||
VZ: 'isLoaded=false(`n.qsj(!1)`;动作类 rsj_1 在 reducer 里未被读取)',
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(P, 'names', 'root_wiring.json'),
|
||||
JSON.stringify(
|
||||
@@ -923,6 +935,12 @@ fs.writeFileSync(
|
||||
DispatchedAt: '未在 action_trace_merged.json 中出现;按 reducer 分支效果定名',
|
||||
Effect,
|
||||
})),
|
||||
...Object.entries(MainQuestAnonymousEffects).map(([Local, Effect]) => ({
|
||||
Local,
|
||||
Name: AnonymousActionNames.get(Local),
|
||||
DispatchedAt: '未在 action_trace_merged.json 中出现;按 reducer 分支效果定名',
|
||||
Effect,
|
||||
})),
|
||||
],
|
||||
Markers: [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// IconsReducer.kt —— 图标资源表切片(对应 module_10032 的 oH 状态 + hH.kru)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 oH:1 个字段,toString 名 "Icons(icons=…)";copy 是 iru(1 字段)。
|
||||
// 默认:icons = ag() = emptyMap()。
|
||||
// 根委派:`vs.kru(t, n.wpx_1)`。
|
||||
// reducer:`t instanceof _H ? n.iru(u) : n`,其中
|
||||
// `u` 是 HashMap:对 `action.icons` 每一项取 `Pair(icon, resource)` 再 put。
|
||||
// 生成物 `IconData(icon: String, resource: Any?)` 与之一致。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.SetIcons
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class IconsStateSlice(
|
||||
val Icons: Map<String, Any?> = emptyMap(),
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
fun ReduceIcons(
|
||||
State0: IconsStateSlice,
|
||||
Action: Any,
|
||||
): IconsStateSlice = when (Action) {
|
||||
is SetIcons ->
|
||||
State0.copy(Icons = Action.icons.associate { it.icon to it.resource })
|
||||
else -> State0
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// MainQuestReducer.kt —— 主线任务切片(对应 module_10032 的 WZ 状态 + nQ.bsk)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 WZ:5 个字段,toString 名 "MainQuest(...)";copy 是 qsj(5 字段 + 回调)。
|
||||
// 默认:isLoaded=false、quests=emptyList()、rewardedQuests=emptyList()、
|
||||
// eventPassShopItemId=null、lastBattleUpdatedQuests=emptyList()。
|
||||
// 根委派:`(null == ih && new nQ(), ih).bsk(t, n.fpx_1)` → `ih.bsk(t, n.fpx_1)`。
|
||||
// reducer:
|
||||
// VZ → isLoaded=false(动作类无 toString,字段 rsj_1 在 reducer 里不读)
|
||||
// KZ → isLoaded=true(`QuestsLoaded(quests)` 里的 quests 在这一支里没有被读取)
|
||||
// YZ → quests = Expand(action.quests)、rewardedQuests = emptyList()
|
||||
// XZ → quests = 按 id 就地替换,找不到则追加(`Qd(c.me7_1, _.me7_1)`)
|
||||
// ZZ → rewardedQuests = rewardedQuests + action.questId
|
||||
// QZ → eventPassShopItemId = action.shopItemId
|
||||
// tQ → lastBattleUpdatedQuests = action.updatedQuestsData
|
||||
// `Expand`(原 `uQ`):
|
||||
// 每个任务若 `completed && completedCount != 0` 则不保留原项;
|
||||
// 再对 1..completedCount 生成一份 `completed=true、completedCount=该值` 的副本;
|
||||
// 最后按 completed 降序稳定排序(`_Q(aQ)`,aQ = compareValues(n.completed, t.completed))。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.AddRewardedQuest
|
||||
import App.State.MainQuestInfo
|
||||
import App.State.QuestsLoaded
|
||||
import App.State.SetBattleUpdatedQuests
|
||||
import App.State.SetEventPassShopItemId
|
||||
import App.State.SetQuests
|
||||
import App.State.UpdateQuests
|
||||
|
||||
/* ------------------------------------------------------------------ 匿名动作 */
|
||||
|
||||
/** 原 `VZ`:把 isLoaded 置 false(没有 toString / 不在 action_inventory 里)。 */
|
||||
object ResetQuestsLoaded
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class MainQuestStateSlice(
|
||||
val IsLoaded: Boolean = false,
|
||||
val Quests: List<MainQuestInfo> = emptyList(),
|
||||
val RewardedQuests: List<MainQuestInfo> = emptyList(),
|
||||
val EventPassShopItemId: Long? = null,
|
||||
val LastBattleUpdatedQuests: List<Any?> = emptyList(),
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
/** 原 `hQ(c)`:把一份任务副本标记为「已完成第 c 次」。 */
|
||||
private fun MarkCompleted(Quest: MainQuestInfo, Count: Int): MainQuestInfo =
|
||||
Quest.copy(completed = true, completedCount = Count)
|
||||
|
||||
/** 原 `uQ`:把任务按完成次数展开,并按 completed 降序排序。 */
|
||||
private fun Expand(Quests: List<MainQuestInfo>): List<MainQuestInfo> {
|
||||
val Result = mutableListOf<MainQuestInfo>()
|
||||
for (Quest in Quests) {
|
||||
val Count = Quest.completedCount
|
||||
if (!(Quest.completed && Count != 0)) Result += Quest
|
||||
for (Index in 1..Count) Result += MarkCompleted(Quest, Index)
|
||||
}
|
||||
return Result.sortedWith(compareByDescending { it.completed })
|
||||
}
|
||||
|
||||
fun ReduceMainQuest(
|
||||
State0: MainQuestStateSlice,
|
||||
Action: Any,
|
||||
): MainQuestStateSlice = when (Action) {
|
||||
is ResetQuestsLoaded -> State0.copy(IsLoaded = false)
|
||||
is QuestsLoaded -> State0.copy(IsLoaded = true)
|
||||
is SetQuests -> State0.copy(
|
||||
Quests = Expand(Action.quests as List<MainQuestInfo>),
|
||||
RewardedQuests = emptyList(),
|
||||
)
|
||||
is UpdateQuests -> {
|
||||
val Result = State0.Quests.toMutableList()
|
||||
for (Quest in Action.quests) {
|
||||
val Index = Result.indexOfFirst { it.id == Quest.id }
|
||||
if (Index >= 0) Result[Index] = Quest else Result += Quest
|
||||
}
|
||||
State0.copy(Quests = Result)
|
||||
}
|
||||
is AddRewardedQuest -> State0.copy(
|
||||
RewardedQuests = State0.RewardedQuests + (Action.questId as MainQuestInfo),
|
||||
)
|
||||
is SetEventPassShopItemId -> State0.copy(EventPassShopItemId = Action.shopItemId)
|
||||
is SetBattleUpdatedQuests -> State0.copy(
|
||||
LastBattleUpdatedQuests = Action.updatedQuestsData as List<Any?>,
|
||||
)
|
||||
else -> State0
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// QuestCategoriesReducer.kt —— 任务分类切片(对应 module_10032 的 zZ 状态 + SZ.lsh)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 zZ:3 个字段,toString 名 "QuestCategories(...)";copy 是 fsh(3 字段 + 回调)。
|
||||
// 默认:categories=emptyList()、statistic=emptyMap()、statisticLoadedTime=0L(`new Dd(0, 0)` 是 Long)。
|
||||
// 根委派:`th.lsh(t, n.apy_1)`。
|
||||
// reducer:
|
||||
// bZ → categories = action.categories 按 `index` 升序(`xZ(jZ)`,jZ 比较 ze9_1 = index)
|
||||
// qZ → categories = categories - action.category(`Ym` 是 minus 元素)
|
||||
// yZ → isHiddenUpdate ? 不变 : statisticLoadedTime = Long.MAX_VALUE
|
||||
// (`new Dd(-1, 2147483647)` 是 Long 的高低位,即 Long.MAX_VALUE)
|
||||
// $Z → statistic = action.statistic.associateBy { it.questCategoryId }、statisticLoadedTime = Date.now()
|
||||
// `Md()` = 当前毫秒(与 LootBoxesReducer 里的 CurrentTimeMillis 同源)。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.QuestCategoryData
|
||||
import App.State.RemoveQuestCategory
|
||||
import App.State.RequestQuestCategoriesStatistic
|
||||
import App.State.SetQuestCategories
|
||||
import App.State.SetQuestCategoriesStatistic
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class QuestCategoriesStateSlice(
|
||||
val Categories: List<QuestCategoryData> = emptyList(),
|
||||
val Statistic: Map<Long, Any?> = emptyMap(),
|
||||
val StatisticLoadedTime: Long = 0L,
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
private fun CurrentTimeMillis(): Long = kotlin.js.Date.now().toLong()
|
||||
|
||||
fun ReduceQuestCategories(
|
||||
State0: QuestCategoriesStateSlice,
|
||||
Action: Any,
|
||||
): QuestCategoriesStateSlice = when (Action) {
|
||||
is SetQuestCategories ->
|
||||
State0.copy(Categories = Action.categories.sortedBy { it.index })
|
||||
is RemoveQuestCategory ->
|
||||
State0.copy(Categories = State0.Categories - (Action.category as QuestCategoryData))
|
||||
is RequestQuestCategoriesStatistic ->
|
||||
if (Action.isHiddenUpdate) State0
|
||||
else State0.copy(StatisticLoadedTime = Long.MAX_VALUE)
|
||||
is SetQuestCategoriesStatistic -> State0.copy(
|
||||
Statistic = Action.statistic.associateBy { it.questCategoryId },
|
||||
StatisticLoadedTime = CurrentTimeMillis(),
|
||||
)
|
||||
else -> State0
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// ReferralEventReducer.kt —— 推荐活动切片(对应 module_10032 的 pQ 状态 + bQ.osk)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 pQ:14 个字段,toString 名 "ReferralEvent(...)";copy 是 hsk(14 字段 + 回调)。
|
||||
// 默认:referrer=null、referrerUid=null、referralsCount=0、referralsData=emptyMap()、
|
||||
// code=null、referrerPanelTitle=""、promoCodeDialogImage=null、promoCodeDialogBackGround=null、
|
||||
// referrerCategoryId=null、referralCategoryId=null、referralQuestsSize=0、
|
||||
// hideReferrerCategory=true、hideReferralCategory=true、hidedAnnounce=null。
|
||||
// 根委派:`lh.osk(t, n.hpy_1)`。
|
||||
// reducer:
|
||||
// zQ(SetReferrer) → referrer、referrerUid
|
||||
// kQ(SetReferrals) → referralsCount、referralsData
|
||||
// mQ(SetPromoCode) → code
|
||||
// wQ(SetReferralEventData) → 后 9 个字段,来自 ReferralEventUserModelCC
|
||||
// (字段顺序与模型 toString 一致:referrerPanelTitle、promoCodeDialogImage、
|
||||
// promoCodeDialogBackGround、referrerCategory、referralCategory、referralQuestsSize、
|
||||
// hideReferrerCategory、hideReferralCategory、hidedAnnounce)
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.ReferralEventUserModelCC
|
||||
import App.State.SetPromoCode
|
||||
import App.State.SetReferralEventData
|
||||
import App.State.SetReferrals
|
||||
import App.State.SetReferrer
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class ReferralEventStateSlice(
|
||||
val Referrer: Any? = null,
|
||||
val ReferrerUid: Any? = null,
|
||||
val ReferralsCount: Int = 0,
|
||||
val ReferralsData: Map<Any?, Any?> = emptyMap(),
|
||||
val Code: String? = null,
|
||||
val ReferrerPanelTitle: String = "",
|
||||
val PromoCodeDialogImage: Any? = null,
|
||||
val PromoCodeDialogBackGround: Any? = null,
|
||||
val ReferrerCategoryId: Long? = null,
|
||||
val ReferralCategoryId: Long? = null,
|
||||
val ReferralQuestsSize: Int = 0,
|
||||
val HideReferrerCategory: Boolean = true,
|
||||
val HideReferralCategory: Boolean = true,
|
||||
val HidedAnnounce: Long? = null,
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
fun ReduceReferralEvent(
|
||||
State0: ReferralEventStateSlice,
|
||||
Action: Any,
|
||||
): ReferralEventStateSlice = when (Action) {
|
||||
is SetReferrer -> State0.copy(
|
||||
Referrer = Action.referrerId,
|
||||
ReferrerUid = Action.referrerUid,
|
||||
)
|
||||
is SetReferrals -> State0.copy(
|
||||
ReferralsCount = Action.referralsCount,
|
||||
ReferralsData = Action.referralsData as Map<Any?, Any?>,
|
||||
)
|
||||
is SetPromoCode -> State0.copy(Code = Action.code)
|
||||
is SetReferralEventData -> {
|
||||
val Data: ReferralEventUserModelCC = Action.eventData
|
||||
State0.copy(
|
||||
ReferrerPanelTitle = Data.referrerPanelTitle,
|
||||
PromoCodeDialogImage = Data.promoCodeDialogImage,
|
||||
PromoCodeDialogBackGround = Data.promoCodeDialogBackGround,
|
||||
ReferrerCategoryId = Data.referrerCategory,
|
||||
ReferralCategoryId = Data.referralCategory,
|
||||
ReferralQuestsSize = Data.referralQuestsSize,
|
||||
HideReferrerCategory = Data.hideReferrerCategory,
|
||||
HideReferralCategory = Data.hideReferralCategory,
|
||||
HidedAnnounce = Data.hidedAnnounce,
|
||||
)
|
||||
}
|
||||
else -> State0
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// SecuritySettingsReducer.kt —— 账号安全设置切片(对应 module_10032 的 V2 状态 + X2.qsv)
|
||||
//
|
||||
// 证据链:
|
||||
// 状态类 V2:1 个字段,toString 名 "SecuritySettingsState(isProfileBlocked=…)";copy 是 f7j(1 字段)。
|
||||
// 默认:`function V2(t) { t = t === cd || t }` → isProfileBlocked=true。
|
||||
// 根委派:`pc.qsv(t, n.vpx_1)`。
|
||||
// reducer:`t instanceof K2 ? n.f7j(t.osv_1) : n`,`K2` 是 SetProfileBlockStatus。
|
||||
package App.State.Reducers
|
||||
|
||||
import App.State.SetProfileBlockStatus
|
||||
|
||||
/* ------------------------------------------------------------------ 状态 */
|
||||
|
||||
data class SecuritySettingsStateSlice(
|
||||
val IsProfileBlocked: Boolean = true,
|
||||
)
|
||||
|
||||
/* ------------------------------------------------------------------ reducer */
|
||||
|
||||
fun ReduceSecuritySettings(
|
||||
State0: SecuritySettingsStateSlice,
|
||||
Action: Any,
|
||||
): SecuritySettingsStateSlice = when (Action) {
|
||||
is SetProfileBlockStatus -> State0.copy(IsProfileBlocked = Action.isProfileBlocked)
|
||||
else -> State0
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// RootReducer.kt —— 根 reducer 骨架(对应 module_10032 的根状态 z6 / TOState 与根 reducer k6)
|
||||
//
|
||||
// 原包 k6 对 89 个切片逐个调用各自的 reducer,再 `return n.cti(...)`(copy 出新状态)。
|
||||
// 这里采用同一形状。已迁移的 28 个切片里,27 个真正调用 reducer,launchParams 只做类型收口:
|
||||
// 这里采用同一形状。已迁移的 33 个切片里,32 个真正调用 reducer,launchParams 只做类型收口:
|
||||
//
|
||||
// inviteState → ReduceInvite(aD / pD.er5)
|
||||
// loginByPassword → ReduceLoginByPassword(gD / MD.cr6)
|
||||
@@ -30,9 +30,14 @@
|
||||
// rulesUpdated → ReduceRulesUpdated(i1 / u1.dsm,根委派 `Ch.dsm(t, n.npx_1)`)
|
||||
// notificationByCountry → ReduceNotificationByCountry(gJ / $J.ssd,根委派 `R_.ssd(t, n.ppx_1)`)
|
||||
// availabilityByRank → ReduceAvailabilityByRank(tet / set.xth,根委派 `$p.xth(t, n.cpy_1)`)
|
||||
// icons → ReduceIcons(oH / vs.kru,根委派 `vs.kru(t, n.wpx_1)`)
|
||||
// questCategories → ReduceQuestCategories(zZ / th.lsh,根委派 `th.lsh(t, n.apy_1)`)
|
||||
// mainQuest → ReduceMainQuest(WZ / ih.bsk,根委派 `(null == ih && new nQ(), ih).bsk(t, n.fpx_1)`)
|
||||
// securitySettings → ReduceSecuritySettings(V2 / pc.qsv,根委派 `pc.qsv(t, n.apx_1)`)
|
||||
// referralEvent → ReduceReferralEvent(pQ / lh.osk,根委派 `lh.osk(t, n.hpy_1)`)
|
||||
// launchParams → 无 reducer(原根 reducer 原样透传;默认 `ag()` = emptyMap())
|
||||
//
|
||||
// 其余 61 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 其余 56 个字段按原样透传(defaultValue 取原构造)。每个切片 reducer 对无关动作都返回原状态,
|
||||
// 所以一次 copy 里串起全部已迁移 reducer,与按动作路由再归约的结果一致。
|
||||
// 迁移进度与每个字段的证据见生成物 RootWiring.kt(不要手改)。
|
||||
package App.State
|
||||
@@ -43,11 +48,13 @@ import App.State.Reducers.ReduceEntrance
|
||||
import App.State.Reducers.ReduceGarage
|
||||
import App.State.Reducers.ReduceGaragePreview
|
||||
import App.State.Reducers.ReduceHome
|
||||
import App.State.Reducers.ReduceIcons
|
||||
import App.State.Reducers.ReduceInvite
|
||||
import App.State.Reducers.ReduceLanguage
|
||||
import App.State.Reducers.ReduceLocalBattleUser
|
||||
import App.State.Reducers.ReduceLoginByPassword
|
||||
import App.State.Reducers.ReduceLootBoxes
|
||||
import App.State.Reducers.ReduceMainQuest
|
||||
import App.State.Reducers.ReduceAvailabilityByRank
|
||||
import App.State.Reducers.ReduceLobbyLoader
|
||||
import App.State.Reducers.ReduceNews
|
||||
@@ -56,9 +63,12 @@ import App.State.Reducers.ReduceNotifications
|
||||
import App.State.Reducers.ReduceProBattle
|
||||
import App.State.Reducers.ReducePromoCode
|
||||
import App.State.Reducers.ReducePurchaseDialog
|
||||
import App.State.Reducers.ReduceQuestCategories
|
||||
import App.State.Reducers.ReduceQuests
|
||||
import App.State.Reducers.ReduceReferralEvent
|
||||
import App.State.Reducers.ReduceRulesUpdated
|
||||
import App.State.Reducers.ReduceScreen
|
||||
import App.State.Reducers.ReduceSecuritySettings
|
||||
import App.State.Reducers.ReduceSupportUrl
|
||||
import App.State.Reducers.ReduceSettings
|
||||
import App.State.Reducers.ReduceShop
|
||||
@@ -105,6 +115,11 @@ object RootReducer {
|
||||
RulesUpdated = ReduceRulesUpdated(State0.RulesUpdated, Action),
|
||||
NotificationByCountry = ReduceNotificationByCountry(State0.NotificationByCountry, Action),
|
||||
AvailabilityByRank = ReduceAvailabilityByRank(State0.AvailabilityByRank, Action),
|
||||
Icons = ReduceIcons(State0.Icons, Action),
|
||||
QuestCategories = ReduceQuestCategories(State0.QuestCategories, Action),
|
||||
MainQuest = ReduceMainQuest(State0.MainQuest, Action),
|
||||
SecuritySettings = ReduceSecuritySettings(State0.SecuritySettings, Action),
|
||||
ReferralEvent = ReduceReferralEvent(State0.ReferralEvent, Action),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,20 +11,25 @@ import App.State.Reducers.EntranceStateSlice
|
||||
import App.State.Reducers.GarageStateSlice
|
||||
import App.State.Reducers.GaragePreviewStateSlice
|
||||
import App.State.Reducers.HomeStateSlice
|
||||
import App.State.Reducers.IconsStateSlice
|
||||
import App.State.Reducers.InviteStateSlice
|
||||
import App.State.Reducers.LobbyLoaderStateSlice
|
||||
import App.State.Reducers.LocalBattleUserStateSlice
|
||||
import App.State.Reducers.LoginByPasswordStateSlice
|
||||
import App.State.Reducers.LootBoxesStateSlice
|
||||
import App.State.Reducers.MainQuestStateSlice
|
||||
import App.State.Reducers.NewsStateSlice
|
||||
import App.State.Reducers.NotificationByCountryStateSlice
|
||||
import App.State.Reducers.NotificationsStateSlice
|
||||
import App.State.Reducers.ProBattleStateSlice
|
||||
import App.State.Reducers.PromoCodeStateSlice
|
||||
import App.State.Reducers.PurchaseDialogStateSlice
|
||||
import App.State.Reducers.QuestCategoriesStateSlice
|
||||
import App.State.Reducers.QuestsStateSlice
|
||||
import App.State.Reducers.ReferralEventStateSlice
|
||||
import App.State.Reducers.RulesUpdatedStateSlice
|
||||
import App.State.Reducers.ScreenStateSlice
|
||||
import App.State.Reducers.SecuritySettingsStateSlice
|
||||
import App.State.Reducers.SettingsStateSlice
|
||||
import App.State.Reducers.ShopStateSlice
|
||||
import App.State.Reducers.SupportUrlStateSlice
|
||||
@@ -144,8 +149,8 @@ data class RootState(
|
||||
val GraphicsSettings: Any? = null,
|
||||
/** 原 controlSettings(i2 / _2().ess)。未迁移:原样透传。 */
|
||||
val ControlSettings: Any? = null,
|
||||
/** 原 securitySettings(V2 / pc.qsv)。未迁移:原样透传。 */
|
||||
val SecuritySettings: Any? = null,
|
||||
/** 原 securitySettings(V2 / pc.qsv)。已迁移。 */
|
||||
val SecuritySettings: SecuritySettingsStateSlice = SecuritySettingsStateSlice(),
|
||||
/** 原 purchaseDialogState(CO / je.ur2)。已迁移。 */
|
||||
val PurchaseDialogState: PurchaseDialogStateSlice = PurchaseDialogStateSlice(),
|
||||
/** 原 battleInviteState(att / Ttt().nth)。未迁移:原样透传。 */
|
||||
@@ -154,8 +159,8 @@ data class RootState(
|
||||
val KeyboardSettings: Any? = null,
|
||||
/** 原 touchscreenHudSettings(j7 / N7().xsv)。未迁移:原样透传。 */
|
||||
val TouchscreenHudSettings: Any? = null,
|
||||
/** 原 mainQuest(WZ / ih.bsk)。未迁移:原样透传。 */
|
||||
val MainQuest: Any? = null,
|
||||
/** 原 mainQuest(WZ / ih.bsk)。已迁移。 */
|
||||
val MainQuest: MainQuestStateSlice = MainQuestStateSlice(),
|
||||
/** 原 language(? / m6().jtg)。已迁移。 */
|
||||
val Language: Language = App.State.Language.EN,
|
||||
/** 原 launchParams(? / (pass-through))。已迁移(透传,强类型)。 */
|
||||
@@ -188,16 +193,16 @@ data class RootState(
|
||||
val RewardedVideosState: Any? = null,
|
||||
/** 原 twitchState(g9 / uf.gta)。已迁移。 */
|
||||
val TwitchState: TwitchStateSlice = TwitchStateSlice(),
|
||||
/** 原 icons(oH / vs.kru)。未迁移:原样透传。 */
|
||||
val Icons: Any? = null,
|
||||
/** 原 icons(oH / vs.kru)。已迁移。 */
|
||||
val Icons: IconsStateSlice = IconsStateSlice(),
|
||||
/** 原 itemNotifications(_1 / A1().dso)。未迁移:原样透传。 */
|
||||
val ItemNotifications: Any? = null,
|
||||
/** 原 contextTutorial(Mst / Jst().tth)。未迁移:原样透传。 */
|
||||
val ContextTutorial: Any? = null,
|
||||
/** 原 suppliesTutorial(? / Uw.uth)。未迁移:原样透传。 */
|
||||
val SuppliesTutorial: Any? = null,
|
||||
/** 原 questCategories(zZ / th.lsh)。未迁移:原样透传。 */
|
||||
val QuestCategories: Any? = null,
|
||||
/** 原 questCategories(zZ / th.lsh)。已迁移。 */
|
||||
val QuestCategories: QuestCategoriesStateSlice = QuestCategoriesStateSlice(),
|
||||
/** 原 proBattle(Wtt / uv.wth)。已迁移。 */
|
||||
val ProBattle: ProBattleStateSlice = ProBattleStateSlice(),
|
||||
/** 原 availabilityByRank(tet / $p.xth)。已迁移。 */
|
||||
@@ -210,8 +215,8 @@ data class RootState(
|
||||
val ContractState: Any? = null,
|
||||
/** 原 promoCode(cZ / Q_.ysg)。已迁移。 */
|
||||
val PromoCode: PromoCodeStateSlice = PromoCodeStateSlice(),
|
||||
/** 原 referralEvent(pQ / lh.osk)。未迁移:原样透传。 */
|
||||
val ReferralEvent: Any? = null,
|
||||
/** 原 referralEvent(pQ / lh.osk)。已迁移。 */
|
||||
val ReferralEvent: ReferralEventStateSlice = ReferralEventStateSlice(),
|
||||
/** 原 supportUrl(I4 / Yl.ct7)。已迁移。 */
|
||||
val SupportUrl: SupportUrlStateSlice = SupportUrlStateSlice(),
|
||||
)
|
||||
@@ -73,7 +73,7 @@ object RootWiring {
|
||||
SliceWiring("battleInviteState", "cpx_1", "att", "Ttt().nth", "Ttt().nth(t, n.cpx_1)", listOf("?dtt", "EnableSetBattleInviteNotifications", "InvitationResponse", "InviteToBattle", "RemoveUserFromInvited", "SelectUserToInvite")),
|
||||
SliceWiring("keyboardSettings", "dpx_1", "Sut", "bw.oth", "bw.oth(t, n.dpx_1)", listOf("?Iut", "?_C", "ChangeAction", "RemoveAction", "ResetAction")),
|
||||
SliceWiring("touchscreenHudSettings", "epx_1", "j7", "N7().xsv", "N7().xsv(t, n.epx_1)", listOf("?E7", "?_C", "UpdateSettings")),
|
||||
SliceWiring("mainQuest", "fpx_1", "WZ", "ih.bsk", "ih.bsk(t, n.fpx_1)", listOf("?VZ", "AddRewardedQuest", "QuestsLoaded", "SetBattleUpdatedQuests", "SetEventPassShopItemId", "SetQuests", "UpdateQuests")),
|
||||
SliceWiring("mainQuest", "fpx_1", "WZ", "ih.bsk", "ih.bsk(t, n.fpx_1)", listOf("AddRewardedQuest", "QuestsLoaded", "ResetQuestsLoaded", "SetBattleUpdatedQuests", "SetEventPassShopItemId", "SetQuests", "UpdateQuests")),
|
||||
SliceWiring("language", "gpx_1", "?", "m6().jtg", "m6().jtg(t, n.gpx_1)", listOf("SetLanguage")),
|
||||
SliceWiring("launchParams", "hpx_1", "?", "(pass-through)", "n.hpx_1", listOf()),
|
||||
SliceWiring("partner", "ipx_1", "UJ", "(inline@partner)", "(function (t, n) { var i; if (t instanceof VJ) i = n.osf(t.rsf_1, cd, cd, cd, cd, cd, cd, cd, cd, cd, t.ssf_1); else if (t instanceof nZ) { var r = t.bsg_1, e = t.csg_1, u = t.dsg_1, s = t.esg_1, o = t.fsg_1, _ = t.gsg_1; i = n.osf(cd, cd, cd, r, e, u, cd, cd, o, _, s); } else i = t instanceof iZ ? n.osf(cd, t.hsg_1) : t instanceof uZ ? n.osf(cd, cd, t.ksg_1) : t instanceof eZ ? n.osf(cd, cd, cd, cd, cd, cd, cd, t.jsg_1) : t instanceof _Z ? n.osf(cd, cd, cd, cd, cd, cd, t.osg_1) : t instanceof X …", listOf("?JJ", "?_Z", "?hZ", "?tZ", "InitPartnerInviteAction", "InitSocialNetworkParameters", "SetLoginParams", "SetLoginStatusForBinding", "SetPartnerId", "SetPartnerParameters", "SetPartnerReady")),
|
||||
@@ -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")
|
||||
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")
|
||||
|
||||
/** 未迁移字段:归约时原样透传,作为后续迁移清单。 */
|
||||
val Unmigrated: List<SliceWiring> get() = All.filter { it.Field !in Migrated }
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
// ⑥ 动作目录:816 个类与 138 个真实派发名对齐
|
||||
// ⑦ 回放:真实 toString 样例的类/字段/类型校验
|
||||
// ⑧ 全目录动作类都能按 KClass 路由
|
||||
// ⑨~㊳ 切片 reducer:InviteState / LoginByPasswordState / TwitchState / HomeScreen / LocalBattleUserState /
|
||||
// ⑨~㊸ 切片 reducer:InviteState / LoginByPasswordState / TwitchState / HomeScreen / LocalBattleUserState /
|
||||
// Shop(含 U7 类别表与 w3 物品表两个子 reducer)/ Screen / LootBoxes / Garage / GaragePreview / Entrance / User / Settings /
|
||||
// AccountSettings / ProBattle / Language / Announcement / News / Notifications / Quests /
|
||||
// LobbyLoader / PurchaseDialogState / PromoCode / SupportUrl / RulesUpdated / NotificationByCountry / AvailabilityByRank;
|
||||
// LobbyLoader / PurchaseDialogState / PromoCode / SupportUrl / RulesUpdated / NotificationByCountry / AvailabilityByRank /
|
||||
// Icons / QuestCategories / MainQuest / SecuritySettings / ReferralEvent;
|
||||
// ㉑ launchParams 是纯透传切片(无 reducer/动作),只做 Map 类型收口;⑭ 根 reducer 的 89 槽位委派
|
||||
//
|
||||
// 用法:$env:TANKIOFFLINE_STATE_TEST='1'; node …(见 TankiOffline/tools/RunStateTest.ps1)
|
||||
@@ -355,6 +356,38 @@ import App.State.Reducers.ResetPurchaseDialog
|
||||
import App.State.Reducers.RulesUpdatedStateSlice
|
||||
import App.State.Reducers.ShowLoader
|
||||
import App.State.Reducers.SupportUrlStateSlice
|
||||
import App.State.IconData
|
||||
import App.State.SetIcons
|
||||
import App.State.Reducers.IconsStateSlice
|
||||
import App.State.Reducers.ReduceIcons
|
||||
import App.State.QuestCategoryData
|
||||
import App.State.QuestCategoryStatistic
|
||||
import App.State.RemoveQuestCategory
|
||||
import App.State.RequestQuestCategoriesStatistic
|
||||
import App.State.SetQuestCategories
|
||||
import App.State.SetQuestCategoriesStatistic
|
||||
import App.State.Reducers.QuestCategoriesStateSlice
|
||||
import App.State.Reducers.ReduceQuestCategories
|
||||
import App.State.AddRewardedQuest
|
||||
import App.State.MainQuestInfo
|
||||
import App.State.QuestsLoaded
|
||||
import App.State.SetBattleUpdatedQuests
|
||||
import App.State.SetEventPassShopItemId
|
||||
import App.State.SetQuests
|
||||
import App.State.UpdateQuests
|
||||
import App.State.Reducers.MainQuestStateSlice
|
||||
import App.State.Reducers.ReduceMainQuest
|
||||
import App.State.Reducers.ResetQuestsLoaded
|
||||
import App.State.SetProfileBlockStatus
|
||||
import App.State.Reducers.ReduceSecuritySettings
|
||||
import App.State.Reducers.SecuritySettingsStateSlice
|
||||
import App.State.ReferralEventUserModelCC
|
||||
import App.State.SetPromoCode
|
||||
import App.State.SetReferralEventData
|
||||
import App.State.SetReferrals
|
||||
import App.State.SetReferrer
|
||||
import App.State.Reducers.ReduceReferralEvent
|
||||
import App.State.Reducers.ReferralEventStateSlice
|
||||
import App.State.Reducers.UserRankBounds
|
||||
import App.State.Reducers.UserStateSlice
|
||||
import App.State.Reducers.ClearHullData
|
||||
@@ -782,7 +815,7 @@ object StateCheck {
|
||||
Check("切片 LocalBattleUser:接 Store 派发后状态已归约", Store.State.IsReArmorTemporaryDisabled)
|
||||
}
|
||||
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 28 个已迁移切片(27 归约 + launchParams 透传)
|
||||
// ⑭ 根 reducer:89 个槽位的委派表 + 33 个已迁移切片(32 归约 + launchParams 透传)
|
||||
run {
|
||||
Check("根:根状态 89 个切片槽位", RootWiring.All.size == 89)
|
||||
Check(
|
||||
@@ -846,7 +879,7 @@ object StateCheck {
|
||||
LocalBattleW.Reducer == "(inline@localBattleUserState)"
|
||||
)
|
||||
Check(
|
||||
"根:迁移表 = 28 个已迁移字段,其余 61 个待迁",
|
||||
"根:迁移表 = 33 个已迁移字段,其余 56 个待迁",
|
||||
RootReducer.Migrated ==
|
||||
setOf(
|
||||
"inviteState", "loginByPassword", "twitchState", "home",
|
||||
@@ -856,8 +889,9 @@ object StateCheck {
|
||||
"news", "notifications", "quests",
|
||||
"lobbyLoader", "purchaseDialogState", "promoCode", "supportUrl",
|
||||
"rulesUpdated", "notificationByCountry", "availabilityByRank",
|
||||
"icons", "questCategories", "mainQuest", "securitySettings", "referralEvent",
|
||||
) &&
|
||||
RootWiring.Unmigrated.size == 61
|
||||
RootWiring.Unmigrated.size == 56
|
||||
)
|
||||
|
||||
// 一次 ReduceRoot 里多个切片各归约自己的动作,互不串片
|
||||
@@ -913,7 +947,7 @@ object StateCheck {
|
||||
S5.User.Uid == "user-1" && S5.Screen.Current == NamedScreen("Preloader")
|
||||
)
|
||||
Check("根:无关动作返回等值状态", ReduceRoot(S5, AddFrags(1)) == S5)
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 28/89")
|
||||
Check("根:Coverage 文本", RootReducer.Coverage == "已迁移 33/89")
|
||||
|
||||
val Store = ReduxStore(RootState(), { S, A -> ReduceRoot(S, A) })
|
||||
Store.Dispatch(SetStatus("LOGGING_IN"))
|
||||
@@ -3367,6 +3401,269 @@ object StateCheck {
|
||||
)
|
||||
}
|
||||
|
||||
// ㊴ 切片 reducer:Icons(oH / vs.kru,1 字段;_H → SetIcons)
|
||||
run {
|
||||
val S0 = IconsStateSlice()
|
||||
Check("切片 Icons:默认空表", S0.Icons.isEmpty())
|
||||
val S1 = ReduceIcons(
|
||||
S0,
|
||||
SetIcons(listOf(IconData("rank", "r1"), IconData("gold", "r2"))),
|
||||
)
|
||||
Check(
|
||||
"切片 Icons:SetIcons 建成 icon→resource 表",
|
||||
S1.Icons == mapOf<String, Any?>("rank" to "r1", "gold" to "r2")
|
||||
)
|
||||
Check("切片 Icons:无关动作不改状态", ReduceIcons(S1, AddFrags(1)) == S1)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, SetIcons(listOf(IconData("a", null))))
|
||||
Check(
|
||||
"根:SetIcons 只动 icons",
|
||||
Root1.Icons.Icons.keys == setOf("a") &&
|
||||
Root1.QuestCategories == Root0.QuestCategories
|
||||
)
|
||||
val W = RootWiring.ByField("icons")!!
|
||||
Check(
|
||||
"根:icons 委派到 oH / vs.kru 且 1 个动作",
|
||||
W.SliceClass == "oH" && W.Reducer == "vs.kru" && W.Actions == listOf("SetIcons")
|
||||
)
|
||||
}
|
||||
|
||||
// ㊵ 切片 reducer:QuestCategories(zZ / th.lsh,3 字段;4 个实例臂)
|
||||
run {
|
||||
fun Cat(Id: Long, Index: Int): QuestCategoryData = QuestCategoryData(
|
||||
color = "", description = "", endDate = null, hideIfEmpty = false, id = Id,
|
||||
image = null, index = Index, name = "c$Id", rankRange = "", min = "",
|
||||
startDate = null, type = "",
|
||||
)
|
||||
|
||||
val A = Cat(1L, 2)
|
||||
val B = Cat(2L, 1)
|
||||
val S0 = QuestCategoriesStateSlice()
|
||||
Check(
|
||||
"切片 QuestCategories:默认空表、加载时间 0",
|
||||
S0.Categories.isEmpty() && S0.Statistic.isEmpty() && S0.StatisticLoadedTime == 0L
|
||||
)
|
||||
val S1 = ReduceQuestCategories(S0, SetQuestCategories(listOf(A, B)))
|
||||
Check(
|
||||
"切片 QuestCategories:SetQuestCategories 按 index 升序",
|
||||
S1.Categories == listOf(B, A)
|
||||
)
|
||||
Check(
|
||||
"切片 QuestCategories:RemoveQuestCategory 按对象删除",
|
||||
ReduceQuestCategories(S1, RemoveQuestCategory(B)).Categories == listOf(A)
|
||||
)
|
||||
Check(
|
||||
"切片 QuestCategories:隐藏刷新不改加载时间",
|
||||
ReduceQuestCategories(S1, RequestQuestCategoriesStatistic(true)) == S1
|
||||
)
|
||||
Check(
|
||||
"切片 QuestCategories:强制刷新把加载时间推到 Long.MAX_VALUE",
|
||||
ReduceQuestCategories(S1, RequestQuestCategoriesStatistic(false))
|
||||
.StatisticLoadedTime == Long.MAX_VALUE
|
||||
)
|
||||
val S2 = ReduceQuestCategories(
|
||||
S1,
|
||||
SetQuestCategoriesStatistic(
|
||||
listOf(
|
||||
QuestCategoryStatistic(nearEndTime = null, questCategoryId = 1L, quests = 3),
|
||||
QuestCategoryStatistic(nearEndTime = 5L, questCategoryId = 2L, quests = 4),
|
||||
)
|
||||
),
|
||||
)
|
||||
Check(
|
||||
"切片 QuestCategories:统计按 questCategoryId 建索引并写当前时间",
|
||||
S2.Statistic.keys == setOf(1L, 2L) && S2.StatisticLoadedTime > 0L
|
||||
)
|
||||
Check("切片 QuestCategories:无关动作不改状态", ReduceQuestCategories(S2, AddFrags(1)) == S2)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, SetQuestCategories(listOf(A)))
|
||||
Check(
|
||||
"根:SetQuestCategories 只动 questCategories",
|
||||
Root1.QuestCategories.Categories == listOf(A) && Root1.MainQuest == Root0.MainQuest
|
||||
)
|
||||
val W = RootWiring.ByField("questCategories")!!
|
||||
Check(
|
||||
"根:questCategories 委派到 zZ / th.lsh 且 4 个动作",
|
||||
W.SliceClass == "zZ" && W.Reducer == "th.lsh" &&
|
||||
W.Actions.toSet() == setOf(
|
||||
"SetQuestCategories", "RemoveQuestCategory",
|
||||
"RequestQuestCategoriesStatistic", "SetQuestCategoriesStatistic",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// ㊶ 切片 reducer:MainQuest(WZ / ih.bsk,5 字段;7 个动作,含 VZ→ResetQuestsLoaded)
|
||||
run {
|
||||
fun Quest(
|
||||
Id: Long,
|
||||
Name: String = "q$Id",
|
||||
Completed: Boolean = false,
|
||||
Count: Int = 0,
|
||||
): MainQuestInfo = MainQuestInfo(
|
||||
action = "", actionParams = null, activateTime = null, active = true,
|
||||
battlePass = false, categoryId = 1L, completed = Completed, completedCount = Count,
|
||||
conditions = null, battleMode = null, contextItemsInfo = null, id = Id, name = Name,
|
||||
quantity = 1, skipForShowProgress = false, type = "", depends = emptyList(),
|
||||
description = "", durationInMinutes = 0, eventPass = false,
|
||||
extendedPeriodicalEndTime = null, extendedPeriodicalStartTime = null, icon = null,
|
||||
minRank = 0, oneTime = false, pinned = false, premium = false, progress = null,
|
||||
rewardExpireTime = null, rewards = "", count = 1, preview = null,
|
||||
skipNewNotification = false, sortedIndex = 0, startTime = 0L, COMPLETE_QUEST = "",
|
||||
)
|
||||
|
||||
val Q1 = Quest(1L)
|
||||
val Q2 = Quest(2L, "q2", Completed = true, Count = 2)
|
||||
val S0 = MainQuestStateSlice()
|
||||
Check(
|
||||
"切片 MainQuest:默认未加载、三个列表为空、活动商品 id 为 null",
|
||||
!S0.IsLoaded && S0.Quests.isEmpty() && S0.RewardedQuests.isEmpty() &&
|
||||
S0.EventPassShopItemId == null && S0.LastBattleUpdatedQuests.isEmpty()
|
||||
)
|
||||
val L1 = ReduceMainQuest(S0, QuestsLoaded(listOf(Q1)))
|
||||
Check("切片 MainQuest:QuestsLoaded 只置 isLoaded", L1.IsLoaded && L1.Quests.isEmpty())
|
||||
Check(
|
||||
"切片 MainQuest:ResetQuestsLoaded 复位 isLoaded",
|
||||
!ReduceMainQuest(L1, ResetQuestsLoaded).IsLoaded
|
||||
)
|
||||
|
||||
val S1 = ReduceMainQuest(S0, SetQuests(listOf(Q1, Q2)))
|
||||
Check(
|
||||
"切片 MainQuest:SetQuests 按完成次数展开并清空已领奖",
|
||||
S1.Quests.size == 3 &&
|
||||
S1.Quests[0].completed && S1.Quests[0].completedCount == 1 &&
|
||||
S1.Quests[1].completed && S1.Quests[1].completedCount == 2 &&
|
||||
S1.Quests[2].id == 1L && !S1.Quests[2].completed &&
|
||||
S1.RewardedQuests.isEmpty()
|
||||
)
|
||||
|
||||
val S2 = ReduceMainQuest(S1, UpdateQuests(listOf(Quest(1L, "q1-new"), Quest(3L))))
|
||||
Check(
|
||||
"切片 MainQuest:UpdateQuests 按 id 就地替换、缺失追加",
|
||||
S2.Quests.size == 4 && S2.Quests[2].name == "q1-new" && S2.Quests[3].id == 3L
|
||||
)
|
||||
|
||||
val S3 = ReduceMainQuest(S2, AddRewardedQuest(Q1))
|
||||
Check(
|
||||
"切片 MainQuest:AddRewardedQuest 追加到已领奖列表",
|
||||
S3.RewardedQuests == listOf(Q1)
|
||||
)
|
||||
Check(
|
||||
"切片 MainQuest:SetEventPassShopItemId 写商品 id",
|
||||
ReduceMainQuest(S3, SetEventPassShopItemId(77L)).EventPassShopItemId == 77L
|
||||
)
|
||||
Check(
|
||||
"切片 MainQuest:SetBattleUpdatedQuests 写战斗增量",
|
||||
ReduceMainQuest(S3, SetBattleUpdatedQuests(listOf("x")))
|
||||
.LastBattleUpdatedQuests == listOf<Any?>("x")
|
||||
)
|
||||
Check("切片 MainQuest:无关动作不改状态", ReduceMainQuest(S3, AddFrags(1)) == S3)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, SetEventPassShopItemId(9L))
|
||||
Check(
|
||||
"根:SetEventPassShopItemId 只动 mainQuest",
|
||||
Root1.MainQuest.EventPassShopItemId == 9L && Root1.Icons == Root0.Icons
|
||||
)
|
||||
val W = RootWiring.ByField("mainQuest")!!
|
||||
Check(
|
||||
"根:mainQuest 委派到 WZ / ih.bsk 且 7 个动作(含 ResetQuestsLoaded)",
|
||||
W.SliceClass == "WZ" && W.Reducer == "ih.bsk" &&
|
||||
W.Actions.toSet() == setOf(
|
||||
"ResetQuestsLoaded", "QuestsLoaded", "SetQuests", "UpdateQuests",
|
||||
"AddRewardedQuest", "SetEventPassShopItemId", "SetBattleUpdatedQuests",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// ㊷ 切片 reducer:SecuritySettings(V2 / pc.qsv,1 字段;K2 → SetProfileBlockStatus)
|
||||
run {
|
||||
val S0 = SecuritySettingsStateSlice()
|
||||
Check("切片 SecuritySettings:默认隐藏个人资料", S0.IsProfileBlocked)
|
||||
Check(
|
||||
"切片 SecuritySettings:SetProfileBlockStatus 写布尔",
|
||||
!ReduceSecuritySettings(S0, SetProfileBlockStatus(false)).IsProfileBlocked
|
||||
)
|
||||
Check(
|
||||
"切片 SecuritySettings:无关动作不改状态",
|
||||
ReduceSecuritySettings(S0, AddFrags(1)) == S0
|
||||
)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, SetProfileBlockStatus(false))
|
||||
Check(
|
||||
"根:SetProfileBlockStatus 只动 securitySettings",
|
||||
!Root1.SecuritySettings.IsProfileBlocked && Root1.ReferralEvent == Root0.ReferralEvent
|
||||
)
|
||||
val W = RootWiring.ByField("securitySettings")!!
|
||||
Check(
|
||||
"根:securitySettings 委派到 V2 / pc.qsv",
|
||||
W.SliceClass == "V2" && W.Reducer == "pc.qsv" &&
|
||||
W.Actions == listOf("SetProfileBlockStatus")
|
||||
)
|
||||
}
|
||||
|
||||
// ㊸ 切片 reducer:ReferralEvent(pQ / lh.osk,14 字段;4 个实例臂)
|
||||
run {
|
||||
val S0 = ReferralEventStateSlice()
|
||||
Check(
|
||||
"切片 ReferralEvent:默认值完整",
|
||||
S0.Referrer == null && S0.ReferrerUid == null && S0.ReferralsCount == 0 &&
|
||||
S0.ReferralsData.isEmpty() && S0.Code == null && S0.ReferrerPanelTitle == "" &&
|
||||
S0.ReferralQuestsSize == 0 && S0.HideReferrerCategory &&
|
||||
S0.HideReferralCategory && S0.HidedAnnounce == null
|
||||
)
|
||||
val S1 = ReduceReferralEvent(S0, SetReferrer("rid", "ruid"))
|
||||
Check(
|
||||
"切片 ReferralEvent:SetReferrer 写前两字段",
|
||||
S1.Referrer == "rid" && S1.ReferrerUid == "ruid" && S1.ReferralsCount == 0
|
||||
)
|
||||
val S2 = ReduceReferralEvent(S1, SetReferrals(5, mapOf<Any?, Any?>("a" to 1)))
|
||||
Check(
|
||||
"切片 ReferralEvent:SetReferrals 写人数与明细",
|
||||
S2.ReferralsCount == 5 && S2.ReferralsData == mapOf<Any?, Any?>("a" to 1)
|
||||
)
|
||||
Check(
|
||||
"切片 ReferralEvent:SetPromoCode 写邀请码",
|
||||
ReduceReferralEvent(S2, SetPromoCode("CODE")).Code == "CODE"
|
||||
)
|
||||
val Data = ReferralEventUserModelCC(
|
||||
hideReferralCategory = false, hideReferrerCategory = false, hidedAnnounce = 3L,
|
||||
promoCodeDialogBackGround = "bg", promoCodeDialogImage = "img",
|
||||
referralCategory = 7L, referralQuestsSize = 4, referrerCategory = 8L,
|
||||
referrerPanelTitle = "title",
|
||||
)
|
||||
val S3 = ReduceReferralEvent(S2, SetReferralEventData(Data))
|
||||
Check(
|
||||
"切片 ReferralEvent:SetReferralEventData 写后 9 个字段",
|
||||
S3.ReferrerPanelTitle == "title" && S3.PromoCodeDialogImage == "img" &&
|
||||
S3.PromoCodeDialogBackGround == "bg" && S3.ReferrerCategoryId == 8L &&
|
||||
S3.ReferralCategoryId == 7L && S3.ReferralQuestsSize == 4 &&
|
||||
!S3.HideReferrerCategory && !S3.HideReferralCategory &&
|
||||
S3.HidedAnnounce == 3L && S3.Referrer == "rid" && S3.ReferralsCount == 5
|
||||
)
|
||||
Check(
|
||||
"切片 ReferralEvent:无关动作不改状态",
|
||||
ReduceReferralEvent(S3, AddFrags(1)) == S3
|
||||
)
|
||||
|
||||
val Root0 = RootState()
|
||||
val Root1 = ReduceRoot(Root0, SetPromoCode("X"))
|
||||
Check(
|
||||
"根:SetPromoCode 只动 referralEvent",
|
||||
Root1.ReferralEvent.Code == "X" && Root1.SecuritySettings == Root0.SecuritySettings
|
||||
)
|
||||
val W = RootWiring.ByField("referralEvent")!!
|
||||
Check(
|
||||
"根:referralEvent 委派到 pQ / lh.osk 且 4 个动作",
|
||||
W.SliceClass == "pQ" && W.Reducer == "lh.osk" &&
|
||||
W.Actions.toSet() == setOf(
|
||||
"SetReferrer", "SetReferrals", "SetPromoCode", "SetReferralEventData",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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