Skip to content

数据存储

所属:开发者 · 同组:QinhRuinsAPI · Provider 与桥接 相关:核心概念 · 数据怎么存 · config.yml 全配置

QR 的数据分两类:绑世界坐标的实例 / 运行态 一律落 本地 YAML(换服没意义),只有 玩家图鉴发现 可选入库跨服共享。本页讲每个 store 存什么、存哪、何时入库。


1. 存储职责一句话

配方(模板 / 蓝图 / 档案 / 战利品表 / 词缀) = 磁盘 YAML + 结构文件,/qr reload 生效
实例与运行态(锚点 / 领取 / 老虎机 / 机关 / 净化容器)= 本地 YAML,绑世界坐标 → 就该本地
玩家图鉴发现 = 可选入数据库(跨服共享),其余仍本地

一句话边界:「这条数据离开本服还有意义吗?」 锚点 / 宝箱领取 / 老虎机记录绑死在本服的世界坐标上,换服即废 → 本地;玩家「发现过哪些遗迹模板」是跨服可携带的收集册 → 可入库。


2. 存储门面:RuinStorage

RuinStorage唯一 跟随 QCL 数据库的存储门面,只管图鉴。其余 store 都是独立的本地 YAML 文件,不经过它。

kotlin
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文件存什么入库?
AnchorStoreanchors.yml锚点实例(模板 / 坐标 / 朝向 / 尺寸 / 状态 / 通关时间)锚点 id❌ 仅本地
DiscoveryStorediscoveries.yml玩家发现的锚点 + 发现的模板(图鉴)玩家 UUID锚点发现仅本地;模板图鉴可入库
LootClaimStoreloot_claims.yml玩家已领过的奖励箱`UUID → anchorIdchestId`
MechFiredStoremech_fired.yml已触发过的一次性机关anchorId → mechId❌ 仅本地
VesselStorevessels.yml每人独立净化容器的内容快照`...anchorId
SharedVesselStoreshared_vessels.yml全服共享容器是否已填充`anchorId...`
SpinStorespins.yml玩家可用的净化老虎机次数授权`UUIDanchorId`
SnapshotStoresnapshots/<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.ymltemplate-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 相关键

yaml
storage:
  type: yaml        # yaml | database(database 跟随 QCL 数据库,跨服共享图鉴)

cleanup:
  snapshot-restore: true       # 移除 / 消退时是否还原地形
  max-snapshot-volume: 500000  # 快照体积上限,超限跳过(防大结构卡服)

完整配置见 config.yml 全配置


下一步