Skip to content

容量与缩容

本页说明 EmakiStorage 的容量领域模型:config.ymlcapacity 段、四来源容量、三级 stackLimit,以及容量调小时的缩容与溢出处理。

capacity

yaml
capacity:
  base_slots: 45
  max_slots: 1000
  warn_entry_count: 5000
  default_stack_limit: 100
字段类型默认说明
base_slotsint45默认开放槽位数(45 = 5 × 9,与 gui.storage_rows 默认值一致)。
max_slotsint1000槽位总量硬上限,0 表示无限。
warn_entry_countint5000条目数超过此值时向控制台记 warning,0 表示不提醒。
default_stack_limitlong100配置级单槽堆叠上限。此层的 0 表示不限制。

四来源容量

effectiveSlots 由四个独立持久化的来源相加后钳制:

text
effective = clamp(base_slots + 权限档位 + grantedSlots + purchasedSlots, 0, max_slots)

max_slots0 时跳过上限钳制。四个来源分开存储,所以调小 base_slots 不会吃掉玩家已授予或已购买的槽位。

来源来自可否为负
baseSlotscapacity.base_slots否(负值按 0 处理)
permissionSlotsemakistorage.slots.<n> 的最大档位
grantedSlots/estorage slot grant、API grantSlotsAsync、Action storage_grant_slot
purchasedSlotsGUI 付费扩容、Action storage_unlock_slot

页数由槽位数推导,不可反向配置:

text
totalPages     = max(1, ceil(effectiveSlots / 每页格数))
reachablePages = max(1, ceil(usedSlots / 每页格数))

第 1 页始终可达(空仓库也要能打开并接收第一件物品);完全没有条目的页无法翻入。

max_slots 设为 0(无限)前请确认内存充足。配置注释给出的量级是单玩家 10 万条目约占 100–200MB 堆内存,这是推算值,未实测。

三级 stackLimit

单槽上限按「最具体优先」解析,三层:

层级存储位置设置方式0 的含义
条目级meta.yml 对应条目/estorage stacklimit slot、API setSlotStackLimitAsync、Action storage_set_stacklimitslot继承玩家级
玩家级meta.ymldefaultStackLimit/estorage stacklimit player、API setStackLimitAsync、Action storage_set_stacklimit 不带 slot继承配置级
配置级config.ymlcapacity.default_stack_limit配置文件不限制(等价 Long.MAX_VALUE

同一个 0 在不同层级语义不同:条目级与玩家级的 0 表示「继承上一级」,配置级的 0 表示「无限制」。解析顺序是条目级 > 0 → 玩家级 > 0 → 配置级,配置级 <= 0 时返回 Long.MAX_VALUE

另有 emakistorage.stacklimit.<n> 权限档位可提供玩家级上限,同样取最大值、不支持通配。

同物品跨槽位存储

默认情况下单槽存满即拒绝剩余部分。behavior.multi_slot_stacking 设为 true 后,同一物品可自动占用新槽位继续存储。

yaml
behavior:
  multi_slot_stacking: false # true = 允许一个条目跨多格

单槽上限 100、手上 120 个橡木原木:

开关结果
false(默认)存入 100,剩余 20 被拒绝(slot_full
true存入 120,显示为 [100] [20] 两格

占用格数如何推导

占用格数不持久化,每次读取时由数量推导:

text
span      = ceil(条目数量 / 单槽上限)
usedSlots = 所有条目 span 之和

usedSlots 必须计入 span,否则玩家能用 45 个跨格条目占满 90 格却只被记 45 格,直接突破 max_slots

单槽上限为无限(default_stack_limit: 0 且未被玩家级/条目级覆盖)时 span 恒为 1:无限的百分比没有意义,也就没有可溢出到第二格的部分。

取出与合并

跨格条目的多个格子共享同一个数量池,点任意一格取出都从条目总量扣除。因为 span 是推导值,收缩是自动的,不存在「合并」这一步:

text
120 个(上限 100)  →  [100] [20]      占用 2 格
点第 1 格取出 20    →  [100]           占用 1 格,后面的条目前滚填补

条目本身存储在无空洞的紧凑列表中,因此「后面的物品前滚填充」是列表的自然状态,界面每次刷新都会重新推导。

界面显示

每格显示本格的量而不是条目总量(第 1 格 100/100,第 2 格 20/100),与玩家阅读原版容器的方式一致。跨格时额外追加一行 gui.entry.span_total,说明条目总量与占用格数。

与其他机制的关系

行为
总槽位限制仍然生效。装不下的部分照旧被拒绝,不会突破 capacity.max_slots
%used_slots%(占位符、/estorage info、界面容量行)自动跟随新语义:开关开启后显示的是占用格数而不是条目数。
/estorage stacklimit slot <n>、API setSlotStackLimitAsyncStorageEntrySnapshot.slotIndex仍是条目下标,不是界面显示格号。上限属于条目本身,条目下标才是稳定身份。开关关闭时两者相同。
搜索命中数 %visible%仍是命中的条目数,因为玩家搜的是物品而不是格子。
溢出锁定按 span 累加边界。跨越容量边界的条目整条锁定(只读可取出),保持零丢失。
持久化格式不变。跨格只是条目数量变大,数量本来就是变长整数。

关掉开关后

true 改回 false 不丢数据:已超过单槽上限的条目仍占一格、显示按 100% 截断、拒绝新存入、可正常取空。

开销

开关关闭时 usedSlots 为 O(1)(直接取条目数)。开启后需遍历全部条目累加 span,单玩家条目数很大时每次界面刷新的开销会上升。容量在每次刷新时只解析一次而非每格一次,但遍历本身无法避免。

缩容与溢出

容量调小导致占用超出边界时,按 unlock.overflow_policy 处理。该键本身在配置详解unlock 段。

四种 overflow_policy

取值行为
lock_readonly超出容量边界的条目只读:可取出、不可存入,取空后自动释放。推荐。
compact超出条目前滚填补空位。条目本身已存储在无空洞的紧凑列表中,因此「前滚」就是列表的自然状态;仍然装不下的部分退化为 lock_readonly
return_inventory尝试把超出条目退回玩家背包,装不下的退化为 lock_readonly。玩家离线时不退还,直接锁定。
reject_change直接拒绝本次缩容。

四种策略全部零丢失,不提供 dropdelete:不可逆数据丢失不应由调整配置隐式触发。

溢出状态不持久化。它由容量与占用推导,在登录、重载、权限变化、命令授予等容量变化时机重新计算,因此不会出现存储标记与事实不同步的情况。

相关页面