星门(Stargate)

[!IMPORTANT] 本文所有坐标偏移、方块数量与 metadata 要求均逐行对照 BlockStargateController.runStructureCheck()(源码 81–97 行)与 formGate()(102–122 行)得出,偏移方向经 StructureUtil.rotate() 旋转。

星门是 StargateNH 唯一的玩家自建多方块结构。它是一个 5×5 的拱门:中央竖立一个星门控制器方块作为核心,周围 15 个方块按固定的拱形排布。结构满足后全部方块会被自动替换为不可见的"已成形"方块,由 TESR 渲染出星门模型。玩家再用一个拨号装置为星门设定 7 位地址,即可与其他星门互联传送。

基本信息

属性 值
结构名 Stargate(星门)
核心方块 星门控制器方块(stargatenh:<group>_stargate_controller)
必需方块 星门雪佛龙方块(meta 1)×7、星门环方块(meta 0)×8
可选方块 无(结构尺寸固定,不可放大或缩小)
结构方块总数 16(1 控制器 + 7 雪佛龙 + 8 环)
外形尺寸 宽 5 × 高 5 × 厚 1(沿朝向方向厚度为 1)
材质 全部为 Material.iron
TileEntity TileStargateController,注册 ID TileEntityStargateControllerNH
能量消耗 无。本 mod 不含任何能量系统(详见下节)

能量与成本模型

本 mod 没有能量、功率或消耗概念。 对全部 Java 源码检索 energy / power / cost / ForgeEnergy / IEnergy / EU 均无任何匹配;TileStargateController 未实现任何 Forge 能量接口,也没有 setHardness / setResistance / setLightLevel 调用。

因此激活一座星门的真实成本只有三项,全部是逻辑性的:

成本项 说明 依据
16 个方块 组装结构所需建材 formGate()
1 个地址 该星门被永久占用一个 7 位地址 TileStargateController.setAddress()
一次性的"被拨"资格 一座星门一生只能被别的星门拨通一次 getDialed() 把 dialed 置 true 后全类再无复位点

方块硬度与爆炸抗性本 mod 未设置,继承原版 Block(Material) 构造函数的默认值(硬度 2.0、爆炸抗性 10.0),这是原版行为而非本 mod 的设定。

结构要求

结构是固定尺寸的:没有最小/最大规模之分,偏移表写死 15 个位置。坐标以控制器方块为原点 (0, 0),offsetX 为水平方向(沿门平面),offsetY 为高度方向(rotate() 永不改变 dy,Y 轴恒定向上)。

完整偏移表

下表左侧是逻辑偏移,实际世界坐标由 StructureUtil.rotate(offsetX, offsetY, facing) 决定。

offsetX offsetY 所需方块 所需 meta 角色
0 0 控制器方块(自身) facing(2–5) 结构核心 / 挂 TileEntity / 拨号发起端
−2 0 星门方块 1(雪佛龙) 拱脚外侧
−1 0 星门方块 0(环) 拱脚内侧
+1 0 星门方块 0(环) 拱脚内侧
+2 0 星门方块 1(雪佛龙) 拱脚外侧
−2 1 星门方块 0(环) 左立柱
+2 1 星门方块 0(环) 右立柱
−2 2 星门方块 1(雪佛龙) 左立柱雪佛龙
+2 2 星门方块 1(雪佛龙) 右立柱雪佛龙
−2 3 星门方块 0(环) 左立柱
+2 3 星门方块 0(环) 右立柱
−2 4 星门方块 1(雪佛龙) 拱顶外侧
−1 4 星门方块 0(环) 拱顶内侧
0 4 星门方块 1(雪佛龙) 拱顶正中央也是雪佛龙
+1 4 星门方块 0(环) 拱顶内侧
+2 4 星门方块 1(雪佛龙) 拱顶外侧

按 meta 汇总:雪佛龙(meta 1)共 7 个,环(meta 0)共 8 个,加控制器 1 个 = 16。

[!TIP] 7 个雪佛龙不是巧合。 雪佛龙数量(7)与地址位数(StargateAddress 的 7 个 sigil)、TileStargateController.CHEVRON_ANGLES 数组长度(7)三者严格相等,拨号动画就是让第 i 个雪佛龙依次对准第 i 个符号。

布局示意(facing = 2,正面视角)

     y=4   [雪佛龙][环]  [雪佛龙]  [环][雪佛龙]
     y=3   [   环   ]              [   环   ]
     y=2   [ 雪佛龙 ]              [ 雪佛龙 ]
     y=1   [   环   ]              [   环   ]
     y=0   [雪佛龙][环] [控制器]   [环][雪佛龙]
           x=-2   x=-1    x=0     x=+1   x=+2

朝向

控制器方块的 metadata 就是朝向,由 onBlockPlacedBy() 依玩家视线写入,只可能是 2 / 3 / 4 / 5(永远不会出现 0 或 1):

玩家朝向 写入的 meta 含义
0 2 北(−Z)
1 5 东(+X)
2 3 南(+Z)
3 4 西(−X)

StructureUtil.rotate() 的旋转对应关系:

facing 方向 逻辑 offsetX 映射到
2 北(−Z) 世界 +X
5 东(+X) 世界 −Z
3 南(+Z) 世界 −X
4 西(−X) 世界 +Z
其他 — 回退为 (dx, dy, 0)

即结构只做水平面内的四面旋转,offsetY 永远映射到 dy。

6 种材质组(§2.14 变体穷举)

ModBlocks.StargateBlocks 枚举定义 6 个材质组,每组各自实例化出完整的 3 个方块(雪佛龙/环共用的方块、控制器方块、已成形方块),共 18 个注册方块,加上 dialing_device 共 19 个方块。

枚举值 id isLegacy 显示名后缀(affix.*) 背景故事 tooltip 对比
Default default false 无 无 唯一无后缀、无 tooltip 的组,名称直接是 tile.default_stargate_block.<meta>.name
SplitOrigin split_origin true of Split Origin The first conquering (2.1.0.0) 5 个 legacy 组中 tooltip 版本号最低
PolychromeContest polychrome_contest true of Polychrome Contest Race for the infinite (2.1.2.3qf) 唯一版本号含字母后缀 qf
DimensionalDuplicity dimensional_duplicity true of Dimensional Duplicity Dawn of the new age (2.2.3) —
HarmonicBreakthrough harmonic_breakthrough true of Harmonic Breakthrough Universes torn apart (2.3.0) —
HeavenlyFire heavenly_fire true of Heavenly Fire Stars forged anew (2.7.0) tooltip 版本号最高(2.7.0)

变体之间的核心差异:仅限外观与命名。 isLegacy 字段在全 mod 中只被三个 ItemBlock 内部类读取,用于决定显示名是否拼接 affix 后缀、是否附加 tooltip;它不影响任何玩法逻辑。6 种材质组的结构要求、地址系统、传送行为、碰撞判定完全一致。实际使用场景是按喜好挑选贴图主题。

材质组不可混用

结构检测用的是 rBlock == block 的方块实例相等比较(StructureUtil.checkBlockAndMeta()),而每种材质组各自 new 出独立的 BlockStargate / BlockStargateController / BlockFormedGate 实例。因此一座星门必须完全由同一材质组的方块组成,混用两种材质组无法成形。

形成机制

全自动检测,放下最后一块方块的瞬间即成形。 没有"手持核方块右键装配"这类手动步骤,也没有结构样板物品。

两条触发路径:

  1. 放下控制器方块 — BlockStargateController.onPostBlockPlaced() 直接调用 runStructureCheck()。
  2. 放下任意一个星门方块(环或雪佛龙) — BlockStargate.onPostBlockPlaced() 调用 findController() 做一次泛洪搜索:只沿着同种方块(neighbor == this)向上下左右 6 个方向扩散,遇到 BlockStargateController 就对它执行 runStructureCheck()。搜索有硬上限 checked.size() > 20 即中止(源码注释 “Hard limit so nothing horrible happens”),意味着泛洪最多检查约 20 个方块;同一 group 内彼此直连的 15 个成员不会触发该上限。

formGate() 随即把 15 个成员方块和控制器本身全部 setBlock(..., flag 3) 为对应的 formedGateBlock,控制器位置写入 meta = facing。

成形后的状态(BlockFormedGate)

成形后结构里的每一个位置都变成 stargatenh:<group>_stargate_formed,metadata 完整保留成形前的身份:

成形后 meta 含义 是否有 TileEntity 破坏时掉落
0 原本是环方块 否(hasTileEntity(meta) = meta > 1) 星门环方块 ×1(damage 0)
1 原本是雪佛龙方块 否 星门雪佛龙方块 ×1(damage 1)
2 / 3 / 4 / 5 原本是控制器,meta 即朝向 是,TileStargateController 控制器方块 ×1(damage 0)

因此拆掉一座成形星门会精确掉回组装它的那 16 个方块,不增不减;getDrops() 完全忽略 fortune 参数,时运对掉落无影响。

渲染上该方块是完全隐形的:getRenderType() 返回 −1、renderAsNormalBlock() 返回 false、isOpaqueCube() 返回 false,实际外观由 RenderStargateTESR 绘制的 models/stargate.obj 提供。选取框按朝向为 5×5×1(getSelectedBoundingBoxFromPool())。

解体机制

拆掉任何一个方块,整座星门立刻解体。 同样有两条路径:

  • 拆控制器(meta > 1)— BlockFormedGate.breakBlock() 直接调用 deform()。
  • 拆其他位置(meta 0/1)— 同样走 findController() 泛洪(上限 20)找到控制器后执行 runDeformCheck(),只要 15 项检查中任意一项不满足就整体 deform()。

deform() 逐个调用 StructureUtil.deformRel(),把每个 BlockFormedGate 换回:meta > 1 → 控制器方块,否则 → 星门方块,metadata 原样保留(所以拆解后的星门方块朝向和类型信息不会丢失,可以直接重新摆放触发成形)。

功能

  • 玩家或生物站在门前,碰撞到门内侧的触发区域即被传送到目标星门(BlockFormedGate.addCollisionBoxesToList() → TileStargateController.doTeleport())。
  • 传送不改变维度——只把实体坐标设到目标星门控制器旁 y + 1.5,仍在同一个 World 内。
  • 触发区域按朝向为 (x−1, y+1, z)–(x+2, y+4, z+1)(facing 0 或 2)或 (x, y+1, z−1)–(x+1, y+4, z+2)(其余朝向)。只有 EntityLivingBase 会被传送,掉落物、箭矢等实体直接穿过。
  • 拨出目标地址后 7 个雪佛龙依次锁定,锁定过程见 拨号序列。

数值

数值 值 来源
结构方块总数 16 runStructureCheck()
雪佛龙数 / 环方块数 7 / 8 runStructureCheck()
泛洪搜索硬上限 20 findController()
雪佛龙间隔角 51.43°(= 360°/7) CHEVRON_ANGLES 数组
符号角步进 22.5°(= 360°/16) SYMBOL_STEP
每符号最短锁定时长 20 tick(1 秒) `animTotalTicks = Math.max(20,
每符号固定停顿 25 tick lockTicksRemaining = 25
最快完成一次拨号 315 tick ≈ 15.75 秒 7 × (20 + 25)

限制

  • 尺寸固定,无法缩放或扩展,多一格少一格都不会成形。
  • 材质组不可混用(见上节)。
  • 地址只能设定一次:setAddress() 首行即 if (hasAddress) return;,且 GUI 在已有地址时只显示拨号界面。
  • 每座星门只能被拨通一次:getDialed() 把 dialed 置为 true 后整个类中再无复位,第二次拨入会被 dialOut() 第一行拒绝。
  • 地址冲突时静默失败:setAddress() 先查注册表,若地址已被占用则不注册也不置 hasAddress,玩家只能看到地址一直没锁定。GUI 的"地址可用/已被使用"提示(isUnique 同步值)是唯一的预检手段。
  • 注册表只存在于主世界:StargateRegistry.RegisterEvent 仅在 world.provider.dimensionId == 0 时加载,见 地址与星门注册表。
  • mod 重载 / 区块卸载会丢失"被拨"状态:dialed 字段不写入 NBT,重新加载时回到 false。
  • dialing 目标位置不持久化,同样只存在于内存中。

参与方块

相关设定