API 层(对外扩展点)
基本信息
| 属性 | 值 |
|---|---|
| 目录 | com.gtnewhorizons.angelica.api + api/clouds/ + api/tesr/ |
| 文件数 | 27(15 根 + 2 clouds/ + 10 tesr/,含 1 个 package-info) |
| 定位 | 供外部 mod 使用的扩展点,全部带 angelica$ 前缀约定或独立命名空间 |
它解决什么问题
Angelica 重写了大量渲染内部流程。外部 mod(Supernova 的彩色光照、第三方 ISBRH、TESR 作者)需要在不硬依赖 Angelica 的前提下接入。本包就是这些接入点的声明处。
设计上有三条并行路线:注解式(ThreadSafeISBRH)、接口式(TesrMeshProvider)、静态注册式(BlockLightProvider.register)。
27 个文件逐类职责
根目录(15 个)
| # | 类 | 行数 | 种类 | 职责 |
|---|---|---|---|---|
| 1 | BlockLightProvider |
115 | interface + 静态门面 | 彩色方块光照的全局单点注册:外部光照引擎(Supernova)实现它并 register()。含 packRGB/unpackR/unpackG/unpackB 打包约定、EarlyFlags 冻结窗口、Holder 默认实现 |
| 2 | SectionLightData |
41 | interface | 单个 chunk section 的 RGB 光照快照。getRGBAndSkyRGB 返回传输格式 ((block & 0xFFFF) << 16) | (sky & 0xFFFF) |
| 3 | TintComputer |
21 | @FunctionalInterface |
computeTint(br,bg,bb,sr,sg,sb,float[3] out) —— 由方块光/天光 RGB 算出着色倍率。Javadoc 强调「光照贴图管亮度,tint 只管颜色」 |
| 4 | TintRegistry |
82 | final class | 具名 tint 混合模式注册表。static{} 先注册 "NONE"(out = 1,1,1),registerMode 返回 ordinal,setCurrentByOrdinal 做越界校验 |
| 5 | GLRedirects |
118 | final class | 对外暴露 GL→GLStateManager 的重定向映射表 + 预编译正则,供绕过字节码变换的调用方(脚本引擎、反射、MethodHandle)自行重写源码文本 |
| 6 | TextureServices |
27 | class(纯静态) | 纹理动画兼容钩子:updateBlockTextureAnimation(IIcon, RenderBlocks)、updateTextureAnimation(IIcon) |
| 7 | ThreadSafeISBRH |
35 | @interface |
@Retention(RUNTIME) @Target(TYPE),唯一成员 boolean perThread()。标记 ISBRH 可离线程执行 |
| 8 | ThreadSafeISBRHFactory |
22 | interface | 上一项的非默认构造替代:继承 ISimpleBlockRenderingHandler,实现 newInstance() |
| 9 | IBlockAccessExtended |
8 | interface | extends IBlockAccess,加 World getWorld() |
| 10 | IDynamicLightProducer |
10 | interface | int getLuminance(ItemStack)。Javadoc:「给没有方块的 mod 物品用,比如 Baubles」 |
| 11 | ExtLightDataAccess |
55 | interface(mixin 侧) | 给 LightDataCache 加 per-block RGB:精确坐标 / 1 方向 / 2 方向(AO 角)三档索引,加 angelica$getFusedByIndex 单次取回 block+sky |
| 12 | ExtAoFaceData |
34 | interface(mixin 侧) | 给 AoFaceData 加 per-corner RGB(4 元素数组),block + sky 各 3 通道 + 加权混合方法 |
| 13 | ExtQuadLightData |
21 | interface(mixin 侧) | 给 QuadLightData 加 per-vertex RGB + angelica$isRGBValid 有效性标志 |
| 14 | ExtLightDataCache |
11 | interface(mixin 侧) | 暴露 LightDataCache 内部持有的 IBlockAccess 引用 |
| 15 | ExtCeleritasRenderBlocks |
9 | interface | 2 个方法:angelica$shouldApplyCeleritasAO() / angelica$setApplyingCeleritasAO(boolean) |
| 16 | clouds/CloudLayer |
39 | record(12 组件) | 单层云参数:id、texture、height、cellWidth/Height、coordinateWidth、offsetX/Z、red/green/blue/alpha |
| 17 | clouds/CloudLayerProvider |
10 | interface | List<CloudLayer> getCloudLayers(WorldClient, int cloudTicks, float partialTicks) |
api/tesr/(10 个)
| # | 类 | 行数 | 种类 | 职责 |
|---|---|---|---|---|
| 18 | tesr/package-info |
5 | Javadoc | @API(owner="angelica", provides="angelica|tesr", apiVersion="2") —— 唯一声明了 API 版本号的子包 |
| 19 | tesr/TesrMaterial |
171 | final class | 桶级渲染属性描述符,interned(ConcurrentHashMap 去重)。19 个字段 + 2 个枚举:Transparency(OPAQUE/TRANSLUCENT/ADDITIVE/ADDITIVE_ALPHA/GLINT,5 项)、SpecialRender(NONE/BEACON_BEAM/GLINT,3 项)。链式 Builder |
| 20 | tesr/TesrShaders |
26 | final class | ConcurrentHashMap<String, TesrShader> 注册表。register(name, bind, release) 校验名字必须是 namespace:path(恰好一个冒号) |
| 21 | tesr/TesrShader |
17 | final class | 具名 GL program:name + Runnable bind + Runnable release。lombok @Getter @Accessors(fluent=true) @RequiredArgsConstructor(PACKAGE) |
| 22 | tesr/TesrMeshProvider |
29 | interface | 主入口:TileEntitySpecialRenderer 实现它即可接入网格缓存/批处理。4 方法:angelica$meshKey、angelica$meshDirty、angelica$transform、angelica$build |
| 23 | tesr/TesrMeshSink |
19 | interface | 捕获期接收器。3 个 angelica$bucket 重载,draw() 改为捕获而非绘制 |
| 24 | tesr/TesrMeshBuilder |
8 | @FunctionalInterface |
angelica$build(TesrMeshSink) |
| 25 | tesr/TesrMeshCache |
18 | final class(纯静态) | renderCached(key, builder) / invalidate(key) → 转发 AngelicaTesrMeshCache.INSTANCE |
| 26 | tesr/ModelPartBatch |
19 | final class(纯静态) | partDraw(ModelRenderer, float[, ModelPartMeshBuilder]) → 转发 ModelPartBatcher |
| 27 | tesr/ModelPartMeshBuilder |
11 | @FunctionalInterface |
angelica$buildPart(Tessellator, ModelRenderer, float) —— 处理覆写了 ModelRenderer.render 的部件 |
三个扩展路线的对比
| 路线 | 入口 | 声明方式 | 依赖强度 | 代表 |
|---|---|---|---|---|
| 注解式 | @ThreadSafeISBRH(perThread=…) |
类注解 | 零(可选注解) | ThreadSafeISBRH |
| 工厂式 | implements ThreadSafeISBRHFactory |
接口 | 需 @Optional.Interface(modid="angelica", iface="…") |
ThreadSafeISBRHFactory |
| 注册式 | BlockLightProvider.register(p) |
静态调用 | 必须早期调用,且只能注册一次 | BlockLightProvider |
BlockLightProvider 的时序契约(最重要的 API)
这是全包中唯一有时序约束的扩展点。源码给出完整的三段契约:
| 方法 | 行 | 约束 |
|---|---|---|
register(provider) |
:69-76 |
重复注册抛 IllegalStateException(:71-73) |
enableColoredLight() |
:82-89 |
必须从 IFMLLoadingPlugin 的 static 初始化器调用;若 MIXINS_FROZEN 已为 true 则抛异常(:83-85) |
freezeMixinConfig() |
:94-96 |
由 mixin 配置求值路径调用,之后 enableColoredLight() 就抛了 |
coloredLightEnabled() |
:101-103 |
读 EarlyFlags.COLORED_LIGHT |
isRegistered() |
:64-66 |
Holder.INSTANCE != Holder.DEFAULT |
默认实现(:105-110)是 lambda (_, _, _, _) -> -1(恒返回「无数据」)。EarlyFlags 与 Holder 是两个 final 内部类(:105-110)。
命名约定
| 模式 | 用途 | 例 |
|---|---|---|
Ext* |
通过 mixin 注入到原版/上游私有类上的能力 | ExtLightDataAccess、ExtAoFaceData、ExtQuadLightData、ExtLightDataCache、ExtCeleritasRenderBlocks |
angelica$* |
方法级前缀,避开 mod 自身命名 | angelica$getRGB、angelica$build、angelica$bucket |
I* / *Provider / *Registry |
纯 Angelica 自有的 SPI | IDynamicLightProducer、CloudLayerProvider、TintRegistry |
Ext* 这一族(5 个)不是给外部 mod 实现的,是 Angelica 自己 mixin 到 LightDataCache / AoFaceData / QuadLightData 等内部类上的桥接接口。放在公开 api 包里是暴露需要,但容易让读者误以为是 mod 扩展点。
已知问题
GLRedirects的TARGET_CLASS带@SuppressWarnings("unused")(:38):说明这个常量在本仓库内没有任何使用点 —— 它是纯对外 API,只被外部脚本消费者使用。TintRegistry.current是非 volatile 的static字段(:19):registerMode在static{}里被调用一次,之后setCurrentByOrdinal从任意线程写current。跨线程可见性无保障 —— 这是真实的并发隐患。BlockLightProvider.Holder.INSTANCE同样非 volatile(:109):同一类问题。TesrMaterial.CURRENT_STATE是 19 个参数的巨型常量(:27):可读性极差,参数顺序错误不会被编译器发现(全是boolean/float)。api/clouds/无package-info:tesr/有@API声明版本,clouds/与根目录都没有。外部 mod 无法判断云层 API 是否有版本保证。IDynamicLightProducer的 Javadoc 只给了一个例子(Baubles),未说明与IDynamicLightSource的关系 —— 两者是不同层的接口(物品 vs 实体/方块),但都在本包内,容易混淆。ExtLightDataAccess依赖org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing:这是 Sodium/Embeddium 派生代码的包名,不是 Minecraft 或 Angelica 自己的。对外 API 泄漏上游包名意味着 Sodium 侧包结构变动会直接破坏本 API(见 Sodium(内嵌库))。
相关条目
- AngelicaModulesConfig -
enableRGBColors、enableTESR*Cache等门控 - Dynamic Lights -
IDynamicLightProducer的消费方 - ThreadSafeISBRHAnnotationTransformer - 通过 ASM 给第三方类打
ThreadSafeISBRH注解 - ImmersiveEngineeringCompatHandler - 8 个类被强制标
perThread=false - Sodium(内嵌库) -
ModelQuadFacing的来源 - Iris(内嵌) - 上游包名泄漏的另一处
- Subprojects(内嵌子项目) -
AngelicaTesrMeshCache/ModelPartBatcher的实际实现所在