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 扩展点。

已知问题

  1. GLRedirects 的 TARGET_CLASS 带 @SuppressWarnings("unused")(:38):说明这个常量在本仓库内没有任何使用点 —— 它是纯对外 API,只被外部脚本消费者使用。
  2. TintRegistry.current 是非 volatile 的 static 字段(:19):registerMode 在 static{} 里被调用一次,之后 setCurrentByOrdinal 从任意线程写 current。跨线程可见性无保障 —— 这是真实的并发隐患。
  3. BlockLightProvider.Holder.INSTANCE 同样非 volatile(:109):同一类问题。
  4. TesrMaterial.CURRENT_STATE 是 19 个参数的巨型常量(:27):可读性极差,参数顺序错误不会被编译器发现(全是 boolean/float)。
  5. api/clouds/ 无 package-info:tesr/ 有 @API 声明版本,clouds/ 与根目录都没有。外部 mod 无法判断云层 API 是否有版本保证。
  6. IDynamicLightProducer 的 Javadoc 只给了一个例子(Baubles),未说明与 IDynamicLightSource 的关系 —— 两者是不同层的接口(物品 vs 实体/方块),但都在本包内,容易混淆。
  7. ExtLightDataAccess 依赖 org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing:这是 Sodium/Embeddium 派生代码的包名,不是 Minecraft 或 Angelica 自己的。对外 API 泄漏上游包名意味着 Sodium 侧包结构变动会直接破坏本 API(见 Sodium(内嵌库))。

相关条目