跳到正文
烈焰甘蔗Wiki

多方块构造机制(Constructable)

基本信息

属性 值
交互入口 com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility
核心接口 IConstructable、ISurvivalConstructable
结构定义 com.gtnewhorizon.structurelib.structure.IStructureDefinition / StructureDefinition

本 mod 自身不包含任何多方块结构。它是一套供其他 mod 使用的构造框架:结构由各 mod 用 IStructureDefinition 描述,本 mod 提供遍历、检查、提示、放置的全部算法。因此本分类下没有 multiblock/ 目录。

参与者接口

接口 作用
IConstructable 标记一个方块实体(或其委托)可被构造触发器驱动
IConstructableProvider 由方块实体提供另一个 IConstructable 实例
ISurvivalConstructable 扩展 IConstructable,额外允许生存模式自动放置
IMultiblockInfoContainer 把"不认识 IConstructable 的方块实体类"转换出构造能力

目标解析顺序

ConstructableUtility.handle0 在目标位置取到方块实体后,按顺序尝试解析构造目标:

  1. 方块实体实现 IConstructableProvider → getConstructable()
  2. 方块实体直接实现 IConstructable → 直接使用
  3. 该方块实体类已通过 IMultiblockInfoContainer.registerTileClass 登记 → 按点击面朝向转换出 IConstructable

都不满足则不触发任何逻辑。

另外,目标位置没有方块实体、或操作者是 FakePlayer 时,函数直接返回 操作者 instanceof EntityPlayerMP 而不继续。

提示与放置的分流

解析成功后,是否潜行决定走哪条路径:

玩家状态 路径 说明
不潜行 客户端生成全息提示 服务端直接返回 true,不做任何检查
潜行 服务端生存自动放置 走限流校验后调用 survivalConstruct

客户端侧还有一道校验:非服务端玩家必须满足 StructureLib.isCurrentPlayer(aPlayer),否则返回 false。

生存自动放置

潜行放置时服务端先做时间限流:

timePast = System.currentTimeMillis() - 上次使用时刻
若 timePast < autoPlaceInterval  →  拒绝并提示剩余毫秒数

限流通过后调用 ISurvivalConstructable.survivalConstruct(stackSize, elementBudget, env),其中 elementBudget 取自 autoPlaceBudget 配置。

survivalConstruct 有多个重载:既可以传旧的 IItemSource + EntityPlayerMP 组合(已废弃),也可以传新的 ISurvivalBuildEnvironment。客户端玩家走后者时会触发一段"hacky migration code"(可由系统属性 structurelib.disable_isc_migration_code 关闭),把玩家临时塞进 GlobalStates 线程局部变量再委托给废弃重载。

返回值约定:

返回值 含义
-1 结构已建造完成
-2 不支持(例如环境 API 不兼容)
>= 0 本轮实际放置的元素数量

结构定义

IStructureDefinition<T> 用字符串数组描述结构布局,配合 IStructureElement<T> 描述每个位置的语义。构建方式为 builder 模式,主要方法两个:

  • addShape(String name, String[][] structurePiece):以二维字符串数组描述布局,可用 StructureUtility.transpose() 转置以改善源码可读性
  • addElement(Character name, IStructureElement<T>):把字符标识绑定到结构元素

IStructureDefinition 提供一组默认方法覆盖不同用途:check(检查)、hints(生成提示,仅客户端)、build(创造模式尽力放置)、buildOrHints(二者择一)、survivalBuild(生存建造)、iterate(低层遍历)。

坐标系:A / B / C

源码文档给出的定义是:站在控制器前方,控制器正面朝向你,未旋转也未翻转时的相对位置。

偏移 含义
A 控制器左侧的方块数(不含控制器自身)
B 控制器上方的方块数(不含控制器自身)
C 你与控制器之间的方块数(不含控制器自身)

放置结果 PlaceResult

IStructureElement.PlaceResult 定义了单个元素在一轮放置中的结果,遍历器据此决定后续行为:

枚举值 含义 遍历器行为
SKIP 检查通过,位置已正确 继续迭代(不报错,不计入已放置)
REJECT 该元素无法处理此位置(被占用、缺资源等) 停止迭代并显示错误粒子
REJECT_CONTINUE 未实现 survivalPlaceBlock 或无法放置,但非错误 静默继续;链式结构中尝试下一个候选
STOP 本 tick 无法继续 停止本轮,等待下一轮
ACCEPT 放置成功 继续迭代
ACCEPT_STOP 放置成功但需等待下一轮 停止本轮

缓存建议

IStructureDefinition 的类文档建议缓存实例:每个多方块只构造一次,可用 ClassValue<IStructureDefinition<?>>,或用 StructureUtility.defer(Function) 求值。源码注释指出 defer 写法略慢,因为每次结构检查都会分配新对象,而 ClassValue 只分配一次。

相关条目:Constructable Trigger、提示渲染系统、配置、通道系统。

浏览全部模组