用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/mbianchidev/2dnd --skill save-system命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | save-system |
| description | Manage 2D&D save schema v16, migration, normalization, and location recovery |
| license | MIT |
Game state is stored in localStorage by src/systems/save.ts. Shared audio
and accessibility preferences plus inventory presentation preferences are
stored separately.
2dnd_save: game state2dnd_preferences: versioned audio and accessibility preferences2dnd_inventory_prefs: inventory sort, filter, and search presentationLegacy 2dnd_audio_prefs and 2dnd_cutscene_accessibility values migrate into
2dnd_preferences. Inventory recency derives from reverse canonical append
order. Do not add presentation fields to item ownership or increment the
campaign schema for these preferences.
SAVE_VERSION is 16.
interface SaveData {
version: number;
player: PlayerState;
defeatedBosses: string[];
codex: CodexData;
appearanceId: string;
timestamp: number;
timeStep?: number;
weatherState?: WeatherState;
}
Set<string> values are serialized as arrays and reconstructed by the scene
loading path.
interface CodexData {
entries: Record<string, CodexEntry>;
unlockedEntryIds: string[];
}
Monster entries retain defeat, AC, drop, and elemental discovery. Knowledge
IDs are normalized against CODEX_KNOWLEDGE_ENTRIES; completion and counts are
derived.
Important composed fields:
interface PlayerPosition {
x: number;
y: number;
chunkX: number;
chunkY: number;
inDungeon: boolean;
dungeonId: string;
dungeonLevel: number;
inCity: boolean;
cityId: string;
cityChunkIndex: number;
}
interface PlayerProgression {
openedChests: string[];
collectedTreasures: string[];
exploredTiles: Record<string, boolean>;
discoveredCities: string[];
quests: QuestLogState;
seenCutsceneIds: CutsceneId[];
pendingCutsceneIds: CutsceneId[];
skillChecks: Record<string, SkillCheckRecord>;
trapSeed: number;
trapStates: Record<string, TrapState>;
trapGuidance: boolean;
tutorial: ;
: ;
: ;
: ;
: ;
: ;
}
{
: | | ;
: ;
: <, >;
: [];
}
{
: <, >;
: [];
}
PlayerState.activeEffects persists normalized ActiveStatusEffect values.
Codex entries persist discoveredElements. PlayerState.party persists unique
companion states, active order, independent progression/inventories/equipment,
control modes, dialogue state, and gambits. Quest progress stores status, stage,
objective counters, claimed reward IDs, and acknowledged danger warnings.
seenCutsceneIds stores stable completed-or-skipped story presentation IDs.
pendingCutsceneIds stores queued IDs awaiting completion or skip and is saved
before presentation. Replay changes neither collection; campaign completion
remains derived from quest state.
tutorial.completed prevents the new-player tutorial from reopening
automatically after completion or skip. Tutorial replay does not reset it.
Fixed non-combat checks persist the
ability, natural roll, modifier, repaired total, DC, outcome, and optional
choice ID.
worldEvents persists a stable seed, deterministic roll/cooldown counters, one
pending choice or special battle, idempotent resolved/claimed IDs, repeat
counters, and the bounded chronological World Events record.
social persists bounded alignment axes, per-town/per-faction reputation
scores, stable applied source IDs, and at most 40 recent cause entries. Names,
tiers, thresholds, shop modifiers, Codex milestones, and achievement hooks are
derived.
achievements persists earned records, once-only event counters/IDs, explicit
defeat-history validity, unlocked/equipped cosmetic titles, debug suppression,
and pending notice IDs. Definitions, categories, points, totals, and
reconstructable progress are derived from canonical data.
gathering persists a deterministic seed, stable node cooldown/depletion,
discovered node/resource IDs, once-only claimed outcomes, discipline statistics,
bounded history, and one exact pending minigame or guarded Battle outcome.
crafting persists known recipe IDs, stable applied discovery/transaction IDs,
natural craft and equipment-upgrade statistics, per-recipe counts, bounded
recent history, and the next sequence. Recipe definitions and values are
canonical derived data.
nautical persists boat ownership/condition/upgrades/cosmetics, discovered
ports/routes/islands/continents/sea tiles, bounded navigation statistics, and
recoverable pending merchant routes, hazards, and encounters. Continents, sea
zones, ports, routes, islands, boats, and encounter pools remain canonical data.
Treat parsed JSON as unknown. Use typed record guards and normalization
helpers; do not cast unvalidated nested values directly.
loadGame() currently handles:
bestiary to codexplayer.positionplayer.progressionnormalizeSeenCutsceneIds() and normalizePendingCutsceneIds()normalizeQuestLog()normalizeTutorialProgress()normalizeWorldEventState();
malformed seeds clear pending encounters, unknown events/choices are removed,
and records are boundednormalizeSocialState(); unknown town
and faction IDs are removed, scores are clamped, applied IDs are deduplicated,
and history is validated against those IDsnormalizeAchievementState();
unknown/duplicate IDs are removed, counters/order are repaired, title
cross-fields are validated, and schema-v12 or older saves reconcile durable
milestones silently while retaining unknown defeat historynormalizeGatheringState(); schema-v13
saves gain defaults, malformed seeds clear generated node/pending state, and
pending outcome/resource/pattern/location cross-fields are validatednormalizeCraftingState(); schema-v14
saves gain defaults, unknown/duplicate IDs are removed, statistics are clamped,
history is bounded/resequenced, and durable discovery is reconciledAfter migration, normalize location state:
(4, 2), tile (3, 3).Always resolve maps through getDungeonLevelMap() and getCityChunk() during
validation.
unknown.SAVE_VERSION for a schema change.For party data, normalize after quests, skill checks, and trap fields. Then
replay completed recruitCompanion quest actions so v5 saves and debug-completed
quests converge idempotently.
Normalize seen and pending cutscene IDs on every load against CUTSCENE_IDS.
Unknown IDs are discarded, IDs remain stable after release, and pending IDs
already present in the seen list are removed. Missing lists default to empty;
legacy recovery may queue only the completed-but-unseen epilogue.
Pre-v9 saves did not have tutorial state and normalize to completed: true so
existing campaigns are not interrupted. New v9 players start false; malformed
v9 values also normalize safely to false.
Do not silently retain malformed data. Use a safe default or reject the save when the top-level payload is unusable.
normalizeActiveEffects().isElement().normalizeSkillCheckRecords().total and success from the saved natural roll, modifier, and DC.saveGame(player, defeatedBosses, codex, appearanceId, timeStep, weatherState);
const save = loadGame();
hasSave();
deleteSave();
getSaveSummary();
Save failures are reported with debugLog(). Loading returns null when the
top-level save is absent or corrupt.
tests/save.test.ts covers:
SaveData without runtime validationnormalizeNauticalState(); schema-v15
and older saves gain defaults, unknown IDs and malformed pending records are
removed, condition/statistics are clamped, and invalid sea positions recover
to a safe port without losing other progression