EmakiStorage
EmakiStorage 是 Emaki 系列的 GUI 仓库模块。它把玩家物品存进按逻辑槽位组织的仓库中,单个槽位可以存放 long 量级的数量,同时完整保留原始 ItemStack(组件、附魔、PDC 全部原样保存)。
仓库界面由 gui/storage_gui.yml 模板描述,容量由 config.yml 与权限档位、命令授予、付费购买共同决定,存取行为通过 CoreLib Action、公开 API 与 Bukkit 事件对外开放。
基本信息
| 项目 | 值 |
|---|---|
| 模块版本 | 1.0.1 |
| API Jar | emaki-storage-api-1.0.1.jar |
| 主类 | emaki.jiuwu.craft.storage.EmakiStoragePlugin |
| 主命令 | /emakistorage |
| 别名 | /estorage |
| 硬依赖 | EmakiCoreLib |
| 软依赖 | PlaceholderAPI |
| 描述符基线 | api-version: "1.21.8"、folia-supported: true |
| Java | Java 25 |
| 主要权限 | emakistorage.use(默认 true)、emakistorage.unlock.purchase(默认 true)、emakistorage.reload(op)、emakistorage.debug(op)、emakistorage.admin(op) |
功能页面
| 页面 | 内容 |
|---|---|
| 命令与权限 | /emakistorage、/estorage 的子命令、权限节点与示例。 |
| 配置详解 | config.yml 的 unlock、behavior、search、persistence、logging 等键。 |
| 容量与缩容 | capacity 段、四来源容量、三级 stackLimit 与缩容溢出策略。 |
| 界面与展示 | gui 与 display 段、gui/storage_gui.yml 模板结构与点击语义。 |
| 付费扩容档位 | unlock_costs.yml 的档位、逐格计价与支付顺序。 |
| CoreLib 动作 | EmakiStorage 注册到 CoreLib ActionRegistry 的 5 个动作。 |
| API 与集成 | 第三方插件通过 emaki-storage-api 调用仓库的方式与结果模型。 |
| 事件 API | StorageDepositEvent、StorageWithdrawEvent、StorageUnlockEvent 三个 Bukkit 事件。 |
| PlaceholderAPI 占位符 | emakistorage 扩展的 10 个占位符与求值线程约束。 |
核心能力
- 单槽
long量级存储:一个逻辑槽位存放一种物品,数量上限来自三级stackLimit配置,而不是原版 64/99 堆叠。 - 完整保留原始物品:去重口径是全量
ItemStack#equals(组件、附魔、自定义 PDC 全部参与比较),不引入任何哈希签名层,因此两个组件不同的同材质物品不会被合并成一个条目。 - 槽位是唯一容量真实来源:
effectiveSlots由base_slots+ 权限档位 + 命令授予 + 付费购买四个来源相加后钳制得出,页数由槽位数推导(ceil(effectiveSlots / 每页格数)),不存在「先定页数再算槽位」的反向推导。 - 混用存入:展示区任意槽位(光标带物品时点击)与固定投入口
deposit_slot两条路径共用同一套事务实现,容量检查、过滤器、事件发布与流水记录只存在一份。 - 1–99 占用率渲染:
display.amount_mode: percent时用物品amount字段的 1–99 表达占用百分比,精确数量写进 lore。max_stack_size组件的合法范围就是 1–99,因此不涉及任何发包技巧。 - 搜索与排序:搜索为子串匹配,永不编译正则;排序是显式「整理」动作,会重写条目顺序。
- 零丢失缩容:容量调小导致占用超出时有四种策略,全部不会造成不可逆数据丢失,不提供
drop/delete。 - 流水日志只写不读:业务逻辑永不读取日志文件,
ADMIN_SET/ADMIN_GIVE/ADMIN_CLEAR三类管理员操作强制记录。
存档设计
| 主题 | 实现 |
|---|---|
| 条目数据 | 二进制单文件 storage.dat,文件魔数 EMSTOR,格式版本 1。 |
| 写入策略 | 全量重写,不是追加写。每次保存都产出一个已经紧凑的文件,因此没有压实器、没有垃圾率统计、没有悬空 id 修复。 |
| 写入顺序 | 先写同目录 .tmp,再读回校验记录数,最后原子替换。写入失败时保留旧文件并删除 tmp。 |
| 逐条目分帧 | 每条记录单独分帧,使用 Paper 的 ItemStack#serializeAsBytes() / deserializeBytes(byte[]),携带 DataVersion 并在读取时过 DataFixer。 |
| 损坏隔离 | 解码失败的记录被写入 corrupt/<uuid>-<时间戳>.dat,其余记录正常载入。 |
| 可手改数据 | 槽位数、stackLimit、排序模式等存在 meta.yml(文本 YAML),条目载荷保持二进制,因为 YAML 无法表达完整 ItemStack。 |
文件结构
服务器运行后,EmakiStorage 主要使用以下文件:
text
plugins/EmakiStorage/
├─ config.yml
├─ unlock_costs.yml
├─ gui/
│ └─ storage_gui.yml
├─ lang/
│ ├─ zh_CN.yml
│ └─ en_US.yml
├─ data/
│ └─ <uuid>/
│ ├─ storage.dat
│ └─ meta.yml
├─ logs/
│ └─ <uuid>/
│ └─ <yyyy-MM-dd>.log
├─ corrupt/
└─ exports/| 路径 | 说明 |
|---|---|
config.yml | 主配置:界面、容量、扩容缩容、展示、存取行为、搜索、持久化、日志。 |
unlock_costs.yml | 付费扩容档位。业务数据文件,只在缺失时释放一次,版本升级不覆盖管理员内容。 |
gui/storage_gui.yml | 仓库界面模板。功能区只配 offset,槽位号由 gui.storage_rows 换算。 |
lang/*.yml | 界面、命令、扩容与控制台提示文案。 |
data/<uuid>/storage.dat | 该玩家的条目数据,二进制全量重写。 |
data/<uuid>/meta.yml | 该玩家的槽位数、stackLimit、排序模式等可手改元数据。 |
logs/<uuid>/<yyyy-MM-dd>.log | 存取流水,按玩家目录 + 按日切文件,只写不读。 |
corrupt/ | 解码失败记录的隔离目录。 |
exports/ | /estorage export 生成的可读 YAML 转储。 |
快速开始
- 把
EmakiCoreLib-*.jar与EmakiStorage-*.jar放入服务器plugins/。 - 不要把
emaki-storage-api-*.jar放进服务器plugins/;API Jar 只给开发者作为编译依赖使用。 - 首次启动后检查
plugins/EmakiStorage/config.yml与unlock_costs.yml。 - 打开自己的仓库:
text
/estorage- 修改配置后重载配置、语言与 GUI 模板:
text
/estorage reload- 给在线玩家追加槽位并查看容量拆解:
text
/estorage slot grant Steve 10
/estorage info Steve使用提示
gui.deposit_feedback不建议设为none。混用存入下物品会按条目顺序落位,可能出现在别的页,没有反馈时玩家会以为物品消失。emakistorage.slots.<n>与emakistorage.stacklimit.<n>取所有生效档位中的最大值,且不支持通配。- 调小
capacity.base_slots不会吃掉玩家已授予或已购买的槽位,这三个来源分别持久化。 - 缩容溢出状态不持久化,它由容量与占用推导,在登录、重载、权限变化、命令授予时重新计算。
- 写类管理命令要求目标玩家在线,见 命令与权限。