物品槽组件
物品槽组件用于显示并交互一份服务端权威的物品状态。普通虚拟槽的身份由“玩家 + mode + bind”决定;不同页面、HUD 和世界页面只要打开了相同 mode + bind,就会自动显示并同步同一份槽位数据。容器替换页面中存在有效 containerBinding 的物品槽则直接使用当前原版容器槽位,不使用虚拟槽身份。客户端只提交点击意图,最终物品、光标、版本和背包变化都由服务端或当前原版容器裁决。
物品槽默认不绘制底框、填充或边框。这样可以直接放到自定义界面素材上;如果需要独立槽位背景,可配置一张静态图片。
槽内物品会按组件最终矩形的短边等比缩放并居中,四周各保留 1 GUI 像素。默认 18×18 槽位仍显示原版 16×16 物品;网格布局把槽位分配为 24×24 时,物品会同步放大为 22×22。宽高不同时只按短边缩放,不会拉伸物品;数量、耐久条和附魔效果会一起缩放。背景、点击范围与 Tooltip 仍使用完整槽位矩形。
静态背景路径支持本地 ChaUI 相对路径或公网 HTTP/HTTPS PNG/JPEG;即使远端 URL 没有扩展名,也会按实际内容识别并拒绝 GIF。公网 URL 的其他规则与图片组件一致。
适用场景
- 临时合成、提交和操作槽
- 按玩家长期保存、可跨页面使用的物品槽
- 映射玩家真实背包位置
- 多个界面位置同步显示同一个槽位
服务端始终权威
客户端不能提交最终物品内容。过期版本、重复操作、伪造会话和无效映射都会被拒绝,避免不同步或重复物品。
通用配置
| 配置项 | 编辑器名称 | 类型 | 默认值 | 可选值或格式 | 说明 |
|---|---|---|---|---|---|
id | ID | 字符串 | 自动生成 item_slot_N | 页面内唯一 ID | 只标识页面组件本身,不等同于槽位绑定 ID。 |
type | 类型 | 只读字符串 | item_slot | 固定值 | 创建后不能修改。 |
parent | 父级 | 字符串 | 空 | 布局组件 ID | 为空表示根级元素。 |
z | 层级 | 整数 | 0 | 任意整数 | 控制槽位绘制顺序。 |
visible | 显示 | 布尔值 | true | true、false | 静态显隐开关。 |
enabled | 启用 | 布尔值 | true | true、false | 为假时不能进行槽位交互。 |
pointerEvents | 指针处理 | 枚举 | auto | auto、block、pass | 槽位在 auto 下天然参与命中;pass 会关闭槽位交互。 |
scale | 缩放 | 数字或公式 | 1 | 非负值 | 以槽位中心缩放画面和命中范围,不改变布局值。 |
rotation | 旋转角度 | 数字或公式 | 0 | 有限角度,单位为度 | 围绕槽位中心顺时针旋转背景与物品画面,并精确命中。 |
opacity | 背景透明度 | 数字或公式 | 1 | 0 至 1 | 只影响槽位背景和边框,物品、数量与附魔效果保持不透明。 |
visibleWhen | 显示条件 | 条件表达式 | 空 | 只读条件 | 条件为假时隐藏。 |
enabledWhen | 启用条件 | 条件表达式 | 空 | 只读条件 | 条件为假时禁用。 |
containerBinding | 容器绑定 | 字符串 | 空 | 当前容器的语义槽位 ID | 仅容器替换页面使用;绑定后委托原版容器保留完整槽位交互。 |
containerTooltip | 容器提示 | 布尔值 | true | true、false | 是否显示绑定原版物品的完整提示。 |
layout.x | X | 数字或公式 | 创建时画布位置 | 合法布局公式 | 槽位左上角 X。 |
layout.y | Y | 数字或公式 | 创建时画布位置 | 合法布局公式 | 槽位左上角 Y。 |
layout.width | 宽 | 数字或公式 | 18 | 合法布局公式 | 推荐保持原版槽位附近尺寸。 |
layout.height | 高 | 数字或公式 | 18 | 合法布局公式 | 推荐保持原版槽位附近尺寸。 |
events.leftPress/rightPress/middlePress | 按下脚本 | ChaUI Script | 空 | 多行脚本 | 对应按键按下时触发。 |
events.leftRelease/rightRelease/middleRelease | 松开脚本 | ChaUI Script | 空 | 多行脚本 | 对应按键捕获仍有效并松开时触发。 |
events.leftClick | 左键脚本 | ChaUI Script | 空 | 多行脚本 | 组件左键事件;物品交换本身仍由槽位交互处理。 |
events.rightClick | 右键脚本 | ChaUI Script | 空 | 多行脚本 | 右键事件。 |
events.middleClick | 中键脚本 | ChaUI Script | 空 | 多行脚本 | 中键事件。 |
events.hoverEnter | 悬浮进入脚本 | ChaUI Script | 空 | 多行脚本 | 鼠标进入时触发。 |
events.hoverLeave | 悬浮离开脚本 | ChaUI Script | 空 | 多行脚本 | 鼠标离开时触发。 |
物品槽不支持自定义 tooltip。鼠标悬浮信息固定来自当前槽位物品自身,保存时写入 tooltip 会被拒绝。容器替换页面可用 containerTooltip: false 关闭绑定原版物品的提示。enabled: false 或 enabledWhen 结果为假时,槽内物品仍会绘制,但不会显示 Tooltip 或响应物品操作。
物品槽也不支持 dragMode。拖动物品、拆分堆叠和容器替换页面中的原版槽位操作都需要完整使用鼠标拖动手势;如果还允许拖动物品槽组件本体,两种行为会发生冲突。需要玩家移动一组槽位时,可以把它们放进可拖动的布局组件中,让布局负责整体移动。
专属配置
| 配置项 | 编辑器名称 | 类型 | 默认值 | 可选值或格式 | 说明 |
|---|---|---|---|---|---|
itemSlot.bind | 绑定 | 字符串 | 组件 ID | 安全绑定 ID | 标识虚拟槽物品状态;存在有效 containerBinding 时忽略并在编辑器隐藏。 |
itemSlot.mode | 模式 | 枚举 | temporary | persistent、temporary、mapped | 决定虚拟槽的存储和来源;存在有效 containerBinding 时忽略并在编辑器隐藏。 |
itemSlot.maxStack | 数量上限 | 整数或 auto | auto | 1 至 2147483647 | 仅 persistent 与 temporary 生效;auto 使用当前物品的原版最大堆叠数。 |
itemSlot.closePolicy | 关闭 | 枚举 | return_to_player | return_to_player、commit、discard | 仅虚拟 temporary 显示和生效;原版绑定槽、persistent、mapped 均不使用。 |
itemSlot.check | 操作条件 | 条件表达式 | 空 | 与 visibleWhen 相同的只读条件语法 | 空白表示允许;结果为假、表达式无效或求值失败时阻止虚拟槽或原版绑定槽操作,但组件点击脚本仍会执行。 |
itemSlot.allowPut | 放入 | 布尔值 | true | true、false | 是否允许物品进入槽位;原版绑定槽的点击、拖拽、Shift 和数字键操作同样遵守。 |
itemSlot.allowTake | 取出 | 布尔值 | true | true、false | 是否允许物品离开槽位;原版绑定槽的点击、拖拽、Shift 和数字键操作同样遵守。 |
itemSlot.path | 背景路径 | 字符串 | 空 | ChaUI 安全相对路径;仅 png、jpg、jpeg | 可使用 {vars.xxx} 等响应式路径模板;留空时槽位背景透明。 |
itemSlot.sourceX | 背景源X | 非负整数或公式 | 0 | 源图像素坐标或数字公式 | 背景选区左上角 X。 |
itemSlot.sourceY | 背景源Y | 非负整数或公式 | 0 | 源图像素坐标或数字公式 | 背景选区左上角 Y。 |
itemSlot.sourceWidth | 背景源宽 | 非负整数或公式 | 整张图片剩余宽度 | 像素尺寸或数字公式 | 背景选区宽度;为 0 时背景不绘制。 |
itemSlot.sourceHeight | 背景源高 | 非负整数或公式 | 整张图片剩余高度 | 像素尺寸或数字公式 | 背景选区高度;为 0 时背景不绘制。 |
背景选区公式每次渲染重新计算并向下取整。公式无效或越界时只隐藏槽位背景,槽位中的物品、数量、提示和交互仍然正常。
原版绑定槽的权威字段
当根级 containerBinding 非空且能解析为当前容器的语义槽位时,组件进入原版绑定槽模式:
- 真实物品、原版光标、网络同步与 Bukkit/第三方插件库存事件由当前 Minecraft 容器负责;
itemSlot.bind、itemSlot.mode、itemSlot.closePolicy不校验、不激活,也不会在编辑器显示;旧页面保留这些字段仍可正常加载;itemSlot.check、allowPut、allowTake、背景路径与源图区域继续校验并生效;- 纯放入要求
allowPut=true,纯取出要求allowTake=true,交换或数字键替换要求两项同时为true; - 普通点击、右键拆分、拖拽分配、Shift、双击、数字键、副手交换与丢弃键都经过同一许可判断。
如果脚本把 containerBinding 设为 null,组件不会自动启用先前被忽略的非法 bind/mode。需要切回虚拟槽时,应再通过脚本设置一组合法的虚拟槽绑定和模式。
编辑器保存 itemSlot.path 与四个背景源图字段时,会保留字段本身:固定数字仍是数字,公式仍保存原始文本,不会提前计算成某一次打开页面时的结果。执行 /chaui reload、服务端重启或重新打开编辑器后,背景路径和选区都会继续存在。
如果这些字段曾被旧版本保存后移除,需要在升级后重新选择一次背景并填写源图选区;新版本无法从已经被旧文件删除的内容中自动恢复。
三种槽位模式
| 模式 | 状态位置 | 关闭后行为 | 常见用途 |
|---|---|---|---|
persistent | 服务端按玩家与 bind 保存 | 不执行关闭策略;之后打开任意相同 bind 页面都会恢复 | 长期存储、跨页面玩家专属槽位 |
temporary | 玩家当前 ChaUI 运行期,按 bind 保存 | 最后一个运行时页面关闭时执行关闭策略并清理 | 合成、提交、跨当前打开页面的临时操作 |
mapped | 服务端真实映射槽位 | 直接使用真实容器状态,无关闭策略 | backpack_0 等玩家背包映射 |
三种模式的数据、版本和收尾逻辑彼此独立。即使 persistent 与 temporary 使用完全相同的 bind,也不会读取或影响对方的物品。
数量上限
持久槽和临时槽可以使用 itemSlot.maxStack 控制一个虚拟槽最多容纳多少件物品。不填写或填写 auto 时,槽位沿用当前物品的原版最大堆叠数;例如原版最多堆叠 64 件的物品仍最多放入 64 件。需要大容量槽位时,可以填写 999 等正整数,最大允许 2147483647。
下面两种写法都可以直接使用:
# 沿用物品自己的原版最大堆叠数
itemSlot:
bind: default_storage
mode: persistent
maxStack: auto# 允许同一种完整物品最多存入 999 件
itemSlot:
bind: bulk_storage
mode: persistent
maxStack: 999槽位会保留一份数量为 1 的完整物品原型,并独立保存逻辑数量,所以 maxStack: 999 可以正确显示、保存和恢复 999 件。物品名称、Lore、附魔、耐久和其他数据都属于完整物品身份;只有完整物品相同才会合并,不能只凭物品 ID 判断。
实际点击遵循这些规则:
- 空光标点击非空槽时,一次最多取出该物品的原版一组,剩余数量继续留在槽内。
- 光标物品与槽内完整物品相同时,会合并到配置的数量上限,放不下的部分留在光标上。
- 槽内已有不同物品时,本次放入会被拒绝,不会用光标物品交换或覆盖原物品。
- 管理员把数量上限降低到当前存量以下时,已有数量会完整保留;在数量降到新上限以下前不能继续放入,但仍可正常逐组取出。
temporary使用return_to_player时,超额逻辑数量会按原版最大堆叠数拆成多组返还。
同一个 mode + bind 代表同一份共享槽位状态,因此所有引用它的组件必须配置相同的数量上限;缺省与显式 auto 视为相同。配置冲突时页面会拒绝保存或加载,避免同一槽位出现两套容量规则。
mapped 背包映射槽和存在有效 containerBinding 的原版绑定槽始终遵循真实 Minecraft 容器规则,会忽略 maxStack,编辑器也不会显示“数量上限”。
持久槽必须先注册
persistent 不接受页面临时写出的任意 bind。管理员必须先在服务端的 plugins/ChaUI/slot.yml 注册该 ID;静态页面、编辑器保存、第三方页面注册、脚本动态改绑和服务端 API 都遵循同一规则。ID 支持中文等 Unicode 字母和数字以及 _、-。
例如,页面组件使用 itemSlot.bind: quest_submit 与 itemSlot.mode: persistent 时,服务器需要配置:
# 服务端 plugins/ChaUI/slot.yml
slots:
- id: quest_submit
acceptWhen: item.id == "minecraft:diamond"
rejectMessage: "这里只能放入钻石"保存后执行 /chaui reload。acceptWhen 拒绝准备放入的物品时,rejectMessage 会显示给玩家;省略或留空则只拒绝操作,不显示额外消息。消息必须是单行文本,最多 256 个 Unicode 码点。
客户端会用注册表即时阻止不满足条件的物品,服务端仍使用真实物品再次裁决。纯取出不检查接收条件;放入或交换才检查准备进入槽位的物品。slot.yml 只登记持久槽 ID、接收条件和拒绝消息,不保存玩家物品;玩家槽位数据仍按 ChaUI 的内存或 MySQL 持久化配置保存。完整配置、限制和错误处理见槽位注册表。
临时槽位关闭策略
return_to_player:关闭时尝试返还玩家,背包满时必须使用安全保护,不能吞物品或刷物品。commit:把最终物品交给其他业务逻辑处理。discard:明确丢弃,适合受控的特殊页面,使用前应确认业务风险。
同一个 temporary + bind 如果出现在多个已保存页面中,这些页面必须配置相同的 closePolicy,否则页面加载或保存会被拒绝。临时槽位会一直保留到玩家最后一个 ChaUI 运行时页面关闭;只关闭其中一个页面不会提前收尾。
操作条件
“操作条件”是客户端发包前的便捷判断,适合根据当前页面变量或只读常量暂时禁止槽位交换。没配置或留空时直接允许;条件为假、语法无效或运行时求值失败时,只阻止内置槽位操作包,组件自己的 events.leftClick 仍按原顺序执行。
这个字段不能替代服务端权限和物品安全校验。客户端状态可能被修改,真正的权限、物品合法性和业务条件仍应在服务端事件中检查。
如果要限制持久槽接收的物品,请把条件写到 slot.yml 的 acceptWhen,不要只写 itemSlot.check。前者会由服务端权威复查,后者只负责页面当前会话的客户端操作前置判断。
背包映射
mapped 使用显式白名单。backpack_0~backpack_35 映射 36 格主背包,另外支持 backpack_mainhand、backpack_offhand、backpack_helmet、backpack_chestplate、backpack_leggings 与 backpack_boots。点击时服务端会用 ChaUI 会话光标与真实背包槽执行权威交换。
在容器替换页面中,配置 containerBinding 的物品槽使用原版容器交互。如果鼠标上的物品来自普通 ChaUI 物品槽,点击这种原版绑定槽时会先完成一次服务端确认的光标交接,再自动重放刚才捕获的原版点击。因此可以把自定义槽中的物品放进背包或箱子绑定槽,同时保留 Shift、拆分、数字键以及第三方插件库存事件的原版行为。交接前也会检查目标组件的 check 与放入/取出许可;交接被拒绝或页面、槽位已经变化时不会重放,也不会复制或丢失物品。
完整编号、动态主手语义和只读背包常量见背包映射表。
配置示例
- id: submit_slot
type: item_slot
parent: ""
visible: true
enabled: true
pointerEvents: auto
scale: 1
opacity: 0.85
z: 10
layout:
x: 40
y: 40
width: 18
height: 18
itemSlot:
bind: quest_submit
mode: temporary
maxStack: auto
closePolicy: return_to_player
check: vars.questReady && vals.player.health > 0 # 操作条件:任务就绪且玩家存活
allowPut: true
allowTake: true
path: gui/item_slot.png # 可选;不写时背景完全透明
sourceX: 0
sourceY: 0
sourceWidth: 18
sourceHeight: 18
events: {}槽位对象的配置可以安全读取,但物品交换结果仍由服务端裁决。下面的事件只读取绑定 ID,不会直接修改槽位物品:
events:
rightClick: |-
vars.slotBind = component("submit_slot").itemSlot.bind
log("当前槽位绑定:{vars.slotBind}")映射背包示例:
itemSlot:
bind: backpack_0
mode: mapped
allowPut: true
allowTake: truemapped 模式不要写 closePolicy。
相同 bind、不同模式仍是两份独立数据:
- id: saved_reward
type: item_slot
layout: {x: 20, y: 20, width: 18, height: 18}
itemSlot:
bind: reward
mode: persistent
- id: current_reward
type: item_slot
layout: {x: 44, y: 20, width: 18, height: 18}
itemSlot:
bind: reward
mode: temporary
closePolicy: return_to_player上面的两个槽位虽然都叫 reward,但永久槽位和临时槽位不会互相显示、覆盖或同步物品。
背景图片只负责装饰,不参与服务端物品裁决,也不会改变槽位的点击区域。物品槽背景不支持 GIF。
常见问题
两个槽位为什么同时变化
它们使用了相同的 itemSlot.mode + itemSlot.bind,因此绑定同一份玩家级服务端状态。这个规则也适用于不同页面、HUD 和世界页面。不需要同步时请更换 bind;需要同名但数据隔离时请使用不同 mode。
操作条件没通过,为什么左键脚本还执行
itemSlot.check 只控制内置槽位操作是否发包,不控制组件事件。这样可以在禁止交换时仍播放提示、修改页面变量或记录本地日志。需要阻止脚本逻辑时,请在 events.leftClick 内使用同样的条件自行分支。
点击后提示版本过期
服务端状态已经变化,客户端提交的是旧版本操作。等待最新同步结果后重新操作,不要让客户端自行构造物品结果。
mapped 为什么只能使用白名单 bind
真实容器映射必须经过服务端白名单,避免客户端构造危险槽位地址。未记录的映射会被拒绝。
创建事件
item_slot 支持 events.create,可在槽位组件实例创建时设置说明变量、显隐或周边组件状态。初始槽位和动态槽位实例各触发一次,但脚本不能伪造最终物品结果;槽位内容仍以服务端同步为准,关闭或 reload 时继续执行既定的持久化、返还或映射策略。
Tooltip 皮肤
物品槽提示的内容优先级保持显式 tooltip、原版物品提示、无提示。服务器全局样式只替换背景与排版;显式文本使用 source: explicit,物品使用统一的 source: item。配置见全局 Tooltip 样式。
猹件开发组