自动售货机
基本信息
| 属性 | 值 |
|---|---|
| 注册名 | multimachine.vendingmachine(GTNH MTE 名,非 vendingmachine: 命名空间) |
| 显示名 | gt.blockmachines.multimachine.vendingmachine.name = Vending Machine |
| MTE ID | 2741(VendingMachine.CONTROLLER_MTE_ID) |
| 类 | MTEVendingMachine extends MTEMultiBlockBase |
| 结构大小 | 2 宽 × 3 高 × 1 深(beginStructureBlock(2, 3, 1, false)),共 6 格 |
| TileEntity | 无独立 TileEntity 类,状态由 MTEVendingMachine 字段 + IGregTechTileEntity 承载 |
| 物品形态 | 1 个 |
源码:blocks/MTEVendingMachine.java(894 行)。
结构要求
形状定义 STRUCTURE_DEFINITION:
.addShape("main", new String[][] { { "cc", "c~", "cc" } })
以控制器为原点展开(check(..., 1, 1, 0, ...)):
c c ← 第 3 层:2 个外壳
c ~ ← 第 2 层:1 个外壳 + 控制器
c c ← 第 1 层:2 个外壳
| 符号 | 含义 | 数量 |
|---|---|---|
~ |
控制器本体(售货机机器方块) | 1(固定在右侧中层,即「Middle right, 2nd layer」) |
c |
ofChain(ofHatchAdderOptional(...), ofBlock(casingBlock, 0)) — 外壳或上行接口,二选一 |
5 |
- 最小规模:5 个 自动售货机外壳 + 1 个控制器
- 最大规模:同上(5 格位置里最多 1 格可替换为 ME 售货机上行接口)
- 布局规则:不能侧翻(
isFacingValid拒绝 UP/DOWN,只能水平四向;getAlignmentLimits同样约束) - 结构检测频率:每
STRUCTURE_CHECK_TICKS = 20tick 一次(onPostTick中mUpdate++ % 20 == 0) getDefaultHasMaintenanceChecks()返回false,不检查维护isTeleporterCompatible()返回false,不可被传送
库存与槽位
| 项目 | 值 | 源码 |
|---|---|---|
| 输入格 | 8 | INPUT_SLOTS = 8 |
| 输出格 | 100 | OUTPUT_SLOTS = 100 |
getSizeInventory() |
108 | INPUT_SLOTS + OUTPUT_SLOTS |
| 缓冲队列 | ConcurrentLinkedQueue<ItemStack> outputBuffer(无上限) |
— |
| 待处理交易 | LinkedBlockingQueue<TradeRequest> pendingTrades(无上限) |
— |
| GUI 预分配 | MAX_TRADES = 300 个交易格子 / 每个分类 |
MTEVendingMachine.MAX_TRADES |
槽位索引映射(getStackInSlot / setInventorySlotContents):
| 索引区间 | 归属 |
|---|---|
0 ~ 7 |
inputItems(ItemStackHandler,8 格) |
8 ~ 107 |
outputItems(ItemStackHandler,100 格) |
isValidSlot(aIndex):aIndex < 108shouldDropItemAt(index):恒为true(拆除时全部掉落)allowPutStack/allowPullStack:均恒为false,外部(自动化/管道)无法直接推拉任何格位getTileEntityBaseType():返回0(mType = 0)
NBT 存读
| 键 | 类型 | 内容 |
|---|---|---|
inputs |
Compound | inputItems.serializeNBT()(8 格) |
outputs |
Compound | outputItems.serializeNBT()(100 格) |
outputBuffer |
List of Compound | 尚未落进 outputs 的待发放物品队列 |
存档兼容:loadNBTData 读取后会比较 getSlots() 与当前常量。若旧存档格数不符(例如历史版本格数更多),
超出部分不会丢失,会被转移到 outputBuffer 里(见 MTEVendingMachine.java:485-513),并 markDirty()。
注意:
currentUser、syncTrades、mUpdate、ticksSinceOutput等运行时字段不写入 NBT。
出货节流
dispenseItems() 每 tick 调用,但发放间隔由 getDispensingDelay() 动态决定:
int baseDelay = 10;
double acceleration = Math.log(outputBuffer.size());
if (acceleration < 1) return baseDelay;
return (int) (baseDelay / acceleration);
| 队列长度 | 发放间隔 |
|---|---|
| 1 ~ 2 | 10 tick |
| 3 | 10 / ln(3) ≈ 9 tick |
| 10 | 10 / ln(10) ≈ 4 tick |
| 20 | 10 / ln(20) ≈ 3 tick |
| e^10 ≈ 22026 | 1 tick |
newBufferedOutputs 为 true 时(刚交易完)跳过延迟立即发一格。
掉落音效按物品类型区分:vendingmachine:coin_drop(货币)/ vendingmachine:item_drop(普通物品),
音量 0.6 + 0.4 * random(),音高 0.95 + 0.1 * random(),当前使用者位置单独补发一次。
交互
| 触发 | 行为 |
|---|---|
| 右键(空手/普通物品) | 记录 currentUser 后 openGui(aPlayer);若已有他人使用则提示 vendingmachine.gui.error.player_using |
| 右键(GTNH 多方块输入配置器) | 载入多方块输入配置 |
| 潜行 + 左键 GUI 出口滑槽 | fillPlayerInventoryWithDispensedItems() 把输出格物品塞进玩家背包(放不下即停) |
| 破坏 | 全部 108 格掉落 |
canUse(player) 逻辑为 currentUser == null || currentUser == player — 同一台机器同一时刻只有一名使用者,
不做任何权限等级检查,客户端关闭界面时通过 NetResetVMUser 包释放占用。
GUI 刷新
- 服务端
onPostTick:若currentUser != null且(syncTrades为真 或 距上次刷新 ≥gui_refresh_interval)则推送NetTradeDisplaySync - 配置
gui_refresh_interval默认 20 tick - 客户端
TradeMainPanel.onUpdate同样按ticksOpen % gui_refresh_interval重建列表
贴图与渲染
| 状态 | 贴图 |
|---|---|
| 正面熄灭 | VM_MACHINE_FRONT_OFF |
| 正面点亮 | VM_MACHINE_FRONT_ON + 发光层 VM_MACHINE_FRONT_ON_GLOW |
| 侧面 | VM_CASING_TEXTURE |
| 活动覆盖层 | VM_OVERLAY_ACTIVE(4 帧 .mcmeta 动画) |
| 非活动覆盖层 | VM_OVERLAY(5 帧) |
ICasingTextureProvider 返回 VM_CASING_TEXTURE;forceUseMui2() 恒为 true,强制使用 ModularUI 2 界面。
allowCoverOnSide 允许任何 allowOnPrimitiveBlock() 的 GTNH 面盖。
限制
- 结构不完整时 GUI 顶部显示
vendingmachine.gui.error.incomplete_structure,且所有交易格子被禁用 - 100 格输出格满了以后新交易会卡在
outputBuffer里,直到玩家取走物品 - 结构固定 6 格,无法扩建、无法旋转到竖直朝向
- 无检查模式(
checkMachine不插入方块),无自动化推拉接口
相关条目
- 自动售货机外壳 - 结构材料
- ME 售货机上行接口 - 可选网络直连
- 交易与定价系统 - 价格、货币、冷却的完整规则