简体中文
EmakiStorage
EmakiStorage 是 Emaki 系列的 GUI 仓库模块. 你可以把物品存进一个按槽位分格的仓库界面, 每个槽位能放下的数量远超原版堆叠上限, 而且存进去的物品在组件, 附魔, PDC (物品上由插件写入的隐藏数据) 这些额外数据上全部原样保留
仓库界面由 gui/storage_gui.yml 模板描述; 容量由 config.yml, 权限档位, 命令授予和付费购买共同决定; 其他插件还能通过 CoreLib 动作, 公开 API 和 Bukkit 事件来存取物品或读取仓库信息
基本信息
| 项目 | 值 |
|---|---|
| 模块版本 | 1.1.5 |
| API Jar | emaki-storage-api-1.1.3.jar |
| 主类 | emaki.jiuwu.craft.storage.EmakiStoragePlugin |
| 主命令 | /emakistorage |
| 别名 | /estorage |
| 硬依赖 | EmakiCoreLib |
| 软依赖 | PlaceholderAPI |
| 描述符基线 | api-version: "26.1", folia-supported: true |
| Java | Java 25 |
| 主要权限 | emakistorage.use (默认 true), emakistorage.unlock.purchase (默认 true), emakistorage.autopickup (默认 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, StorageBatchEvent 四个 Bukkit 事件 |
| PlaceholderAPI 占位符 | emakistorage 扩展的 10 个占位符与求值线程约束 |
核心能力
- 单个槽位能存的量很大: 一个槽位只放一种物品, 数量上限来自三级
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, 当前格式版本 2. 文件末尾还带一段预留 (reservation) 记录, 让 API 的预留能跨重启保留下来 |
| 写入策略 | 每次保存都把整个文件重写, 不是往后追加. 所以每次存完文件都是紧凑的, 也就不用压实工具, 不用统计垃圾比例, 不用修复悬空的 id |
| 写入顺序 | 先在同一个目录写一个 .tmp, 再读回来核对记录条数, 最后一步才整体替换. 如果写入失败, 旧文件保留不动, 并把 tmp 删掉 |
| 逐条目分帧 | 每条记录单独打包, 用 Paper 的 ItemStack#serializeAsBytes() / deserializeBytes(byte[]), 记录里带上 DataVersion, 读取时会经过 DataFixer 升级 |
| 损坏隔离 | 解不开的记录被单独写到 corrupt/<uuid>-<时间戳>.dat, 剩下的记录照常载入 |
| 可手改数据 | meta.yml (文本 YAML, version: 1.0.0) 保存 player_name, granted_slots, purchased_slots, default_stack_limit, sort_mode, auto_pickup 这些可以直接手改的数据; 物品本身还是二进制, 因为 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调小不会吃掉玩家已经授予或购买的槽位, 这三个来源各自单独存档 - 缩容溢出的状态不会存进文件, 它是根据容量和占用推算出来的; 目前只有刷新 GUI 视图时才会去算它, 所以在打开界面, 以及每次存取, 翻页, 排序, 搜索之后刷新时会重新算一次
config.yml注释里出现的/storage是历史写法, 命令并未注册该别名, 见 命令与权限- 会改动数据的那些管理命令要求目标玩家在线, 见 命令与权限