feat:碎片完善

This commit is contained in:
zhongyidian committed 2026-01-11 18:18:20 +08:00
1 parent ec7e8e2bd2
commit 046501705f
74 files changed
+1602 -172

No files matched your search

+142
View File
@@ -0,0 +1,142 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";
interface ChenyunStore {
// 存储每个场景(place)的已访问展品ID集合
// 格式:{ place1: Set<1, 2>, place2: Set<1, 2>, ... }
visitedExhibits: Record<string, Set<number>>;
// 标记展品为已访问
markExhibitVisited: (place: string, exhibitId: number) => void;
// 检查展品是否已访问
isExhibitVisited: (place: string, exhibitId: number) => boolean;
// 获取某个场景已访问的展品ID数组
getVisitedExhibits: (place: string) => number[];
// 重置某个场景的访问记录
resetPlace: (place: string) => void;
// 重置所有访问记录
resetAll: () => void;
// ========== 体悟模块状态 ==========
// 银元之战是否已解决
isYinyuanSolved: boolean;
// 设置银元之战解决状态
setYinyuanSolved: (solved: boolean) => void;
// 米棉之战是否已解决
isMimianSolved: boolean;
// 设置米棉之战解决状态
setMimianSolved: (solved: boolean) => void;
}
// 将 Set 转换为数组以便序列化
const serializeVisitedExhibits = (
visitedExhibits: Record<string, Set<number>>
): Record<string, number[]> => {
const serialized: Record<string, number[]> = {};
for (const [place, exhibits] of Object.entries(visitedExhibits)) {
serialized[place] = Array.from(exhibits);
}
return serialized;
};
// 将数组转换回 Set
const deserializeVisitedExhibits = (
serialized: Record<string, number[]> | undefined
): Record<string, Set<number>> => {
if (!serialized || typeof serialized !== "object") {
return {};
}
const visitedExhibits: Record<string, Set<number>> = {};
for (const [place, exhibits] of Object.entries(serialized)) {
if (Array.isArray(exhibits)) {
visitedExhibits[place] = new Set(exhibits);
} else {
visitedExhibits[place] = new Set();
}
}
return visitedExhibits;
};
export const useChenyunStore = create<ChenyunStore>()(
persist(
(set, get) => ({
visitedExhibits: {},
markExhibitVisited: (place: string, exhibitId: number) => {
set((state) => {
const currentExhibits =
state.visitedExhibits[place] || new Set<number>();
if (!currentExhibits.has(exhibitId)) {
const newExhibits = {
...state.visitedExhibits,
[place]: new Set([...currentExhibits, exhibitId]),
};
return { visitedExhibits: newExhibits };
}
return state;
});
},
isExhibitVisited: (place: string, exhibitId: number) => {
const { visitedExhibits } = get();
return visitedExhibits[place]?.has(exhibitId) || false;
},
getVisitedExhibits: (place: string) => {
const { visitedExhibits } = get();
return Array.from(visitedExhibits[place] || []);
},
resetPlace: (place: string) => {
set((state) => {
const newExhibits = { ...state.visitedExhibits };
delete newExhibits[place];
return { visitedExhibits: newExhibits };
});
},
resetAll: () => {
set({ visitedExhibits: {} });
},
// ========== 体悟模块状态 ==========
isYinyuanSolved: false,
setYinyuanSolved: (solved: boolean) => {
set({ isYinyuanSolved: solved });
},
isMimianSolved: false,
setMimianSolved: (solved: boolean) => {
set({ isMimianSolved: solved });
},
}),
{
name: "chenyun-storage", // localStorage key
partialize: (state) => ({
visitedExhibits: serializeVisitedExhibits(state.visitedExhibits),
isYinyuanSolved: state.isYinyuanSolved,
isMimianSolved: state.isMimianSolved,
}),
onRehydrateStorage: () => (state) => {
if (state) {
// 确保反序列化后的数据格式正确
state.visitedExhibits = deserializeVisitedExhibits(
state.visitedExhibits as any
);
// 确保解决状态有默认值
if (state.isYinyuanSolved === undefined) {
state.isYinyuanSolved = false;
}
if (state.isMimianSolved === undefined) {
state.isMimianSolved = false;
}
}
},
}
)
);
+152
View File
@@ -0,0 +1,152 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";
interface PuzzleStore {
// 每个故居的已解锁碎片集合,格式:{ residence: Set<pieceId> }
puzzles: Record<string, Set<number>>;
// 解锁碎片
unlockPuzzle: (residence: string, pieceId: number) => void;
// 检查碎片是否解锁
isPuzzleUnlocked: (residence: string, pieceId: number) => boolean;
// 获取已解锁碎片列表
getUnlockedPuzzles: (residence: string) => number[];
// 重置指定故居的所有碎片
resetPuzzles: (residence: string) => void;
// 获取收集进度
getPuzzleCollectProgress: (residence: string) => number;
}
// 将 Set 转换为数组以便序列化
const serializePuzzles = (puzzles: Record<string, Set<number>>) => {
const serialized: Record<string, number[]> = {};
for (const [residence, pieces] of Object.entries(puzzles)) {
serialized[residence] = Array.from(pieces);
}
return serialized;
};
// 将数组转换回 Set
const deserializePuzzles = (
serialized: Record<string, number[]> | undefined
) => {
if (!serialized || typeof serialized !== "object") {
return {};
}
const puzzles: Record<string, Set<number>> = {};
for (const [residence, pieces] of Object.entries(serialized)) {
// 确保 pieces 是数组
if (Array.isArray(pieces)) {
puzzles[residence] = new Set(pieces);
} else {
// 如果格式不对,创建新的 Set
puzzles[residence] = new Set();
}
}
return puzzles;
};
// 辅助函数:确保 puzzles 中的值都是 Set
const ensurePuzzlesAreSets = (puzzles: any): Record<string, Set<number>> => {
const fixed: Record<string, Set<number>> = {};
if (puzzles && typeof puzzles === "object") {
for (const [residence, pieces] of Object.entries(puzzles)) {
if (pieces instanceof Set) {
fixed[residence] = pieces;
} else if (Array.isArray(pieces)) {
fixed[residence] = new Set(pieces);
} else {
fixed[residence] = new Set();
}
}
}
return fixed;
};
export const usePuzzleStore = create<PuzzleStore>()(
persist(
(set, get) => ({
puzzles: {},
unlockPuzzle: (residence: string, pieceId: number) => {
const { puzzles } = get();
// 确保 puzzles 格式正确
const fixedPuzzles = ensurePuzzlesAreSets(puzzles);
const residencePuzzles = fixedPuzzles[residence] || new Set<number>();
if (!residencePuzzles.has(pieceId)) {
const newPuzzles = { ...fixedPuzzles };
newPuzzles[residence] = new Set([...residencePuzzles, pieceId]);
set({ puzzles: newPuzzles });
}
},
isPuzzleUnlocked: (residence: string, pieceId: number) => {
const { puzzles } = get();
// 确保 puzzles 格式正确
const fixedPuzzles = ensurePuzzlesAreSets(puzzles);
const residencePuzzles = fixedPuzzles[residence];
if (!residencePuzzles) {
return false;
}
return residencePuzzles.has(pieceId);
},
getUnlockedPuzzles: (residence: string) => {
const { puzzles } = get();
// 确保 puzzles 格式正确
const fixedPuzzles = ensurePuzzlesAreSets(puzzles);
const residencePuzzles = fixedPuzzles[residence];
if (!residencePuzzles) {
return [];
}
return Array.from(residencePuzzles);
},
getPuzzleCollectProgress: (residence: string): number => {
const totalPuzzles = 16;
const { puzzles } = get();
const fixedPuzzles = ensurePuzzlesAreSets(puzzles);
const residencePuzzles = fixedPuzzles[residence];
if (!residencePuzzles) {
return 0;
}
return (residencePuzzles.size / totalPuzzles) * 100;
},
resetPuzzles: (residence: string) => {
const { puzzles } = get();
// 确保 puzzles 格式正确
const fixedPuzzles = ensurePuzzlesAreSets(puzzles);
const newPuzzles = { ...fixedPuzzles };
delete newPuzzles[residence];
set({ puzzles: newPuzzles });
},
}),
{
name: "puzzle-storage", // localStorage key
partialize: (state) => ({
puzzles: serializePuzzles(state.puzzles),
}),
merge: (persistedState, currentState) => {
const persisted = persistedState as {
puzzles?: Record<string, number[]>;
};
return {
...currentState,
puzzles: deserializePuzzles(persisted?.puzzles),
};
},
onRehydrateStorage: () => (state) => {
// 在恢复时,确保所有 puzzles 都是 Set
if (state) {
state.puzzles = ensurePuzzlesAreSets(state.puzzles);
}
},
}
)
);