Run any Skill in Manus
with one click
with one click
Run any Skill in Manus with one click
Get Started$pwd:
$ git log --oneline --stat
stars:381
forks:121
updated:March 30, 2026 at 02:55
File Explorer
SKILL.md
Maintain and document the TabooLib incision module. Use when working on runtime weaving, Scalpel DSL, @Surgeon annotations, dispatcher/registry flow, remap/version matching, bytecode site matching, Incision-Test fixtures, or incision user/design documentation in this repository.
创建补丁:收集需求信息,在主仓库创建 Issue,创建本地分支,进入规划模式。
完成补丁:推送分支到个人仓库,向主仓库提交 PR。
| name | taboolib-multiblocks |
| description | 在 TabooLib 中,定义和验证多方块结构(Multiblock)。 (project) |
如果要使用多方块结构功能,要遵守以下规则:
DenseMultiblock(字符图案),大型稀疏结构用 SparseMultiblock(坐标映射)pattern 数组第一个元素 = 最顶层(最高 Y),最后一个 = 最底层;每个 String 数组元素是一行 Z(北→南),字符串中每个字符是 X 列(西→东)'0' 字符必须恰好出现一次作为锚点;稀疏型锚点默认在 (0,0,0)'0'、'_'、空格外)都必须在 mapping 中定义,否则会映射为空气StringStateMatcher.parse() 解析方块:支持 minecraft:stone(材质)、minecraft:stairs[facing=north](带属性)、#minecraft:wool(标签)三种格式symmetrical = true:如果结构在水平面上关于中心轴对称,设置此标志可跳过多余旋转检测,性能提升约 4 倍MultiblockRegistry 注册:使用 命名空间:名称 格式的 ID 进行全局注册| 类 | 说明 |
|---|---|
DenseMultiblock | 密集型:用字符图案 Array<Array<String>> 定义结构 |
SparseMultiblock | 稀疏型:用 Map<BlockPos, IStateMatcher> 定义结构 |
StateMatcher | 内置匹配器工厂(ANY/AIR/fromMaterial/fromBlockData/fromPredicate/displayOnly) |
StringStateMatcher | 从字符串解析匹配器(材质名/方块属性/标签) |
MultiblockRegistry | 全局注册表(register/get/unregister/getAll/clear) |
BlockPos | 整数坐标,支持 +/- 运算和 rotate() 旋转 |
MultiblockRotation | 旋转枚举(NONE/CLOCKWISE_90/CLOCKWISE_180/COUNTERCLOCKWISE_90) |
IMultiblock | 核心接口(validate/simulate/test/offset) |
IStateMatcher | 方块匹配器接口(displayName/test) |
SimulateResult | 模拟结果(worldPosition/stateMatcher/character) |
| 字符 | 含义 | 默认匹配器 | 可否在 mapping 中覆盖 |
|---|---|---|---|
0 | 中心锚点(必须恰好一个) | StateMatcher.AIR | 可覆盖(如 '0' to parse("minecraft:lapis_block")) |
_ | 任意方块 | StateMatcher.ANY | 可覆盖 |
(空格) | 空气 | StateMatcher.AIR | 可覆盖(如 ' ' to StateMatcher.ANY) |
| 格式 | 示例 | 说明 |
|---|---|---|
| 材质名 | minecraft:stone | 匹配材质,忽略方块状态属性 |
| 方块数据 | minecraft:oak_stairs[facing=north,half=bottom] | 精确匹配,包括指定的状态属性 |
| 方块标签 | #minecraft:wool | 匹配标签中的所有方块 |
| 枚举值 | 角度 | (x, y, z) → |
|---|---|---|
NONE | 0° | (x, y, z) |
CLOCKWISE_90 | 顺时针 90° | (-z, y, x) |
CLOCKWISE_180 | 180° | (-x, y, -z) |
COUNTERCLOCKWISE_90 | 逆时针 90° | (z, y, -x) |
val altar = DenseMultiblock(
pattern = arrayOf(
// 顶层
arrayOf(
" ",
" S ",
" "
),
// 底层
arrayOf(
"SSS",
"S0S",
"SSS"
)
),
mapping = mapOf(
'S' to StringStateMatcher.parse("minecraft:stone_bricks")
)
)
MultiblockRegistry.register("my_plugin:altar", altar)
val stairAltar = DenseMultiblock(
pattern = arrayOf(
arrayOf(
" WWW ",
"N S",
"N 0 S",
"N S",
" EEE "
)
),
mapping = mapOf(
' ' to StateMatcher.ANY,
'0' to StringStateMatcher.parse("minecraft:lapis_block"),
'N' to StringStateMatcher.parse("minecraft:oak_stairs[facing=south]"),
'S' to StringStateMatcher.parse("minecraft:oak_stairs[facing=north]"),
'W' to StringStateMatcher.parse("minecraft:oak_stairs[facing=east]"),
'E' to StringStateMatcher.parse("minecraft:oak_stairs[facing=west]"),
)
).apply { symmetrical = true }
val fluidStructure = DenseMultiblock(
pattern = arrayOf(
arrayOf(
"GGGGGGG",
" LLLLLG",
"GGGGGGG",
" WW0WWG",
"GGGGGGG",
)
),
mapping = mapOf(
' ' to StateMatcher.ANY,
'0' to StringStateMatcher.parse("minecraft:lapis_block"),
'G' to StringStateMatcher.parse("minecraft:bricks"),
'W' to StringStateMatcher.parse("minecraft:water"),
'L' to StringStateMatcher.parse("minecraft:lava"),
)
)
val fourPillars = SparseMultiblock(
blocks = buildMap {
val pillar = StringStateMatcher.parse("minecraft:stone_bricks")
for (x in listOf(-3, 3)) {
for (z in listOf(-3, 3)) {
for (y in 0..2) {
put(BlockPos(x, y, z), pillar)
}
}
}
put(BlockPos(0, 0, 0), StringStateMatcher.parse("minecraft:diamond_block"))
}
)
val anchor = BlockPos(block.x, block.y, block.z)
// 自动尝试所有旋转(非对称 = 4 方向,对称 = 1 方向)
val rotation = multiblock.validate(world, anchor)
if (rotation != null) {
// 匹配成功,rotation 为匹配时的旋转方向
}
val results = multiblock.simulate(anchor, rotation)
for (result in results) {
val pos = result.worldPosition
val block = world.getBlockAt(pos.x, pos.y, pos.z)
if (!result.stateMatcher.test(block)) {
println("缺失: $pos 需要 ${result.stateMatcher.displayName}")
}
}
val mapping = mapOf(
'F' to StateMatcher.fromMaterial(Material.FURNACE),
'I' to StateMatcher.fromPredicate("iron_or_gold") { block ->
block.type == Material.IRON_BLOCK || block.type == Material.GOLD_BLOCK
},
'W' to StringStateMatcher.parse("#minecraft:planks"),
'T' to StringStateMatcher.parse("#minecraft:logs"),
)