数据存储
所属:开发者 · 同组:QinhRuinsAPI · Provider 与桥接 相关:核心概念 · 数据怎么存 · config.yml 全配置
QR 的数据分两类:绑世界坐标的实例 / 运行态 一律落 本地 YAML(换服没意义),只有 玩家图鉴发现 可选入库跨服共享。本页讲每个 store 存什么、存哪、何时入库。
1. 存储职责一句话
配方(模板 / 蓝图 / 档案 / 战利品表 / 词缀) = 磁盘 YAML + 结构文件,/qr reload 生效
实例与运行态(锚点 / 领取 / 老虎机 / 机关 / 净化容器)= 本地 YAML,绑世界坐标 → 就该本地
玩家图鉴发现 = 可选入数据库(跨服共享),其余仍本地一句话边界:「这条数据离开本服还有意义吗?」 锚点 / 宝箱领取 / 老虎机记录绑死在本服的世界坐标上,换服即废 → 本地;玩家「发现过哪些遗迹模板」是跨服可携带的收集册 → 可入库。
2. 存储门面:RuinStorage
RuinStorage 是 唯一 跟随 QCL 数据库的存储门面,只管图鉴。其余 store 都是独立的本地 YAML 文件,不经过它。
RuinStorage.init(plugin, config) // 读 storage.type,决定图鉴走 YAML 还是数据库
RuinStorage.isDatabase(): Boolean // 图鉴当前是否走数据库storage.type 开关
storage.type | 图鉴去向 |
|---|---|
yaml(默认) | 图鉴发现写本地 discoveries.yml |
database | 图鉴发现写 QCL 数据库表 qr_codex |
database 模式下若 QCL 数据库不可用 / 建表失败,会打 warning 并 自动回退本地 YAML,绝不因此崩服:
[QinhRuins] storage.type=database,但 QinhCoreLib 数据库不可用,图鉴回退本地 YAML数据库后端跟随 QCL:MySQL = 真正跨服共享;SQLite = 本地单机。
表与前缀
| 表名 | 用途 | 结构 |
|---|---|---|
qr_codex | 玩家图鉴:发现过的模板 | (player VARCHAR(36), template VARCHAR(64)),主键 (player, template) |
QR 自己只建
qr_codex一张表(前缀qr_)。秦淮生态里其它表前缀(如 QI 的qi_)归各自插件所有,QR 不碰。
3. 各 store 一览
| Store | 文件 | 存什么 | 键 | 入库? |
|---|---|---|---|---|
AnchorStore | anchors.yml | 锚点实例(模板 / 坐标 / 朝向 / 尺寸 / 状态 / 通关时间) | 锚点 id | ❌ 仅本地 |
DiscoveryStore | discoveries.yml | 玩家发现的锚点 + 发现的模板(图鉴) | 玩家 UUID | 锚点发现仅本地;模板图鉴可入库 |
LootClaimStore | loot_claims.yml | 玩家已领过的奖励箱 | `UUID → anchorId | chestId` |
MechFiredStore | mech_fired.yml | 已触发过的一次性机关 | anchorId → mechId | ❌ 仅本地 |
VesselStore | vessels.yml | 每人独立净化容器的内容快照 | `... | anchorId |
SharedVesselStore | shared_vessels.yml | 全服共享容器是否已填充 | `anchorId | ...` |
SpinStore | spins.yml | 玩家可用的净化老虎机次数授权 | `UUID | anchorId` |
SnapshotStore | snapshots/<anchorId>.nbt | 生成前原地形快照(消退 / 移除时还原) | 锚点 id | ❌ 仅本地(二进制 NBT) |
全部在 onEnable 时按文件路径 init,路径都在 plugins/QinhRuins/ 下。
4. 为什么这些「就该本地」
- 锚点(AnchorStore):记的是「X 世界 (123, 64, -45) 有一座遗迹」。这坐标在别的服根本不存在,入库毫无意义。
- 领取 / 老虎机 / 机关(LootClaimStore / SpinStore / MechFiredStore):都按具体锚点 id 记,锚点本身就是本地的,记录自然跟着本地。
- 容器内容(VesselStore / SharedVesselStore):绑某座遗迹的某个容器槽位。
- 快照(SnapshotStore):是世界方块的原始备份,纯本地二进制,还附带 体积上限(
cleanup.max-snapshot-volume,默认 500000),超限跳过快照避免主线程卡服。
5. 图鉴:唯一可跨服的数据
DiscoveryStore 同时管两样东西:
- 锚点发现(
discoveries.<UUID>):玩家走近过哪些具体锚点 —— 始终本地(锚点本身本地)。 - 模板发现 / 图鉴(
template-discoveries.<UUID>或qr_codex表):玩家见过哪些 遗迹种类 —— 这是收集成就,可跨服。
图鉴的 YAML / 数据库切换由 RuinStorage.isDatabase() 决定:
- YAML 模式:模板图鉴写进
discoveries.yml的template-discoveries段。 - 数据库模式:模板图鉴写
qr_codex表;本地 YAML 不再写template-discoveries。写库走 异步(RuinStorage.runAsync)不阻塞主线程。
跨服同步:CodexSyncListener
数据库模式下,CodexSyncListener 处理跨服图鉴的 加载 / 卸载:
| 时机 | 动作 |
|---|---|
| 玩家加入 | 异步从 qr_codex 读该玩家图鉴 → 切回主线程 DiscoveryStore.mergeTemplates 合并进内存 |
| 玩家退出 | DiscoveryStore.unloadTemplates 从内存卸载(避免缓存膨胀) |
这样玩家在 A 服发现的遗迹种类,登 B 服(同库)即可见。YAML 模式下该监听器空转(
isDatabase()为 false 时直接 return)。
6. 落盘时机
| Store | 何时写盘 |
|---|---|
AnchorStore | 由锚点管理器统一 saveAll(生成 / 状态变化 / 回收时) |
DiscoveryStore / LootClaimStore / MechFiredStore / SpinStore | 每次新增记录 立即 save(数据库模式的图鉴改为异步写库) |
SharedVesselStore | 标脏(dirty)+ 定时 600 tick(约 30 秒)批量 save,以及关服时 save |
VesselStore | 标脏(dirty),锚点清理(clearAnchor)与关服时 save(无定时器) |
SnapshotStore | 生成时 capture、还原成功后删快照文件 |
关服(
onDisable)时RuinStorage.close()+VesselStore.save()+SharedVesselStore.save()兜底落盘。
7. config.yml 相关键
storage:
type: yaml # yaml | database(database 跟随 QCL 数据库,跨服共享图鉴)
cleanup:
snapshot-restore: true # 移除 / 消退时是否还原地形
max-snapshot-volume: 500000 # 快照体积上限,超限跳过(防大结构卡服)完整配置见 config.yml 全配置。
下一步
- Provider 与桥接 — 钥石物品源 / 成长度 / 队伍
- 向导与图鉴 — 图鉴玩法层
- 核心概念 — 配方 vs 实例 vs endgame 分层