自动售货机

基本信息

属性 值
注册名 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 = 20 tick 一次(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 < 108
  • shouldDropItemAt(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 不插入方块),无自动化推拉接口

相关条目