移动占位方块(BlockMovingRow)
ForgeRelocation 内部方块。结构开始移动时,它会临时占据每一行最前端的那一格,从而让整行方块在动画期间表现为"前移一格"。
方块名 relocation.blockmovingrow,由 mrtjp.relocation.blocks.BlockMovingRow 定义。mcmod.info 里的描述只有一句:“Move blocks from one place to another”。
基本属性
继承自 MrTJPCore 的 InstancedBlock(带 TileEntity 的方块基类),后者在构造时执行 GameRegistry.registerBlock(this, getItemBlockClass, name),因此本方块会自动注册出一个 ItemBlockCore。
| 属性 | 值 | 来源 |
|---|---|---|
| 方块名 | relocation.blockmovingrow |
blocks.scala:22 |
| 基类 | mrtjp.core.block.InstancedBlock |
blocks.scala:22 |
| 材质 | Material.iron |
blocks.scala:22 |
| 硬度 | -1f(setHardness(-1f)) |
blocks.scala:23 |
| 脚步声 | Block.soundTypeGravel |
blocks.scala:24 |
| 创造栏 | setCreativeTab(null)——不进创造模式物品栏 |
blocks.scala:25 |
| TileEntity | addSingleTile(classOf[TileMovingRow]) |
blocks.scala:26 |
抗爆 setResistance |
无(全仓库该方块未调用) | — |
| 光照等级 | 无 | — |
因为 setCreativeTab(null),这个方块无法被玩家以任何方式获得——它只由代码在移动开始时放置、移动结束时清除。
放置与清除
TileMovingRow.setBlockForRow(w, r) 对每一行调用:
w.setBlock(r.pos.x, r.pos.y, r.pos.z, RelocationMod.blockMovingRow, 0, 3)
meta 恒为 0;更新标记 3 即二进制 11(发送方块更新 + 抑制邻居更新)。整个移动过程不靠 metadata 表达方向——方向信息在 BlockRow.moveDir 与网络描述符里,不在方块状态里。
TileMovingRow.update() 是它的自愈逻辑:
override def update() {
if (!MovementManager2.isMoving(world, x, y, z)) world.setBlockToAir(x, y, z)
}
若世界状态与占位方块不同步(例如结构已被移除),该方块在下一次更新时把自己变成空气。
碰撞箱 = 前方方块的箱子
TileMovingRow 覆写 getBlockBounds 与 getCollisionBounds(后者直接返回前者),从运动中的结构里按坐标反查自己所属的 BlockRow,再算出动态碰撞箱:
override def getBlockBounds = {
val s = MovementManager2.getEnclosedStructure(world, x, y, z)
if (s != null) {
val r = s.rows.find(_.contains(x, y, z)).get
TileMovingRow.getBoxFor(world, r, s.progress)
} else Cuboid6.full
}
getBoxFor 的逻辑(blocks.scala:34-47):取 p = r.pos.copy.offset(r.moveDir ^ 1)(占位方块身后那一格,即真正被推走的方块)。
- 若
p处也是blockMovingRow(相邻两行首尾相接的极端情况),返回满立方Cuboid6.full.copy() - 否则取该方块的
getCollisionBoundingBoxFromPool,减去r.pos的偏移,加上BlockCoord.sideOffsets(r.moveDir) * progress——碰撞箱因此跟随动画进度一起平移
这就是玩家在移动过程中能撞上"正在移动的方块"的原因:碰撞箱是按 progress 连续插值的,而方块本体还停在原位。
推动实体
pushEntities(r, progress) 由 BlockRow.pushEntities 每 tick 调用:
val box = Cuboid6.full.copy
.add(new Vector3(r.preMoveBlocks.head))
.add(new Vector3(BlockCoord.sideOffsets(r.moveDir)).multiply(progress))
.toAABB
val dp = (if (progress >= 1.0) progress + 0.1 else progress) - prevProg
val d = new Vector3(BlockCoord.sideOffsets(r.moveDir)) * dp
world.getEntitiesWithinAABBExcludingEntity(null, box) match {
case list: JList[_] =>
for (e <- list.asInstanceOf[JList[Entity]])
e.moveEntity(d.x, d.y max 0, d.z)
case _ =>
}
prevProg = progress
三点值得注意:
- 差分推动:不直接用绝对
progress,而是算出本 tick 的增量dp再乘方向向量,配合prevProg字段。 - 垂直方向不向下推:
d.y max 0——实体永远不会被压进地板。向下移动的结构不会把站在上面的实体拖下去。 - 末帧补偿:
progress >= 1.0时用progress + 0.1,多推 0.1 格,确保实体被推出方块原本占据的格位,而不是卡在边界上。
语言文件
显示名是 Moving Block,但语言键与文件都在 MCFrames 那边:
tile.relocation.blockmovingrow.name=Moving Block
它位于 src/main/resources/assets/mcframes/lang/en_US.lang——ForgeRelocation 自己没有 assets/relocation/ 目录,也没有 zh_CN.lang。见 配置文件 一节对资源文件的完整清单。
相关条目
- 运动模型(结构与行的分解) ——
TileMovingRow只是其中的渲染/碰撞/推实体一环,方块本体的搬移由ITileMover负责 - 方块搬运器注册表 ——
MovingTileRegistry如何决定某个方块用哪种搬运方式