
多块系统
为构建多方块结构提供基础。
开发者请注意,请先运行命令 /mbs display true。
MultiBlockSystem
MultiBlockSystem 是一个为模组作者和整合包制作者设计的强大框架,用于轻松创建、验证和分发复杂的自定义多方块结构。通过提供精简的工具集,本模组将搭建庞大而复杂机械的过程转变为安全且高度优化的体验。
✨ 特性
灵活的模式设计:利用简单、直观的基于字符串的系统来定义多方块模式,支持从基础机械到巨大多层结构的一切。
高级结构验证:系统提供强大的视觉反馈,允许建造者切换验证显示,以确保每个方块都精确放置在需要的位置。
高性能扫描:通过智能的、基于后台的异步扫描,模组能够捕捉庞大的结构设计,即使是最复杂的构建,也不会影响服务器性能。
安全分发:内置的混淆和压缩功能确保您的自定义结构定义紧凑且安全,非常适合整合包开发者包含独特、专有的内容。
适合模组作者的命令套件:全面的命令行界面允许快速导出、重新加载和配置管理,而无需重启游戏。
1. 从其他模组注册的方法
build.gradle(软依赖)
dependencies {
// 使用 compileOnly 表示软依赖(游戏可以在没有此模组的情况下启动)
compileOnly fg.deobf("com.multiblocksystem:multiblocksystem:1.0.0:api")
}
mods.toml
[[dependencies.yourmod]]
modId="multiblocksystem"
mandatory=false # 软依赖 = 没有此模组也能启动
versionRange="[1.0,)"
ordering="BEFORE"
side="BOTH"
注册代码
// YourMod.java
@Mod("yourmod")
public class YourMod {
public YourMod() {
FMLJavaModLoadingContext.get().getModEventBus()
.addListener(this::onCommonSetup);
}
private void onCommonSetup(FMLCommonSetupEvent event) {
event.enqueueWork(() -> {
if (!ModList.get().isLoaded("multiblocksystem")) return;
YourMultiBlockSetup.register();
});
}
}
// YourMultiBlockSetup.java
public class YourMultiBlockSetup {
public static void register() {
// ===== 1. 注册控制器方块 =====
MultiBlockRegistry.registerAsController(
new ResourceLocation("yourmod", "blast_furnace_controller"),
new BlastFurnaceControllerBehavior()
);
// ===== 2. 将您的方块注册为 INPUT =====
// 如果拥有 IItemHandler Capability,一行代码即可
MultiBlockRegistry.registerAsLinkable(
new ResourceLocation("yourmod", "input_hopper"),
LinkRole.INPUT,
LinkableBehavior.fromForgeCapability()
);
// ===== 3. 将原版箱子注册为 INPUT =====
// (原版方块也可以注册)
MultiBlockRegistry.registerAsLinkable(
Blocks.CHEST,
LinkRole.INPUT,
LinkableBehavior.fromForgeCapability()
);
// ===== 4. 自定义存储则需要自行实现 =====
MultiBlockRegistry.registerAsLinkable(
new ResourceLocation("yourmod", "big_tank"),
LinkRole.FUEL,
new LinkableBehavior() {
@Override
public IFluidStorage getFluidStorage(Level level, BlockPos pos) {
BlockEntity be = level.getBlockEntity(pos);
if (be instanceof BigTankBlockEntity tank) {
return tank.getFluidStorage();
}
return null;
}
@Override
public boolean hasFluidStorage() { return true; }
@Override
public boolean hasItemStorage() { return false; }
}
);
// ===== 5. 注册结构体形状 =====
MultiBlockRegistry.registerStructure(
new ResourceLocation("yourmod", "blast_furnace"),
StructureDefinition.fromPattern(
List.of(
new String[]{"FFF", "FCF", "FFF"}, // Y=0
new String[]{" ", " . ", " "} // Y=1
),
Map.of(
'F', Blocks.BLAST_FURNACE.defaultBlockState(),
'C', YourBlocks.BLAST_FURNACE_CONTROLLER.get().defaultBlockState()
),
'C'
),
new CapabilitySpec()
.require(LinkRole.INPUT, 1)
.require(LinkRole.OUTPUT, 1)
);
// ===== 6. 注册端口方块(支持4层检测) =====
// 第1层:直接在方块类上实现 IPortBlock 接口的方法
// 第2层:通过 API 注册的方法(如下所示)
// 第3层:如果有 Forge Capability 则自动适配(IItemHandler/IEnergyStorage/IFluidHandler)
// 第4层:通过数据包的方块标签注册(data/multiblocksystem/tags/blocks/multiblock_ports.json)
MultiBlockRegistry.registerPort(
new ResourceLocation("yourmod", "item_input_port"),
PortRegistry.get(new ResourceLocation("multiblocksystem", "item_input"))
);
MultiBlockRegistry.registerPort(
new ResourceLocation("yourmod", "energy_output_port"),
PortRegistry.get(new ResourceLocation("multiblocksystem", "energy_output"))
);
}
}
2. ControllerBehavior 实现示例
public class BlastFurnaceControllerBehavior implements ControllerBehavior {
@Override
public ResourceLocation getDefaultStructureId() {
return new ResourceLocation("yourmod", "blast_furnace");
}
@Override
public void onFormed(Level level, BlockPos pos, IMultiBlockNetwork network) {
BlockEntity be = level.getBlockEntity(pos);
if (be instanceof BlastFurnaceControllerBE ctrl) {
ctrl.setFormed(true);
}
}
@Override
public void onBroken(Level level, BlockPos pos, IMultiBlockNetwork network) {
BlockEntity be = level.getBlockEntity(pos);
if (be instanceof BlastFurnaceControllerBE ctrl) {
ctrl.setFormed(false);
}
}
@Override
public void tick(Level level, BlockPos pos, IMultiBlockNetwork network) {
IItemStorage input = network.getItemStorage(LinkRole.INPUT);
IItemStorage output = network.getItemStorage(LinkRole.OUTPUT);
Amount inputCost = Amount.of(3);
Amount outputYield = Amount.of(5);
boolean canRun = network.canProcess(
List.of(IBigItemStack.of(Items.IRON_ORE, inputCost)),
List.of(IBigItemStack.of(Items.IRON_INGOT, outputYield))
);
if (!canRun) return;
// 消耗 1/3 FE/tick 的配方
Amount energyCost = Amount.of(1, 3);
Amount consumed = network.consumeEnergy(energyCost, true);
if (!consumed.isGreaterThanOrEqual(energyCost)) return;
network.consumeEnergy(energyCost, false);
network.processTransfer(
List.of(IBigItemStack.of(Items.IRON_ORE, inputCost)),
List.of(IBigItemStack.of(Items.IRON_INGOT, outputYield))
);
}
}
3. Amount 计算的具体示例
Amount 是一个封闭接口(sealed interface),其实现仅限于两个 record 类:
| 实现 | 内部表示 | 用途 |
|---|---|---|
LongAmount |
long 分子 / 分母 |
一般值(高速) |
BigAmount |
BigInteger 分子 / 分母 |
超过 long 的超大值 |
工厂方法(Amount.of(...))会自动选择最优实现,并且当计算结果在 long 范围内时,BigAmount 会被降级为 LongAmount。
// 整数
Amount a = Amount.of(100); // → LongAmount(100, 1)
Amount b = Amount.of(3); // → LongAmount(3, 1)
// 分数
Amount oneThird = Amount.of(1, 3); // → LongAmount(1, 3)
Amount twoThirds = Amount.of(2, 3); // → LongAmount(2, 3)
Amount half = Amount.of(1, 2); // → LongAmount(1, 2)
// 四则运算(均为返回新 Amount 的不可变操作)
Amount sum = oneThird.add(twoThirds); // 1/3 + 2/3 = 1 → LongAmount(1, 1)
Amount diff = a.subtract(b); // 100 - 3 = 97
Amount product = oneThird.multiply(3); // 1/3 * 3 = 1(零误差)
Amount quotient = a.divide(b); // 100 / 3 = 100/3
// 比较
boolean gt = a.isGreaterThan(b); // true
boolean gte = oneThird.isGreaterThanOrEqual(half); // false
boolean eq = product.equals(Amount.ONE); // true
// 转换
BigInteger val1 = product.floor(); // BigInteger(1)
BigInteger val2 = quotient.ceil(); // BigInteger(34)
double val3 = oneThird.toDouble(); // 0.33333...(用于显示)
// 显示
System.out.println(oneThird.toDisplayString()); // "1/3 (≈0.333333)"
System.out.println(product.toDisplayString()); // "1"
System.out.println(quotient.toDisplayString()); // "100/3 (≈33.333333)"
// 字符串序列化(用于 JSON 保存)
String json = oneThird.toSerialString(); // "1/3"
Amount restored = Amount.fromSerialString(json); // → LongAmount(1, 3)
// NBT 序列化
CompoundTag tag = oneThird.toNbt();
Amount fromTag = Amount.fromNbt(tag);
// 能量效率计算(零误差)
Amount efficiency = Amount.of(2, 3); // 66.666...%
Amount baseCost = Amount.of(100);
Amount actualCost = baseCost.multiply(efficiency); // 200/3 FE
long floorCost = actualCost.floor().longValueExact(); // 66(仅写入 Minecraft 时使用)
LongAmount 的自动升级
LongAmount 使用 Math.multiplyExact / Math.addExact 进行溢出检测,当结果超出 long 范围时,会自动升级为 BigAmount:
Amount huge = Amount.of(Long.MAX_VALUE);
Amount one = Amount.of(1);
Amount result = huge.add(one); // → BigAmount (超出 long 范围,自动升级)
BigAmount 的自动降级
BigAmount 在计算结果分子和分母都在 long 范围内时,会自动降级为 LongAmount:
Amount big = Amount.of(BigInteger.valueOf(99999999999L), BigInteger.valueOf(3));
Amount small = Amount.of(3);
Amount result = big.multiply(small); // → LongAmount (结果在 long 范围内)
4. /mbs 命令参考
MultiBlockSystem 提供以下服务器命令:
/mbs export
扫描指定范围的方块,生成多方块定义文件。
/mbs export <pos1> <pos2> <core> <filename> [ex1_pos1] [ex1_pos2] ... [exN_pos1] [exN_pos2]
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
pos1 |
BlockPos | 是 | 扫描范围的角坐标(支持相对坐标 ~ ~ ~) |
pos2 |
BlockPos | 是 | 扫描范围的另一个角坐标 |
core |
BlockPos | 是 | 控制器方块的坐标(相对坐标的原点) |
filename |
String | 是 | 输出文件名(无需 .json 扩展名) |
exN_pos1 |
BlockPos | 否 | 排除区域 N 的角坐标(支持 Tab 补全) |
exN_pos2 |
BlockPos | 否 | 排除区域 N 的另一个角坐标 |
排除区域:由每个 ex_pos1 / ex_pos2 对定义的 AABB(轴对齐边界框)内的方块将不被扫描。最多可指定 200 个排除区域(由于 Forge 命令树递归深度限制)。
# 基本示例
/mbs export ~ ~ ~ ~10 ~10 ~10 ~ ~5 my_structure
# 带排除区域的示例(排除第150层到第300层)
/mbs export 0 0 0 100 300 100 ~ ~150 my_tower 0 150 0 100 300 100
/mbs reload
重新加载磁盘上的多方块定义文件。
/mbs reload
将重新扫描 multiblocks/ 目录中的所有 .json 文件,并更新结构体定义。控制器和链接方块的注册不会被清除(因为它们只在 FMLCommonSetupEvent 中注册一次)。
/mbs display
切换结构正确性显示的标记。
/mbs display [enabled]
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
enabled |
boolean | 否 | true 开启显示,false 关闭显示 |
无参数执行时显示当前状态。
5. BigInteger 存储支持
IBigIntegerItemHandler
IBigIntegerItemHandler 是将 Forge 的 IItemHandler 扩展到 BigInteger 规模的鸭子接口(直接继承自 IItemHandler)。
| 方法 | 说明 |
|---|---|
getSlotLimitBig(int slot) |
以 BigInteger 返回槽位的最大容量 |
insertItemBig(int slot, ItemStack, BigInteger, boolean) |
以 BigInteger 规模插入物品 |
extractItemBig(int slot, Item, BigInteger, boolean) |
以 BigInteger 规模提取物品 |
getTotalCountBig(Item) |
以 BigInteger 返回指定物品在所有槽位的总持有量 |
所有方法都包含默认实现,即使对于未实现的 IItemHandler,也能保证基于 long 的回退行为。
MixinItemStackHandler
为 Forge 的 ItemStackHandler(具体类)自动附加 IBigIntegerItemHandler 的 Mixin。
// multiblocksystem.mixins.json
{
"mixins": ["MixinItemStackHandler"]
}
由于 ItemStackHandler 已经实现了 IItemHandler,IBigIntegerItemHandler 的默认方法会直接调用 getSlots()、insertItem()、getSlotLimit() 等来提供 BigInteger 操作。这是一个仅用于标记的 Mixin,不包含额外代码。
检测方法:
IItemHandler handler = ...;
if (handler instanceof IBigIntegerItemHandler bigHandler) {
// 使用 BigInteger 规模的操作
BigInteger limit = bigHandler.getSlotLimitBig(slot);
} else {
// 常规 IItemHandler — ForgeItemHandlerAdapter 回退到 long 基础
}
ForgeItemHandlerAdapter 的双重路径
ForgeItemHandlerAdapter 是 IItemHandler → IItemStorage 的桥接器,通过 instanceof IBigIntegerItemHandler 检查执行双重路径处理:
- 支持 BigInteger 时:直接调用
IBigIntegerItemHandler的方法 - 不支持时:回退到基于
long的聚合
Forge 标准的 ItemStackHandler 通过 Mixin 自动支持 BigInteger。拥有自定 IItemHandler 实现的模组可以手动实现 IBigIntegerItemHandler 以启用 BigInteger 操作。
6. KubeJS 集成
MultiBlockSystem 作为可选的软依赖集成了对 KubeJS 的支持。即使在不存在 KubeJS 的环境中,模组也能正常运行。
6.1 插件注册
KubeJS 会从 src/main/resources/kubejs.plugins.txt 自动检测插件:
// src/main/resources/kubejs.plugins.txt
com.multiblocksystem.kubejs.MultiBlockKubeJSPlugin multiblocksystem
6.2 KubeJSPlugin(Java 侧)
package com.multiblocksystem.kubejs;
import dev.latvian.mods.kubejs.KubeJSPlugin;
import dev.latvian.mods.kubejs.script.BindingsEvent;
import dev.latvian.mods.kubejs.script.ScriptType;
import com.multiblocksystem.api.behavior.LinkRole;
import com.multiblocksystem.CapabilitySpec;
public class MultiBlockKubeJSPlugin extends KubeJSPlugin {
@Override
public void registerBindings(BindingsEvent event) {
if (event.getType() != ScriptType.STARTUP) return;
event.add("MultiBlockRegistry", new MultiBlockRegistryJS());
event.add("LinkRole", LinkRole.class);
event.add("CapabilitySpec", CapabilitySpec.class);
}
}
注意: 方法名是
registerBindings而非addBindings。它定义在 KubeJS 2001.x (Forge 1.20.1) 的KubeJSPlugin基类中。
6.3 注册适配器(MultiBlockRegistryJS)
从 KubeJS 脚本调用的包装类。负责 String → ResourceLocation 转换、JS 对象 → BlockState 转换。
| 方法 | 说明 |
|---|---|
registerController(String, ControllerBehavior) |
通过方块 ID 注册控制器 |
registerController(Block, ControllerBehavior) |
通过 Block 对象注册控制器 |
registerLinkable(String, LinkRole) |
通过方块 ID 注册链接方块(自动检测 Forge IItemHandler) |
registerLinkable(String, LinkRole, LinkableBehavior) |
通过方块 ID 注册链接方块(自定义行为) |
registerLinkable(Block, LinkRole) |
通过 Block 对象注册链接方块 |
registerPort(String, String) |
通过方块 ID 和端口 TypeID 注册端口方块 |
registerStructure(String, List<String[]>, Map, String) |
通过 KubeJS 风格的字符串模式注册结构体 |
registerStructure(String, List<String[]>, Map, String, CapabilitySpec) |
注册结构体(带规格) |
isController(String) |
检查指定方块是否已注册为控制器 |
isLinkable(String) |
检查指定方块是否已注册为链接方块 |
isPort(String) |
检查指定方块是否已注册为端口 |
6.4 KubeJS 脚本示例(startup_scripts/my_multiblocks.js)
// KubeJS 在 MultiBlockSystem 加载后执行脚本,因此可以直接从全局使用 MultiBlockRegistry,而无需等待 StartupEvents.postInit。
// ===== 注册控制器方块 =====
MultiBlockRegistry.registerController(
"mymod:blast_furnace_controller",
{
getDefaultStructureId: () => "mymod:blast_furnace",
onFormed: (level, pos, network) => {
console.log("Blast furnace formed at " + pos);
},
tick: (level, pos, network) => {
const input = network.getItemStorage(LinkRole.INPUT);
const output = network.getItemStorage(LinkRole.OUTPUT);
const cost = Amount.of(3);
const yield = Amount.of(5, 2);
const canRun = network.canProcess(
[{ item: "minecraft:iron_ore", count: cost }],
[{ item: "minecraft:iron_ingot", count: yield }]
);
if (!canRun) return;
network.processTransfer(
[{ item: "minecraft:iron_ore", count: cost }],
[{ item: "minecraft:iron_ingot", count: yield }]
);
}
}
);
// ===== 将原版方块注册为链接方块 =====
MultiBlockRegistry.registerLinkable("minecraft:chest", LinkRole.INPUT);
MultiBlockRegistry.registerLinkable("minecraft:barrel", LinkRole.OUTPUT);
// ===== 注册端口方块 =====
// 让尚未实现 IPortBlock 的方块被识别为端口
MultiBlockRegistry.registerPort("mymod:item_input_port", "multiblocksystem:item_input");
MultiBlockRegistry.registerPort("mymod:energy_output_port", "multiblocksystem:energy_output");
// ===== 注册结构体定义 =====
MultiBlockRegistry.registerStructure(
"mymod:blast_furnace",
[
["FFF", "FCF", "FFF"],
[" ", " . ", " "]
],
{
"F": "minecraft:blast_furnace",
"C": "mymod:blast_furnace_controller"
},
"C",
new CapabilitySpec()
.require(LinkRole.INPUT, 1)
.require(LinkRole.OUTPUT, 1)
);
6.5 build.gradle 设置(使用 KubeJS 时)
repositories {
maven {
url "https://maven.latvian.dev/releases"
content { includeGroup "dev.latvian.mods" }
}
}
dependencies {
// KubeJS 使用 compileOnly(运行时由 KubeJS 侧提供)
compileOnly fg.deobf("dev.latvian.mods:kubejs-forge:2001.6.5-build.26") {
transitive = false
}
}
API 包:
dev.latvian.mods.kubejs.*(不是dev.latvian.kubejs.*) Maven GAV:dev.latvian.mods:kubejs-forge:2001.6.5-build.26
7. Amount 计算的具体示例(JS)
// JS 侧的 Amount 计算示例
const a = Amount.of(1, 3); // 1/3
const b = Amount.of(1, 6); // 1/6
const c = a.add(b); // 1/3 + 1/6 = 1/2 ← 完全精确
const d = a.multiply(3); // 1/3 * 3 = 1 ← 零误差
console.log(c.toDisplayString()); // "1/2 (≈0.500000)"
console.log(d.toDisplayString()); // "1"
// 能量效率计算
const efficiency = Amount.of(2, 3); // 66.666...% efficiency
const baseCost = Amount.of(100); // 100 FE base cost
const actualCost = baseCost.multiply(efficiency); // 200/3 FE ← 零误差
// 仅在写入 Minecraft 时使用 floor/ceil
const longCost = actualCost.floor(); // 66 (BigInteger)
8. 注意事项
RegistryImpl.clearStructures() 的使用方法
/mbs reload 只应调用 clearStructures()。controllers 和 linkables 是在 FMLCommonSetupEvent 中注册的,因此不应在服务器重载时清除。
Amount 的 GCD 成本
LongAmount 使用基于 long 的高速 GCD,因此一般值的计算几乎是瞬时的。只有 BigAmount 使用 BigInteger.gcd(),具有 O(log n) 的成本。如果每帧大量调用,建议缓存到 final 字段中。
ForgeItemHandlerAdapter 的聚合上限
当 ForgeItemHandlerAdapter 检测到实现 IBigIntegerItemHandler 的 IItemHandler 时,会使用基于 BigInteger 的聚合(理论上无上限)。对于不支持的 IItemHandler,则使用 long 聚合,总容量可达 Long.MAX_VALUE(约 9.2×10¹⁸)。但单个槽位的操作受限于 Forge 的 IItemHandler,即每个槽位最多 Integer.MAX_VALUE 个物品。Forge 标准的 ItemStackHandler 已通过 Mixin 自动实现 IBigIntegerItemHandler,因此默认为 BigInteger 兼容。
StructureDefinition.fromPattern 的字符编码
| 字符 | 含义 |
|---|---|
(空格) |
任意(什么都可以,不参与判定) |
. (点) |
空气(必须为空) |
| 其他 | 必须为一词典中指定的方块 |
| coreChar | 控制器位置(相对坐标的原点) |
ExcludeRegion 的使用方法
ExcludeRegion 通过 AABB(轴对齐边界框)定义扫描排除的区域。可通过 /mbs export 命令的排除参数指定,或将 List<ExcludeRegion> 传给 ChunkScanTask 手动使用。
9. API 参考
9.1 核心类型
| 类 | 包 | 说明 |
|---|---|---|
Amount |
api.amount | 有理数类型封闭接口。通过 Amount.of(n) / Amount.of(n, d) 创建 |
LongAmount |
api.amount | long 分子/分母的 record。溢出时自动升级 |
BigAmount |
api.amount | BigInteger 分子/分母的 record。结果在 long 范围内时自动降级 |
IBigItemStack |
api.amount | Item + Amount 的组合。通过 IBigItemStack.of(item, amount) 创建 |
CapabilitySpec |
root | 多方块成立所需的链接配置。通过 .require(LinkRole, count) 添加 |
ExcludeRegion |
root | 扫描排除区域(AABB) |
→ 计算示例请参阅 第 3 节
9.2 链接方块用接口(由其他模组实现)
IMultiBlockController — 控制器 BlockEntity 实现
包: api.compat — 另请参阅 第 1 节的注册代码
| 方法 | 参数 | 说明 |
|---|---|---|
addLink(BlockPos, LinkRole) |
链接方块坐标, 角色 | 记录链接方块的连接 |
removeLink(BlockPos) |
链接方块坐标 | 解除链接 |
hasLink(BlockPos) |
方块坐标 | 检查指定坐标是否已链接 |
getLinkedBlocks() |
— | 返回所有链接目标的 Map<BlockPos, LinkRole> |
使用方法: 如果您的 BlockEntity 继承
AbstractMultiBlockController,将自动实现。手动实现时,可直接 implementsIMultiBlockController。
IMultiBlockLink — 链接方块的 BlockEntity 实现
包: api.compat
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
connectToController(BlockPos, LinkRole) |
控制器坐标, 角色 | void | 记录到控制器的连接 |
disconnectController() |
— | void | 解除连接 |
isConnected() |
— | boolean | 是否正在连接到控制器 |
getControllerPos() |
— | @Nullable BlockPos |
连接目标控制器坐标 |
getRole() |
— | LinkRole | 当前角色 |
getItemHandler() |
— | IItemHandler | 返回 Forge 的 IItemHandler |
使用方法: 如果您的 BlockEntity 继承
AbstractLinkBlockEntity,将自动实现。
9.3 抽象基类(通过继承使用)
AbstractMultiBlockController — 控制器 BlockEntity 的基类
包: com.multiblocksystem(根)
| 方法 | 类型 | 说明 |
|---|---|---|
tick() |
concrete | 主循环。每40 tick检查一次结构,成立期间调用 processRecipes() |
onFormationChanged(boolean formed) |
protected, 建议重写 | 结构成立状态变化时的回调 |
isFormed() |
concrete | 当前结构是否成立 |
getInventoryForRole(LinkRole) |
concrete | 指定角色的聚合 IItemHandler |
getInputInventory() / getOutputInventory() |
concrete | 常用角色的快捷方式 |
getTemplateId() |
concrete | 关联的结构定义的 ResourceLocation |
setTemplateId(ResourceLocation) |
concrete | 手动指定结构定义 |
继承时的最低实现:
public class MyControllerBE extends AbstractMultiBlockController {
public MyControllerBE(BlockPos pos, BlockState state) {
super(MY_BE_TYPE.get(), pos, state);
}
@Override
protected void onFormationChanged(boolean formed) {
// 结构成立/崩溃时的处理(GUI更新、粒子等)
}
}
详情请参阅 第 1 节的注册代码 / 第 2 节的实现示例
AbstractLinkBlockEntity — 链接方块的 BlockEntity 基类
包: com.multiblocksystem(根)
| 方法 | 类型 | 说明 |
|---|---|---|
connectToController(...) / disconnectController() |
concrete | IMultiBlockLink 的实现 |
isConnected() / getControllerPos() / getRole() |
concrete | 获取连接状态 |
getItemHandler() |
concrete | 返回内部的 ItemStackHandler(槽位数: DEFAULT_SLOTS = 9) |
onConnected(LinkRole role) |
protected, 建议重写 | 连接时的回调 |
onDisconnected() |
protected, 建议重写 | 断开时的回调 |
onDestroyed(Level) |
concrete | 从 Block.onRemove 调用以通知控制器 |
继承时的最低实现:
public class MyLinkBE extends AbstractLinkBlockEntity {
public MyLinkBE(BlockPos pos, BlockState state) {
super(MY_BE_TYPE.get(), pos, state);
}
@Override
protected void onConnected(LinkRole role) {
// 连接时的处理(视觉特效等)
}
}
9.4 行为定义接口(用于委派)
ControllerBehavior — 控制器的行为
包: api.behavior — 所有方法均有默认实现
| 方法 | 参数 | 说明 |
|---|---|---|
onFormed(Level, BlockPos, IMultiBlockNetwork) |
结构成立时调用 | |
onBroken(Level, BlockPos, IMultiBlockNetwork) |
结构崩溃时调用 | |
onLinked(Level, BlockPos, BlockPos, LinkRole, IMultiBlockNetwork) |
链接连接时调用 | |
onUnlinked(Level, BlockPos, BlockPos, LinkRole, IMultiBlockNetwork) |
链接断开时调用 | |
tick(Level, BlockPos, IMultiBlockNetwork) |
成立期间每 tick 调用 | |
getDefaultStructureId() |
负责的结构 ID(null 则自动判定) | |
getValidStructureIds() |
可负责的结构 ID 集合 | |
ControllerBehavior.simple(String) |
static | 最小配置的工厂 |
详情请参阅 第 2 节
LinkableBehavior — 链接方块的行为
包: api.behavior — 存储获取均返回 @Nullable 的默认实现
| 方法 | 返回值 | 说明 |
|---|---|---|
getItemStorage(Level, BlockPos) |
@Nullable IItemStorage |
物品存储 |
getEnergyStorage(Level, BlockPos) |
@Nullable IEnergyStorage |
能量存储 |
getFluidStorage(Level, BlockPos) |
@Nullable IFluidStorage |
流体存储 |
getGenericStorage(Level, BlockPos, ResourceKey) |
@Nullable IGenericStorage |
通用存储 |
onLinked(Level, BlockPos, LinkRole, IMultiBlockNetwork) |
void | 连接时回调 |
onUnlinked(Level, BlockPos, LinkRole) |
void | 断开时回调 |
hasItemStorage() / hasEnergyStorage() / hasFluidStorage() |
boolean | 存储有无的预先声明 |
LinkableBehavior.fromForgeCapability() |
static | 自动包装 Forge IItemHandler |
详情请参阅 第 1 节的注册代码
9.5 网络与注册
| 类/接口 | 包 | 说明 |
|---|---|---|
IMultiBlockNetwork |
api.network | 从控制器操作网络状态的入口(实现由内部提供) |
MultiBlockNetwork |
root | 控制器⇔链接方块的连接/断开逻辑(static utility) |
MultiBlockRegistry |
api.registration | API 的唯一注册窗口 |
StructureDefinition |
api.registration | 结构体定义包装器 |
MultiBlockEvent |
api | Forge 事件(Formed / Destroyed) |
MultiBlockAPI |
api | 内部运行时API(通常不直接使用) |
IPortBlock |
api.port | 作为端口方块的功能方块需要实现的接口 |
IPortType |
api.port | 定义端口类型的接口(getId / getCategory) |
PortRegistry |
api.port | IPortType 的全局注册表 |
MultiBlockTags |
api.tags | 数据包用标签定义(MULTIBLOCK_PORTS) |
IMultiBlockNetwork 的主要方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
getControllerPos() |
— | BlockPos | 控制器坐标 |
isFormed() |
— | boolean | 结构是否成立 |
getItemStorage(LinkRole) |
角色 | IItemStorage | 按角色获取物品存储(聚合) |
getAllItemStorage() |
— | IItemStorage | 跨所有角色的存储 |
getEnergyStorage(LinkRole) |
角色 | IEnergyStorage | 能量存储 |
getFluidStorage(LinkRole) |
角色 | IFluidStorage | 流体存储 |
canProcess(List<IBigItemStack>, List<IBigItemStack>) |
输入, 输出 | boolean | 检查是否可转移 |
processTransfer(List<IBigItemStack>, List<IBigItemStack>) |
输入, 输出 | boolean | INPUT→OUTPUT 物品转移 |
consumeEnergy(Amount, boolean) |
量, simulate | Amount | 能量消耗 |
详情请参阅 第 2 节的实现示例
9.6 存储接口
| 接口 | 包 | 主要方法 |
|---|---|---|
IItemStorage |
api.storage | insert(IBigItemStack, simulate) / extract(Item, Amount, simulate) / getCount(Item) / getCapacity() |
IEnergyStorage |
api.storage | 基于 BigInteger 的能量 |
IFluidStorage |
api.storage | 基于 BigInteger 的流体 |
IGenericStorage |
api.storage | 通用资源(魔力、热量等) |
9.7 BigInteger 支持(内部机制)
| 类 | 包 | 说明 |
|---|---|---|
IBigIntegerItemHandler |
api.compat | 将 IItemHandler 扩展到 BigInteger 规模的鸭子接口 |
ForgeItemHandlerAdapter |
api.behavior | IItemHandler → IItemStorage 桥接器(自动检测 BigInteger) |
MixinItemStackHandler |
mixin | 为 ItemStackHandler 自动附加 IBigIntegerItemHandler 的标记 Mixin |
详情请参阅 第 5 节
9.8 端口方块相关(4层检测)
结构体内端口坐标处由玩家放置的方块是否被认可为所需端口,按以下优先级检测:
| 层 | 检测方法 | 条件 |
|---|---|---|
| 第1层 | IPortBlock 接口 |
方块类实现 IPortBlock,且 getPortType().getId() 匹配 |
| 第2层 | MultiBlockRegistry API 注册 |
通过 registerPort() 注册的方块 ID,且 IPortType 匹配 |
| 第3层 | Forge Capability |
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。