漏斗与自动化流水线集成 (MC 26.2)
本文档详细解析 Minecraft 26.2 下 Item Clumps 的漏斗抽取机制、传输速率对齐、红石分拣器稳定性及容器集成细节。
📊 特性信息框
| 属性 | 技术规格 |
|---|---|
| 系统名称 | 漏斗滴灌式抽取引擎 |
| 目标类 | net.minecraft.world.level.block.entity.HopperBlockEntity |
| 抽取方法 | HopperBlockEntity.addItem(Container, ItemEntity) |
| 抽取速率 | 每 $8\text{ tick}$ 抽取 $1\text{ 个物品}$($2.5\text{ 个/秒}$) |
| 数量扣减策略 | originalStack.shrink(1) 伴随 entity.setItem() 元数据刷新 |
| 自动化兼容 | 100% 兼容原版红石物品分拣器与漏斗过滤器 |
⚙️ 自动化滴灌抽取架构
在原版 Minecraft 中,若掉落物堆叠 $\le 64$ 且漏斗有空位,漏斗会一次性吸收整个实体。若模组盲目允许漏斗直接吸收包含 $5,000$ 个物品的巨型聚合体,会导致漏斗瞬间爆满或遗失数千物品。
Item Clumps 拦截 HopperBlockEntity.addItem 以强制执行滴灌抽取:
┌────────────────────────────┐
│ Hopper Tick Cycle │
│ (Every 8 Game Ticks) │
└─────────────┬──────────────┘
│
▼
┌────────────────────────────┐
│ Is Item Entity Count > 1? │
└─────────────┬──────────────┘
│
┌────────────────┴────────────────┐
│ (Yes) │ (No)
▼ ▼
┌───────────────────────────┐ ┌───────────────────────────┐
│ Clone Single Item Slice │ │ Native Vanilla Extraction │
│ baseItem = stack.copy(1) │ │ (Standard 1-item / stack) │
└─────────────┬─────────────┘ └───────────────────────────┘
│
▼
┌───────────────────────────┐
│ Try Insert Into Hopper │
│ HopperBlockEntity.addItem │
└─────────────┬─────────────┘
│
┌────────┴────────┐
│ │
(Success) (Failed / Full)
│ │
▼ ▼
┌───────────────────┐ ┌───────────────┐
│ Shrink Ground │ │ Abort Transfer│
│ Clump by 1; │ │ Entity Retains│
│ Refresh Name Tag. │ │ Full Count. │
└───────────────────┘ └───────────────┘⏱️ 传输速率与红线漏斗分拣对齐
原版 Minecraft 漏斗以 8-tick 冷却时间运行($0.4\text{ 秒}$):
$$\text{Hopper Transfer Rate} = \frac{1\text{ item}}{8\text{ ticks}} = \frac{20\text{ ticks/s}}{8\text{ ticks}} = 2.5\text{ items/second}$$
由于 Item Clumps 每个周期精确只抽取 $1\text{ 个物品}$:
- 标准物品分拣器:保持 41-1-1-1-1 物品配置的漏斗以精确的原版速度汲取聚合体,绝不会过载比较器信号或烧毁相邻红石线。
- 水流水槽分拣线:漂过漏斗线上方的巨型聚合体被平稳逐个汲取,不会阻塞水流或产生密集实体推挤。
- 漏斗矿车:以两倍于普通漏斗的速度从巨型聚合体中吸取物品($1\text{ tick } 1\text{ 个} = 20\text{ 个/秒}$),完全对齐原版矿车特性。
💻 真实源码实现参考
源自 Minecraft 26.2 的 HopperBlockEntityMixin.java:
java
@Inject(method = "addItem(Lnet/minecraft/world/Container;Lnet/minecraft/world/entity/item/ItemEntity;)Z", at = @At("HEAD"), cancellable = true)
private static void item_clumps$customHopperExtract(Container container, ItemEntity entity, CallbackInfoReturnable<Boolean> cir) {
ItemStack itemStack = entity.getItem();
int count = itemStack.getCount();
if (count > 1) {
// Entity is a clump. Extract exactly 1 item slice.
ItemStack baseItem = itemStack.copyWithCount(1);
ItemStack result = HopperBlockEntity.addItem(null, container, baseItem, null);
if (result.isEmpty()) {
// Hopper successfully absorbed the 1 item. Shrink entity stack.
ItemStack originalStack = entity.getItem().copy();
originalStack.shrink(1);
entity.setItem(originalStack); // Updates standard item tracker and custom name
cir.setReturnValue(true);
} else {
// Hopper was full or couldn't accept item
cir.setReturnValue(false);
}
}
}