主题
这页用于说明 HNWarehouse 当前版本的正式存储后端、运行时 Session、旧 YAML 迁移机制与日常运维排查重点。
当前存储方式
当前版本的正式持久化主路径已经切到数据库后端。
当前实现特点:
- 主后端由 HNCore 的
DatabaseManager驱动 - 仓库系统不再把
plugins/HNWarehouse/data/players/*.yml作为正式主数据源 - 旧 YAML 目录现在主要是历史迁移来源
- 物品 payload 统一复用 HNCore
ItemCodec,不是业务仓库自己再维护一套额外物品序列化协议
也就是说:
- 日常运行时以数据库中的玩家仓库档案为准
- 旧 YAML 主要用于从历史版本升级时的导入
- 运维排查也应优先围绕
status / inspect / routecheck与数据库状态展开,而不是默认去找玩家 YAML 文件
当前数据结构概览
当前仓库数据已经按业务职责拆成数据库层结构,典型可以理解为以下几类:
accounts:玩家仓库账户级元数据与总体状态pages:玩家实际拥有的仓库页骨架与页级属性entries:每个页面内的物品条目purchases:一次性购买状态unlocks:一次性解锁状态expansions:页扩容状态
这意味着当前不再是“整份玩家 YAML 全量覆盖写回”的思路,而是:
- 仓库账户、页面、条目、购买、解锁、扩容状态分层持久化
- 条目层可以按页面局部重写,不必每次都把整份玩家仓库全量序列化一遍
- 物品内容统一通过 HNCore
ItemCodec存取,减少多个插件并存时的物品协议分裂
关于物品 payload
当前条目里的物品快照不是 HNWarehouse 私有格式,而是统一走:
- HNCore
ItemCodec
这带来的好处是:
- 物品编解码语义与 HNCore 公共协议保持一致
- 更适合和邮件、奖励、签到、仓库这类需要保存物品快照的模块协同
- 后续做迁移、兼容或坏数据隔离时更容易统一处理
运行时 Session 行为
当前仍保留 PlayerItemSession 作为运行时内存态,但行为已经不是旧式同步落盘模型。
主要行为:
- 玩家加入时:异步加载 session
- 玩家退出 / 被踢出时:异步保存并卸载 session
- 自动保存:按配置间隔异步执行
- 插件关闭时:统一
flush reload:管理员触发后后台执行重载,期间仍保留安全收尾与 session 保存语义
关于 unloadSession()
当前实现已经修复“先把 session 从内存移除,再执行保存”的丢档风险。
这意味着:
- 退出 / 卸载流程现在会优先保证保存链路安全完成
- 不建议再用旧认知理解成“玩家一退就立刻同步写完、否则就一定丢档”
- 更准确的理解是:运行时以 Session 为主、持久化以异步安全保存为主、关闭阶段再做统一 flush
自动保存
相关配置:
yml
storage:
autosave-interval-seconds: 60说明:
- 单位是秒
0表示关闭自动保存- 当前 autosave 在异步任务中执行
- 主要目的是避免把完整批量落盘压在主线程上
运维建议:
- 测试服可以适当缩短,方便验证写入行为
- 正式服不要把间隔调得过于激进,否则虽然不一定直接卡主线程,但仍可能增加数据库压力
- 如果你已经有大量离线查询、频繁投递与高在线人数,建议结合数据库负载一起观察,而不是只盯着“写入快不快”
离线摘要缓存
当前离线仓库摘要查询有一层短 TTL 缓存。
它的作用是:
- 减少短时间重复查看离线玩家仓库时的数据库读取
- 避免管理场景中连续
inspect/ 摘要查询反复打库
当前语义建议理解为:
- 这是短缓存,不是长期结果缓存
- 写入发生后会主动失效相关缓存
- 主要影响的是离线玩家摘要查询,不是在线 Session 内部状态
如果你发现短时间连续查看同一个离线玩家时结果一致,这是正常现象;优先确认是否落在摘要缓存时间窗内。
旧 YAML 自动迁移
旧版本目录仍可能存在:
text
plugins/HNWarehouse/data/players/当前启动时会把它当成迁移来源扫描。
当前迁移语义
- 启动时扫描旧
data/players/*.yml - 只有数据库中还不存在该玩家档案时才会导入
- 成功后会写入:
text
plugins/HNWarehouse/data/.migration-complete- 原始 YAML 文件不会被自动删除
这意味着什么
- 旧 YAML 现在更像“历史导入源”,而不是正式主数据目录
- 如果你已经完成迁移,后续新增玩家不应再默认依赖 YAML 生成
- 保留原始 YAML 的目的是给升级后的人工核对与回退留余地
恢复性与坏数据处理
当前读取数据库条目时,会尽量做坏数据隔离。
建议理解为:
- 如果个别
entry损坏,会跳过坏条目并记录警告日志 - 单条坏数据不会直接阻断整份玩家仓库档案加载
- 排查时不要因为一条物品坏了,就默认整份仓库都不可恢复
这对仓库系统尤其重要,因为条目层天然更容易出现:
- 历史物品结构变化
- 跨版本物品 payload 差异
- 外部插件联动带来的异常物品内容
当前目标是:尽量把损坏隔离到单条 entry,而不是放大成整档不可用。
常见排查命令
看整体运行状态
text
/hnwarehouse status适合确认:
- 存储后端
- 自动保存间隔
- 离线摘要缓存秒数
- 当前已加载 Session 数量
- 仓库定义与访问限制骨架
看某个玩家的仓库摘要
text
/hnwarehouse inspect <玩家>
/hnwarehouse inspect <玩家> detail
/hnwarehouse inspect <玩家> access适合确认:
Session 已加载状态是否符合预期- 玩家当前有多少仓库 / 页面
- 当前锁定原因
- 具体条目 ID 与数量
- 离线摘要是否已命中短缓存
看为什么投递失败
text
/hnwarehouse routecheck <玩家> <仓库> [manual|reward|auto-collect]适合确认:
- 目标页是否允许该来源
- 是否命中
item-admission - 是否被访问条件拦截
日常排查建议
场景 1:玩家说“仓库打不开”
先看:
/hnwarehouse inspect <玩家> access- 是否是
purchase / unlock / use-requirements问题 visible-when-locked是否开启
场景 2:玩家说“物品没进仓库”
先看:
- 当前来源是否启用
- 默认目标仓库是否正确
- 页面
allowed-sources是否允许 item-admission是否拦截/hnwarehouse routecheck ...
场景 3:玩家说“物品取不出来”
先看:
- 条目 ID 是否正确
- 目标页面是否正确
- 玩家是否在线
- 背包是否能正常回填
/hnwarehouse inspect <玩家> detail
场景 4:为什么短时间连续查看离线玩家时像是“重复结果”
先看:
- 是否仍在离线摘要 TTL 缓存时间窗内
- 是否发生过写入导致缓存失效
- 当前看的是否是离线玩家而不是在线 Session
当前不建议的运维方式
当前不建议把下面这些做法当成主运维入口:
- 直接手改数据库记录作为常规操作
- 把旧 YAML 当成正式主档反复修
- 仅凭磁盘文件变化判断 Session 是否已生效
更稳的顺序通常是:
- 先用
status / inspect / routecheck排查 - 再看数据库状态与运行日志
- 必要时使用管理命令修复
- 最后才考虑人工修数据库或核对旧 YAML 迁移源
关于旧 YAML
旧 data/players/*.yml 现在主要用于:
- 迁移来源
- 升级后人工比对
- 极端情况下的历史恢复参考
它已经不适合作为“当前正式玩家仓库数据主入口”。
当前还没有的运维能力
相比更成熟的业务插件,HNWarehouse 当前还没有完整提供:
- 面向运维的数据库一致性校验命令
- 自动迁移报告导出
- 批量修复工具
- 更完整的运维后台面板
所以当前运维主路径仍然是:
statusinspectroutecheckwithdrawunlockforceunlockreset- 数据库状态与运行日志
备份建议
当前备份建议应按实际后端理解:
- 如果使用 SQLite,应优先备份本地数据库文件
- 如果使用 共享数据库 / 独立数据库实例,应备份数据库本体
- 如果你仍保留旧 YAML 迁移源,也可以把
plugins/HNWarehouse/data/players/一并备份,作为历史迁移参考
特别建议在这些操作前先备份:
- 大规模改
warehouses/*.yml - 调整仓库 ID、页 ID
- 重新设计购买 / 解锁 / 扩容逻辑
- 手动处理数据库中的玩家仓库异常状态
- 首次从旧 YAML 升级到数据库版本
这样即使出问题,也更容易按“数据库主档 + YAML 历史迁移源”双层回退。
