墙面标识
基本信息
| 属性 | 值 |
|---|---|
| 实现类 | modernmarkings.blocks.MarkingWall(继承 BlockBase) |
| 方块数 | 83 |
| 注册位置 | modernmarkings.init.ModBlocks 的 new MarkingWall(...) 静态字段 |
| 材质 | Material.carpet |
| 碰撞 | 无(getCollisionBoundingBoxFromPool 返回全 0 包围盒) |
| 厚度 | 0.01(setBlockBoundsBasedOnState) |
| 渲染 | 自定义 ISimpleBlockRendering(renderMarkingWallID) |
| 参考实现 | 注释指明参照原版 BlockSign 的贴附逻辑 |
83 个方块涵盖工厂安全标识:电压等级牌、危险符号、编号、方向箭头、字母。
分类统计
| 类别 | 数量 | 成员示例 |
|---|---|---|
| 字母 A–Z | 26 | wall_marking_letter_a … wall_marking_letter_z |
| 电压等级 | 18 | voltage_eu / voltage_ev / voltage_fe / voltage_hv / voltage_iv / voltage_luv / voltage_lv / voltage_max / voltage_mv / voltage_pert / voltage_rf / voltage_uev / voltage_uhv / voltage_uiv / voltage_umv / voltage_uv / voltage_uxv / voltage_zpm |
| 数字 | 15 | number_0 … number_9 + number_no / number_numero / number_dash / number_comma / number_period |
| 危险符号 | 14 | symbol_chemical / symbol_electric / symbol_fire / symbol_fluid / symbol_frost / symbol_gears / symbol_laser / symbol_magic / symbol_mob / symbol_pinch / symbol_production / symbol_radiation / symbol_radiation_2 / symbol_storage |
| 危险线 | 2 | hazardline_left / hazardline_right |
| 出口 | 1 | wall_marking_exit |
| 单位牌 | 1 | unit |
| 急救 | 1 | first_aid |
| 灭火器 | 1 | fire_extinguisher |
| 警告 | 1 | warning_danger |
| 箭头 | 2 | arrowleft / arrowright |
| 菱形危险 | 1 | hazard_diamond |
合计 83。
[!NOTE] 18 个电压等级覆盖 GT 电力体系的 EU 到 ZPM 全套(
voltage_luv是 LuV 而非voltage_lv的误写——两者都存在,luv是小写 u 的正确拼写)。
放置:只能贴侧壁
onBlockPlaced 显式拒绝上下表面:
if (side != 0 && side != 1) { // 0 = DOWN, 1 = UP
return side;
}
return getDirectionFromPlacedPlayer(world, x, y, z);
即点顶面/底面时直接返回原 side(放置失败),只有 4 个侧面才继续。方向不看点击的面,而是用最近玩家的朝向决定贴附哪一面:
getDirectionFromPlacedPlayer 取 world.getClosestPlayer(x, y, z, -1),把 rotationYaw 折成 4 个 rotation,返回值直接是 ForgeDirection 的序号:2 = 北、3 = 南、4 = 西、5 = 东。
[!WARNING] 源码缺陷
MarkingWall.java:44-45的getClosestPlayer(x, y, z, -1)可能返回 null(半径 -1 表示不限距离,周围 7×7×7 无玩家时即为 null),紧接着player.rotationYaw会抛NullPointerException。该方法被onBlockPlaced(第 40 行)和canPlaceBlockAt(第 150 行)调用,两处都没有做 null 检查。实际触发需要在无玩家的位置对方块交互。
canPlaceBlockAt 随后校验目标那一面确实是实心的:world.isSideSolid(x + dir.offsetX, y, z + dir.offsetZ, dir, false)。
元数据与包围盒
setBlockBoundsBasedOnState 按 meta 把方块压成 0.01 厚的薄片,紧贴对应墙面:
| meta | 朝向 | min/max |
|---|---|---|
| 2 | 北 | z ∈ [1 - 0.01, 1] |
| 3 | 南 | z ∈ [0, 0.01] |
| 4 | 西 | x ∈ [1 - 0.01, 1] |
| 5 | 东 | x ∈ [0, 0.01] |
| 其它 | 兜底 | 整格 0,0,0 – 1,1,1 |
getSelectedBoundingBoxFromPool 读世界元数据返回同样的薄片 AABB,让选中框也跟着贴到墙上。
依赖方块变化:正反面不对称
onNeighborBlockChange 判定支撑时多了 .getOpposite():
ForgeDirection dir = ForgeDirection.getOrientation(meta).getOpposite();
而 canPlaceBlockAt 用的是不带 getOpposite 的方向。源码里作者自己留了注释:
// I have no idea why .getOpposite is required here when it's not in canPlaceBlockAt, but it works like this
结果是:放置时校验的是正面所依附的墙是否实心,拆除时校验的却是背面的墙。两侧的判定条件并不一致。
判定失败时同样 setBlockToAir + dropBlockAsItem,即标识掉落为物品并消失。
相关条目
- 地面标线 - 铺地的 87 个兄弟方块
- Chisel 雕刻组 - 全部 83 个进
Wall blocks组 - 燃料与合成 -
wall_marking_exit的配方