Files
ichni_Official/docs/offline-content-unlock-system.md

7.2 KiB
Raw Blame History

Offline 内容解锁系统

适用项目ichni Official
状态Core-003 已完成并经 Unity 运行时测试通过
最后更新2026-07-18

本文是章节、歌曲和未来内容使用 Key 解锁机制的唯一使用说明。修改解锁规则、编写 Yarn 解锁命令或排查“内容为什么锁定”时,应先阅读本文。

1. 目标与边界

首发版本为纯 Offline。内容解锁记录在玩家本地 ES3 存档中,用于控制章节和歌曲是否可进入;它不是付费凭证、云端权益或反作弊机制。

解锁状态独立于下列数据域:

  • 歌曲成绩Accuracy、Max Combo、FC/AP、Chart Revision。
  • 剧情记录:故事树 Block、对话选项、Yarn 变量。
  • 选曲缓存:本次运行中每章节最后选中的歌曲和难度。

当前不实现 Payment Unlock。未来若接入商店、DLC 或在线 entitlement应由对应模块向本系统授予同样的 Key不得在 UI 或歌曲数据中重新建立支付专用判断。

2. 主要代码与职责

位置 职责
Assets/Scripts/Saving/UnlockSaveModule.cs Key 存档、Schema、规则求值、章节/歌曲统一授权。
Assets/Scripts/Saving/GameSaveManager.cs 启动时创建并加载 UnlockSaveModule
Assets/Scripts/Menu/ChapterSelection/ChapterSelectionUnit.cs 为章节和歌曲配置 UnlockRequirement
Assets/Scripts/NewStorySystem/YarnFunctions/StoryTreeCommands.cs 提供 grant_unlock 与兼容的 unlock_song Yarn 命令。
Assets/Scripts/UI/ChapterSelection/ChapterSelectionUI.cs 阻止锁定章节进入剧情和选曲。
Assets/Scripts/UI/SongSelection/PlaySongUI.csSongSelectionTab.cs 阻止标准 Play 与快速点击绕过锁定。

3. Key 命名规则

Key 是稳定的内部 ID不是玩家可见文本也不是歌曲标题、章节标题或 Yarn 节点标题。

  • 只能包含小写英文字母、数字和下划线。
  • 必须以小写字母开头,长度为 196。
  • 推荐格式:来源_章节_事件_状态
  • 示例:story_ch0_prologue_completedstory_ch0_route_a_completedchapter_ch1_available
  • 禁止使用点号、空格、连字符、中文/日文等本地化文本,或会频繁更名的显示名称。

不符合规则的 Key 无法被授予;运行时遇到配置错误时会保持锁定并只输出一次警告,避免错误配置意外开放内容。

4. 配置章节与歌曲

ChapterSelectionUnit.unlockRequirement 控制该章节的剧情入口和选曲入口。SongItemData.unlockRequirement 控制歌曲自身。

根节点为空时表示无条件开放。需要锁定时,在 Odin Inspector 的 Unlock Requirement 中选择下列节点:

节点 含义 使用示例
Key 玩家必须持有该 Key。 一首歌曲要求 story_ch0_prologue_completed
All Of (AND) 所有子条件都满足才开放。 同时完成两个剧情分支。
Any Of (OR) 满足任意一个子条件即可开放。 完成路线 A 或路线 B。

真正开始歌曲时,章节规则和歌曲规则必须同时满足。即使歌曲本身无条件开放,只要所属章节锁定,仍不能进入。

Key、空的 All Of / Any Of 列表、或组合中的空子节点都被视为错误配置并失败关闭。

5. 从 Yarn 授予 Key

通用内容解锁

<<grant_unlock story_ch0_prologue_completed>>

grant_unlock 立即写入本地存档,适用于章节、歌曲、教程和未来任意内容。它本身不显示提示;若需要文案,应在 Yarn 中额外使用 show_message

兼容的歌曲命令

<<unlock_song story_ch0_song_02_available>>

unlock_song 同样授予 Key并在首次授予后保留旧有歌曲解锁提示行为。当前提示仍会显示英文和内部 Key此显示问题属于后续本地化任务不影响授权结果。

两个命令都具备幂等性:已拥有同一 Key 时不会重复保存或重复弹出歌曲解锁提示。

6. 存档、Schema 与清档

  • 文件:Application.persistentDataPath/GameSaves/UnlockKeys.json
  • ES3 数据 KeyUnlockKeys
  • 当前 SchemaUnlock Save v1

本系统保留了旧 UnlockKeys.json 的文件名与 ES3 Key。此前仅保存 HashSet<string>、但没有 Schema 的预发布文件会作为 v0 无损读取,并补写为 v1文件中不符合当前命名规则的 Key 会被删除。

若读取到非 v1、且不是旧 v0 的 Schema当前预发布策略会重置该文件。正式发布后若变更解锁存档结构必须编写显式迁移不能继续删档。

StoryManager.ClearAllStorySave() 会同时清空剧情树、Yarn 变量和全部内容解锁 Key便于测试完整剧情进度。它不会清除歌曲成绩。

7. 入口防护

所有现有可进入内容的入口均需遵守同一授权规则:

入口 防护行为
章节剧情入口 按钮禁用,并在点击回调中再次检查章节规则。
章节选曲入口 按钮禁用,并在点击回调中再次检查章节规则。
歌曲标准 Play 通过 UnlockSaveModule.CanEnterSong(...) 作最终检查。
歌曲快速点击 使用同一最终检查,不能绕过标准 Play。

SongSelectionTab.isLocked 只用于锁图标和预览表现,不能作为安全判断的唯一来源。剧情刚授予 Key 或 UI 被其他逻辑刷新后,真正进入前仍会重新计算规则。

8. 内容作者工作流

  1. 先定义需要代表的进度事实,并按规则起一个稳定 Key。
  2. 在 Chapter 或 Song 的 Unlock Requirement 中引用这个 Key 或组合规则。
  3. 在对应 Yarn 节点完成时添加 grant_unlock 或兼容的 unlock_song
  4. 使用新档测试锁定状态,再完成一次剧情测试授予后的即时状态。
  5. 重启游戏确认 Key 仍存在;清空剧情存档后确认内容重新锁定。

不要为了“解锁某首歌”而直接修改 UI、isLockedUnlockKeys.json;所有授予必须经由 UnlockSaveModule.GrantKey(...) 或 Yarn 命令。

9. 未来扩展原则

  • 新内容类型优先复用 UnlockRequirementUnlockSaveModule
  • 需要更复杂的组合时在现有规则树中增加节点,不要在各页面复制 if 判断。
  • 商店、DLC、成就或云端 entitlement 将来只负责授予/撤销 Key章节和歌曲 UI 不应关心 Key 的来源。
  • 如需玩家可见的“为何锁定”说明,应添加本地化提示 Key不要展示内部 Unlock Key。
  • UnlockSaveModule.UnlockStateChanged 预留给未来需要在当前页面即时刷新解锁状态的 UI。

10. 回归测试清单

  1. 无规则的章节和歌曲在新档可进入。
  2. 配置 Key 后,新档中章节/歌曲锁定。
  3. 锁定歌曲的标准 Play 和快速点击均无法进入。
  4. 锁定章节的剧情入口和选曲入口均无法进入。
  5. grant_unlock 后规则立即满足;返回菜单后显示正确。
  6. 重启后 Key 仍存在。
  7. All Of 只有全部 Key 存在时开放;Any Of 任一 Key 存在时开放。
  8. 空 Key 或错误组合不会开放内容,并只产生一次可定位警告。
  9. ClearAllStorySave() 后剧情进度与解锁 Key 均清除,歌曲成绩保留。