v0.12: 存档迁移钩子 + 考古日志滚动条(差异化叙事)
gameStore persist: - name v1→v2, 加 version:2 + migrate 钩子 - migrate 合并旧存档与 INITIAL_STATE, 补全 bossKills/starTidesEncountered/ chronicle/attributes/activeExpedition/constellation 等字段, 防旧存档崩溃 - 丢弃不可解的活跃谜题(旧算法生成) archaeoLog.ts (新增): - 5 阶段日志池 dawn/awakening/contact/ascension/deep (48 条) - 按飞升次数+接触进度解锁阶段, deep 层含哲学反转 - pickLogEntry 避免短期重复(最近8条) ArchaeoLogTicker.tsx (新增): - marquee 横向滚动, 18-30s 随机推送新条目 - 阶段色标 emerald/amber/fuchsia/rose, inset glow - 进度里程碑触发即时刷新(解锁新阶段) - prefers-reduced-motion 降级 page.tsx: - footer 上方集成 ArchaeoLogTicker globals.css: - echo-ticker-marquee/fade keyframes + reduced-motion 降级 调研落地: Antimatter Dimensions news ticker + Universal Paperclips 哲学递进 lint 零错误, 构建成功(5.7s)
This commit is contained in:
+41
-1
@@ -1339,8 +1339,48 @@ export const useGameStore = create<Store>()(
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: "echo-nexus-save-v1",
|
||||
name: "echo-nexus-save-v2",
|
||||
version: 2,
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
// v0.12 存档迁移:旧存档(v0/v1,key=echo-nexus-save-v1)补全新增字段,防崩溃
|
||||
migrate: (persistedState: unknown, version: number) => {
|
||||
void version; // v0/v1 统一走合并迁移,无需分支
|
||||
const s = (persistedState || {}) as Record<string, unknown>;
|
||||
const base = createInitialState();
|
||||
// 合并:以当前 INITIAL_STATE 为基底,旧存档字段覆盖,缺失字段用默认值
|
||||
const migrated = {
|
||||
...base,
|
||||
...s,
|
||||
// v0.8+ 新增字段兜底
|
||||
bossKills: (s.bossKills as number) ?? 0,
|
||||
starTidesEncountered: (s.starTidesEncountered as string[]) ?? [],
|
||||
chronicle: (s.chronicle as unknown[]) ?? [],
|
||||
runStart: (s.runStart as number) ?? Date.now(),
|
||||
// v0.8.2 attributes 系统
|
||||
attributes: (s.attributes as Record<string, number>) ?? base.attributes,
|
||||
attributeProgress: (s.attributeProgress as unknown) ?? base.attributeProgress,
|
||||
pendingAttrPoints: (s.pendingAttrPoints as number) ?? 0,
|
||||
// v0.10 探险系统字段兜底
|
||||
activeExpedition: (s.activeExpedition as unknown) ?? null,
|
||||
totalExpeditions: (s.totalExpeditions as number) ?? 0,
|
||||
lastExpeditionSummary: (s.lastExpeditionSummary as unknown) ?? null,
|
||||
// 星图兜底
|
||||
constellation: (s.constellation as string[]) ?? [],
|
||||
pendingPerkChoices: (s.pendingPerkChoices as unknown[]) ?? [],
|
||||
// 技术树/碎片/成就兜底(防旧存档为 undefined)
|
||||
tech: (s.tech as Record<string, number>) ?? {},
|
||||
fragments: (s.fragments as Record<string, boolean>) ?? {},
|
||||
achievements: (s.achievements as Record<string, boolean>) ?? {},
|
||||
} as GameState;
|
||||
// 丢弃不可解的活跃谜题(旧算法生成)
|
||||
if (migrated.activePuzzle && typeof migrated.activePuzzle === "object") {
|
||||
const p = migrated.activePuzzle as { nodes?: unknown[] };
|
||||
if (!p.nodes || !Array.isArray(p.nodes) || p.nodes.length === 0) {
|
||||
migrated.activePuzzle = null;
|
||||
}
|
||||
}
|
||||
return migrated;
|
||||
},
|
||||
// 不持久化临时字段
|
||||
partialize: (s) => {
|
||||
const { _lastAutoDecode, _lastSpawn, _combo, _lastPulse, _achievementQueue, _tideEvents, globalTide, ...rest } = s;
|
||||
|
||||
Reference in New Issue
Block a user