模组 API 与扩展点
基本信息
OpenBlocks 暴露三层扩展点:FlinFlam 注册表(运行时可查可写)、6 个 RPC 接口(客户端↔服务端)、以及若干纯数据接口(供其它 mod 实现以被识别)。
| 层次 | 入口 | 位置 |
|---|---|---|
| 静态门面 | openblocks.api.OpenBlocksApi |
api/OpenBlocksApi.java |
| API 提供者装配 | openblocks.ApiSetup |
ApiSetup.java |
| 编译期注入 | openblocks.api.ApiHolder |
api/ApiHolder.java |
| RPC 注册 | RpcCallDispatcher.INSTANCE.startRegistration() |
OpenBlocks.java:619-622 |
API 提供者机制
OpenBlocksApi 只有一个静态 provider 字段与两个方法(OpenBlocksApi.java:3-35):
| 成员 | 行 | 行为 |
|---|---|---|
interface ApiProvider |
:5-10 |
getApi(Class<T>) / isApiPresent(Class<T>) |
init(ApiProvider) |
:17-20 |
重复调用抛 IllegalStateException("API already initialized")(:18) |
getApi(Class<T>) |
:26-29 |
@Deprecated,注释指向 ApiHolder(:22-25);provider 为 null 时抛 IllegalStateException("API not initialized") |
isApiPresent(Class<T>) |
:31-34 |
同上 |
装配逻辑在 ApiSetup(58 行):
registry = new ApiProviderRegistry<IApiInterface>(IApiInterface.class)(:23-24)setupApis()注册唯一实现registry.registerInstance(FlimFlamRegistry.instance)然后registry.freeze()(:28-31)——冻结后不可再注册installHolderAccess(ASMDataTable)走 ASM 注入ApiFactory.instance.createApi(ApiHolder.class, IApiInterface.class, table, registry)(:33-35)injectProvider()调OpenBlocksApi.init(new ApiProviderAdapter(registry)),失败时重新抛出IllegalStateException并附上 API 来源(:37-46)getApiSource()失败时Log.severe并返回"<unknown, see logs>"(:48-56)——这是不吞异常的catch (Throwable)写法
private final ApiSetup apiSetup = new ApiSetup();(OpenBlocks.java:249)
ApiHolder的 javadoc 里提到「OpenPeripheralAddons」——那是上游复制粘贴留下的痕迹(api/ApiHolder.java),不影响功能。
唯一已注册的 API 实现
FlimFlamRegistry.instance(ApiSetup.java:29)。对外接口是 IFlimFlamRegistry(api/IFlimFlamRegistry.java):
public interface IFlimFlamRegistry extends IApiInterface {
List<String> getAllFlimFlamsNames();
IFlimFlamDescription getFlimFlamByName(String name);
List<IFlimFlamDescription> getFlimFlams();
void registerFlimFlam(String name, IFlimFlamDescription meta);
FlimFlamDescriptionSimple registerFlimFlam(String name, int cost, int weight, IFlimFlamAction effect);
}
注意:registry.freeze()(ApiSetup.java:30)在 postInit 之前执行,因此外部 mod 无法再通过 API 新增 FlimFlam 效果——只有 postInit 里 OpenBlocks.java:760-781 那 17 个是活的。
配套的 3 个 FlimFlam 接口:
| 接口 | 作用 |
|---|---|
IFlimFlamDescription |
效果元数据:name() / weight() / cost() / isSafe() / isSilent() / action() / canApply(int luck) |
FlimFlamDescriptionSimple |
上者的默认实现,构造器 (name, cost, weight, effect),链式 markSafe() / markSilent() / setRange(a, b) |
IFlimFlamAction |
效果的实际执行体 |
FlimFlamDescriptionSimple 的 cost 实际是幸运值区间上界(负值才生效),细节与「不作为缺陷」的论证见附魔页。
6 个 RPC 接口
RpcCallDispatcher.INSTANCE.startRegistration()(OpenBlocks.java:619-622)注册:
| 顺序 | 接口 | 文件 |
|---|---|---|
| 1 | IRotatable |
rpc/IRotatable.java |
| 2 | IStencilCrafter |
rpc/IStencilCrafter.java |
| 3 | IColorChanger |
rpc/IColorChanger.java |
| 4 | ILevelChanger |
rpc/ILevelChanger.java |
| 5 | ITriggerable |
rpc/ITriggerable.java |
| 6 | IGuideAnimationTrigger |
rpc/IGuideAnimationTrigger.java |
rpc/ 包共 6 个文件,与注册的 6 个接口一一对应,无多余文件。
IGuideAnimationTrigger 的实际使用方是 TileEntityBuilderGuide(common/tileentity/TileEntityBuilderGuide.java:21 实现该接口),用于在放置方块后从服务端触发客户端动画。IStencilCrafter 由 TileEntityDrawingTable 实现(common/tileentity/TileEntityDrawingTable.java:21)。
供其它 mod 实现的标记接口
这些接口不由 OpenBlocks 调用,而是 OpenBlocks 检查实现者来决定行为:
| 接口 | 用途 | 行 |
|---|---|---|
IElevatorBlock |
电梯配对查询:getColor(World,x,y,z) / getRotation(...) 与 PlayerRotation 枚举 |
api/IElevatorBlock.java |
IPointable |
指针类物品的选中回调:onPointingStart / onPointingEnd |
api/IPointable.java |
IPaintableBlock |
24 位 RGB 版的 Block.recolourBlock |
api/IPaintableBlock.java |
IMagnetAware |
磁铁是否可释放:canRelease() |
api/IMagnetAware.java |
IApiInterface |
所有 API 接口的根标记 | api/IApiInterface.java |
IElevatorBlock 有两个内部实现,都在 OpenBlocks 自己包里:
BlockElevator(common/block/BlockElevator.java:23)——颜色存在方块 meta(getColor返回world.getBlockMetadata,:72-74)BlockElevatorRotating(common/block/BlockElevatorRotating.java:16)——颜色存在 TileEntity(getColor走getColorMeta,:65-67),并额外实现getRotation(:70-85)
IPaintableBlock 由 BlockCanvas 实现(common/block/BlockCanvas.java:23),把 recolourBlockRGB 委派给 TileEntityCanvas.applyPaint(:101-105)。
ElevatorActionHandler判定电梯配对时用instanceof IElevatorBlock,共 4 处::63(当前电梯,是强制转换(IElevatorBlock) world.getBlock(...))、:75-76(候选电梯)、:171(事件入口前置检查)、:208。所以外部 mod 实现的IElevatorBlock也能参与电梯配对——这是 OpenBlocks 对外开放最实质的扩展点之一。
事件
events/ 包只有 2 个事件类:
| 事件 | 方向 | 行 |
|---|---|---|
ElevatorActionEvent |
C2S | events/ElevatorActionEvent.java:13(@NetworkEventMeta(direction = EventDirection.C2S)) |
PlayerActionEvent |
— | events/PlayerActionEvent.java |
另在 api/ 包里有 4 个可取消的事件:GraveDropsEvent、GraveSpawnEvent、InventoryEvent、SleepingBagUseEvent。
数值
| 数值名 | 来源 | 值 |
|---|---|---|
| 已注册 API 实现数 | ApiSetup.java:29 |
1(仅 FlimFlamRegistry) |
| 已注册 RPC 接口数 | OpenBlocks.java:619-622 |
6 |
rpc/ 包文件数 |
目录 | 6(与注册数一致) |
| 已注册的 FlimFlam 效果数 | OpenBlocks.java:760-781 |
17 |
| 供实现的标记接口数 | api/ 包 |
5 |
| 网络事件数 | OpenBlocks.java:614-617 |
6 |
api/ 包 .java 文件数 |
目录 | 16(含 1 个 package-info.java) |
api/ 包事件类数 |
目录 | 4 |
相关条目
- 附魔:FlimFlam - 唯一可用的 API 实现
- 方块 / 电梯 -
IElevatorBlock的两个内部实现 - 方块 / 投影建造系统 -
IStencilCrafter/IColorChanger的使用方 - 集成 / 外部模组 - 与其它 mod 的对接点