Skip to content

Commit 2f54db7

Browse files
authored
fix(glsm): add double-angle glRotatef redirect target used by NTM-CE (#65)
* fix(glsm): add double-angle glRotatef redirect target used by NTM-CE HBM's Nuclear Tech (Community Edition) calls net.minecraft.client.renderer.GlStateManager.rotate(double, float, float, float) from its tile entity item renderers. The GLSM redirector rewrites vanilla GlStateManager calls to GLStateManager by method name while preserving the caller's descriptor, so the (DFFF)V rotate call became GLStateManager.glRotatef(DFFF)V — which did not exist, crashing with NoSuchMethodError when rendering the Industrial Turbine item (issue #64). Add the missing glRotatef(double, float, float, float) overload next to the existing double-parameter glScalef/glTranslatef compat overloads; it delegates to the float form. Also extend the redirector tests: GLSMRedirectorTest now asserts a synthetic GlStateManager.rotate(DFFF) call is rewritten to GLStateManager.glRotatef with the descriptor preserved, and GLStateManagerRedirectContractTest asserts both the (FFFF)V and (DFFF)V glRotatef forms exist on the compiled class (394 tests, 0 failures). * fix(compat): adapt HBM-CE mixin targets on DefaultChunkRenderer HBM-CE's MixinDefaultChunkRenderer redirects reads inside fillCommandBuffer, a method that existed in upstream Celeritas but was dropped in Actinium's rewritten renderer. The mixin then aborts with a Critical injection error, poisoning DefaultChunkRenderer and breaking world loading (issue #47): a NoClassDefFoundError on VintageRenderSectionManager\ surfaces in Minecraft.loadWorld and the client player never spawns, cascading into the player-null NPE storm. Restore a fillCommandBuffer(CameraTransform) compatibility seam (never invoked by the render path) so the redirects find their getfield targets and apply cleanly, preserving the unsafe camera access they also apply to setModelMatrixUniforms. MixinOcclusionCuller still targets the old Celeritas OcclusionCuller API that Actinium does not provide, so dev runs enable -Dmixin.env.ignoreConstraints to downgrade that Critical failure to a skip instead of poisoning the class. * build: add HBM-CE and CTM dev dependencies Declare curse.maven coordinates for HBM's Nuclear Tech Mod Community Edition (1312314:8330665) and its CTM dependency (267602:2915363) so the dev client reproduces the HBM celeritas-mixin environment for issue #64 / #47 work. * fix(celeritas): restore legacy OcclusionNode API as HBM-CE mixin seam HBM-CE's MixinOcclusionCuller wraps the pre-lattice upstream culling API: isWithinFrustum(Viewport, OcclusionNode) call sites in isSectionVisible and tryVisitNode, plus isWithinRenderDistance(CameraTransform, OcclusionNode, float) in isSectionVisible. Actinium's lattice-based rewrite dropped the object-node API, so the critical injections failed, poisoned OcclusionCuller, and aborted the world-join task with NoClassDefFoundError before mc.player was created — surfacing as the issue #47 player-null NPE storm. Reintroduce a minimal OcclusionNode data holder and the four legacy members as dead injection targets, mirroring upstream b07278d0. Verified in the dev client: all HBM celeritas mixins now apply cleanly and the world loads. * fix(render): snapshot section light data for off-thread chunk builds Chunk-builder workers read the live light NibbleArrays while the light engine keeps mutating them on the main thread, so a torn read bakes transient darkness into the mesh (water and fluidlogged quads turning black after a relight burst). Copy the block/sky light arrays eagerly while the section is being cloned on the main thread. * fix(render): guard tile-entity batches against GL state leaks HBM-CE machine TESRs leak depth/blend/texture state during the render loop. The FastTESR batch flush relies on ambient GL state, so with machines in view the leaked state turned HBM water reeds into opaque black crosses that also punched holes in the water surface behind them. Wrap the block-entity region in a GLSM attrib push/pop and restore the clean entry state right before drawBatch, in both the main path and the mod-injected setTileEntities path. * docs: plan celeritas upstream sync (0a3624bc to b8c1079a) * perf(celeritas): sync fast frustum clamping and visibility snapshot from upstream Sync upstream commits 9b4256d0, daaefb72, 7c7c8228, d96b07f3 and the FFC/snapshot portion of 8fdbdb49 (0a3624bc..d96b07f3 + 8fdbdb49). - OcclusionCuller: explicit allowFrustumClamping parameter (7-arg findVisible), branchless integer angle refinement, aperture-based frustum clamping via FastFrustumClamping, multi-root search disables clamping. Public/package-visible signatures (isWithinFrustum, isWithinRenderDistance, tryVisitNode, Visitor) preserved. - FastFrustumClamping: new SWAR-based packed aperture culler (upstream). - RegionCullCache: reset-based classification with UNCOMPUTED and PARTIAL_DISTANCE_IN/PARTIAL_FRUSTUM_IN sub-classifications plus cached(). - SectionLattice: visibility snapshot reduced from long[] to int[] visibleFrames with SnapshotBuffers; findVisible gains the clamping flag. - RenderListManager/RenderSectionManager: thread the clamping flag through (enabled for the main pass, disabled for the orthographic shadow pass). Not included: b8c1079a shadow-occlusion refactor (deferred to the next phase), HBM-CE OcclusionNode seam (lives on fix/issue64-ntm-glsm, not in this branch). * feat(celeritas): sync shadow occlusion culler classes from upstream Sync the algorithm/data portion of upstream b8c1079a (receiver-driven shadow occlusion culling). - ShadowOcclusionCuller: new receiver-driven shadow search rooted at the main pass's visible sections, traversing toward the light (upstream). - ShadowSearchFrustum: new optional capability interface for shadow frustums that support the receiver-driven search (upstream). - SectionLattice: constructor gains hasShadowPass; adds shadowVisitState, shadowCuller, visibleCells/visibleCount; splits snapshot buffers into main/shadow pairs; findVisible records visible cells when a shadow pass exists; adds findShadowVisible. - OcclusionCuller: findVisible gains visitState and recordVisible parameters; static members made package-visible for ShadowOcclusionCuller; records visible cells during the search. - Viewport: adds getFrustum(). RenderListManager/SectionGraph wiring is deferred to the next phase; the tree is intentionally not fully buildable until then. * feat(celeritas): wire receiver-driven shadow occlusion into renderers Finish the common-side sync of upstream b8c1079a by adopting SectionGraph and the frame-ordered shadow search in the renderer layer. - SectionGraph: new shared lattice + single search thread + deferred lattice updates (upstream). - RenderListManager: constructor takes (SectionGraph, shadow, AsyncOcclusionMode, SectionTicker); attach/detach/updateSectionMetadata and the search thread move into SectionGraph; adds startShadowGraphUpdate and the shadow flag; startGraphUpdate rejects the shadow manager. - RenderSectionManager: both list managers share one SectionGraph; update() and updateForShadowPass() split by frame order (didShadowPassRunThisFrame); attach/detach/metadata fan out through the graph; the local getCurrentRenderListManager() seam is kept for the render/rebuild paths, while terrain search uses the terrain manager and shadow search uses updateForShadowPass. - SimpleWorldRenderer: setupTerrain/setupShadowTerrain/prepareFrame split, with the local shadow render-distance switch retained in setupShadowTerrain; chunk events apply while the graph is quiescent. - VintageRenderSectionManager/ActiniumWorldRenderer: drop the now-redundant finishAllGraphUpdates() in the shadow render path (setupShadowTerrain already joins). Build and all 423 tests pass. * feat(shader): activate receiver-driven shadow occlusion culling Wire the common-side shadow search (b8c1079a) into the Iris shader module. - WorldRendererCompat: add setupShadowTerrain and getLastViewport so the shadow pass can run the frame-ordered shadow search with the player viewport captured by the preceding terrain pass. - ShadowRenderer: call setupShadowTerrain(playerViewport, shadowViewport) instead of setupTerrain in the celeritas integration block; pass resolved near/far planes and the interval size to the advanced shadow frustum (legacy perspective packs skip depth planes); update culling info strings. - AdvancedShadowCullingFrustum: implement ShadowSearchFrustum and add depth planes (toward/away) using SHADOW_CAMERA_OFFSET. - SafeZoneCullingFrustum: override supportsOcclusionSearch() to false (safe-zone semantics are incompatible with the receiver-driven search). - ShadowMatrices: extract SHADOW_CAMERA_OFFSET constant. - ActiniumWorldRenderer: implement setupShadowTerrain/getLastViewport. Shadow occlusion now runs end-to-end: the shadow search consumes the terrain pass's visible-cell root set and expands toward the light. Build and all 423 tests pass; runtime shadow verification still pending. * build(celeritas): add JMH benchmark harness adapted to LWJGL 3.4.1 Sync the upstream f3c5642e benchmark harness and adapt it to Actinium's LWJGL 3.4.1 (the version Cleanroom and the mod's dependency script use). - celeritas-common/src/jmh: voxel/occlusion/multidraw benchmark sources from upstream, including the GL-backed OcclusionCullerBench and MultiDrawBench with their @benchmark methods. SectionLattice/findVisible calls updated for the post-b8 3-arg constructor and 7-arg findVisible. - build.gradle: jmh source set, jmhImplementation (jmh-core + annotation processor) and LWJGL 3.4.1 (lwjgl/lwjgl-opengl/lwjgl-egl) with the same native-classifier logic as GTNHLib; lwjgl-egl ships no natives classifier, matching upstream. - gradle.properties: jmh_version. HeadlessGl opens a system EGL context (mesa), so the GL benchmarks need EGL available at runtime (not bundled); pure-CPU benchmarks compile and run regardless. Build and all 423 tests pass. * docs: mark celeritas upstream sync complete * Revert "build(celeritas): add JMH benchmark harness adapted to LWJGL 3.4.1" This reverts commit 16eaec9. * chore: ignore local Mesa DLL dir for deferred JMH harness * docs: note JMH harness deferred (Windows Mesa EGL error 126) * fix(glsm): fall back to bufferData when mapBufferRange fails StreamingUploader's MAP_BUFFER_RANGE path fed the glMapBufferRange result straight into MemoryUtilities.memAddress0 without a null check. When the driver fails the mapping (returns NULL), Unsafe.getLong(null, 0x10) kills the JVM with EXCEPTION_ACCESS_VIOLATION reading address 0x10 (hs_err on the splash render thread during startup; MAP_BUFFER_RANGE is the default streaming upload strategy). Restore upstream Angelica's guarded form: RenderBackend gains mapBufferRangeAddress (returns 0L on failed mapping) and the uploader falls back to bufferData with a one-time WARN. The fallback is per-call, so transient mapping failures recover automatically on the next upload. * fix(celeritas): keep camera getfields inline in RenderSectionManager.update HBM-CE MixinRenderSectionManager (hbm.mod.mixin.json) registers @reDIrect injections on the update(Viewport, int, boolean) method body that rewrite the CameraTransform x/y/z getfields to its unsafe accessors. The b8c1079a shadow occlusion sync delegated that camera bookkeeping to the new private updateCameraPosition helper, leaving the redirector with zero scanned targets; the mixin application aborts with InjectionError, poisons the whole RenderSectionManager class and crashes mod construction with NoClassDefFoundError (observed as an Actinium onConstruct crash). Inline the camera reads back into update (updateCameraPosition stays for the shadow pass, which HBM-CE does not redirect) and lock the binding contract with HbmCameraRedirectContractTest, which asserts the three GETFIELD instructions against the compiled class bytes (same pattern as GLStateManagerRedirectContractTest). * fix(glsm): derive FFP shader flags from bound VAO attributes HBM-CE uploads OBJ models into VAOs while its glEnableClientState calls (redirected to GLSM) leak bits such as COLOR_BIT into ShaderManager's globally tracked currentVertexFlags without a matching VAO attribute. Raw GL draws (glDrawElements and friends, used by HBM's VAO path and by ShaderManager.preDraw()) then pick a shader variant that declares an attribute the VAO does not provide; the shader reads the default (0,0,0,1) and the model renders black. Because the leak is global and never restored, every machine rendered after the first model upload is affected and the pollution also breaks GUI item icons that share the FFP pipeline, independent of the fast-lit item / display-list / multidraw options. Derive the vertex-flag mask from VertexAttribState's per-VAO attribute enablement instead: ShaderManager.preDraw() and onBindVertexArray() for VAOs unknown to the vanilla VertexFormat setup path now use VertexAttribState.deriveVertexFlags(), which always matches the real GL state. Locked down by VertexAttribStateDeriveVertexFlagsTest. * fix(hbm): restore machine lightmap and depth state Route HBM render-state scopes through the GLSM state stack and synchronize world lightmap coordinates before tile-entity rendering. Derive fixed-function vertex flags from the bound VAO so raw HBM models do not inherit stale attributes. Add conditional mixins, regression tests, and compatibility documentation. Test: ./gradlew build --no-daemon * build(gradle): increase CI build memory Raise the Gradle heap and direct-memory limits to 8G and cap worker concurrency at two so GitHub Actions builds do not exhaust runner memory during compilation and remapping. Test: ./gradlew compileJava --no-daemon * fix(hbm): restore shader texture state * fix(shader): render block entities in shadow pass Collect tile entities after the shadow render lists are updated instead of during the later terrain setup. * fix(glsm): resync shader state after foreign draws * fix(glsm): isolate built-in item render state
1 parent 6110854 commit 2f54db7

53 files changed

Lines changed: 1824 additions & 202 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

celeritas-common/src/main/java/org/embeddedt/embeddium/impl/render/chunk/DefaultChunkRenderer.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,36 @@ protected GlTessellation createRegionTessellation(CommandList commandList, Rende
382382
return tessellation;
383383
}
384384

385+
/**
386+
* Legacy Celeritas command-buffer fill API — HBM-CE compatibility seam.
387+
*
388+
* <p>HBM-CE's {@code MixinDefaultChunkRenderer} (from {@code hbm.mod.mixin.json})
389+
* applies {@code @Redirect} injections on this class that replace direct reads of
390+
* the camera transform's integer coordinates with unsafe accessors (see HBM's
391+
* {@code CeleritasCameraTransformAccess}). One group of those redirects targets
392+
* {@link #setModelMatrixUniforms} (which this renderer retains); the other group
393+
* targets a {@code fillCommandBuffer} method that existed in the upstream Celeritas
394+
* {@code DefaultChunkRenderer} but no longer exists in Actinium's rewritten pipeline
395+
* (command buffers are now filled by {@code BatchAssembler}). Without this method the
396+
* whole mixin application aborts with a Critical injection error, which poisons this
397+
* class and breaks world loading (a subsequent {@code NoClassDefFoundError} on
398+
* {@code VintageRenderSectionManager$ChunkRenderer} surfaces during
399+
* {@code Minecraft.loadWorld}).
400+
*
401+
* <p>This method is never invoked by Actinium's render path; it exists purely so the
402+
* third-party mixin finds its injection targets and applies cleanly. The reads below
403+
* are kept so the redirects have a {@code CameraTransform.intX/intY/intZ} getfield to
404+
* rewrite, matching the same unsafe camera access they apply to
405+
* {@code setModelMatrixUniforms}.</p>
406+
*/
407+
@SuppressWarnings("unused")
408+
void fillCommandBuffer(CameraTransform camera) {
409+
int originX = camera.intX;
410+
int originY = camera.intY;
411+
int originZ = camera.intZ;
412+
// Intentionally unused: the values are consumed by HBM-CE's redirected accessors.
413+
}
414+
385415
@Override
386416
public void delete(CommandList commandList) {
387417
super.delete(commandList);

celeritas-common/src/main/java/org/embeddedt/embeddium/impl/render/chunk/RenderSectionManager.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,17 @@ protected boolean isDebugInfoShown() {
198198
* per-frame camera bookkeeping.
199199
*/
200200
public void update(Viewport positionedViewport, int frame, boolean spectator) {
201-
this.updateCameraPosition(positionedViewport);
201+
// HBM-CE compatibility seam. MixinRenderSectionManager (hbm.mod.mixin.json) applies
202+
// @Redirect injections on this exact method body that rewrite the CameraTransform
203+
// x/y/z getfields below to its unsafe accessors (CeleritasCameraTransformAccess).
204+
// The reads must stay inline here — delegating to updateCameraPosition() leaves the
205+
// redirector with zero scanned targets and the mixin application aborts with a
206+
// Critical injection error, poisoning this class (NoClassDefFoundError during mod
207+
// construction). updateCameraPosition is kept for the shadow pass, which HBM-CE
208+
// does not redirect. See HbmCameraRedirectContractTest.
209+
this.lastCameraPosition = positionedViewport.getBlockCoord();
210+
var transform = positionedViewport.getTransform();
211+
this.cameraPosition = new Vector3d(transform.x, transform.y, transform.z);
202212

203213
if (this.shadowPassRanThisFrame) {
204214
// The shadow pass searched for this frame if the graph was dirty then. Any needsUpdate raised by
@@ -237,6 +247,10 @@ public void updateForShadowPass(Viewport playerViewport, Viewport shadowViewport
237247
this.getSearchDistance(), lightVector, this.getTargetQueueSize());
238248
}
239249

250+
/**
251+
* Shadow-pass camera bookkeeping. Not shared with {@link #update} any more: HBM-CE's
252+
* redirector must find the CameraTransform getfields inside {@code update}'s own body.
253+
*/
240254
private void updateCameraPosition(Viewport positionedViewport) {
241255
this.lastCameraPosition = positionedViewport.getBlockCoord();
242256
var transform = positionedViewport.getTransform();

celeritas-common/src/main/java/org/embeddedt/embeddium/impl/render/chunk/occlusion/OcclusionCuller.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,61 @@ public static boolean isWithinFrustum(Viewport viewport, int chunkX, int chunkY,
473473
return viewport.isBoxVisible((chunkX << 4) + 8, (chunkY << 4) + 8, (chunkZ << 4) + 8, CHUNK_SECTION_SIZE);
474474
}
475475

476+
// --------------------------------------------------------------------------------------------------------
477+
// Legacy object-node API — HBM-CE compatibility seam.
478+
//
479+
// HBM-CE's MixinOcclusionCuller (hbm.mod.mixin.json) applies MixinExtras @WrapOperation injections
480+
// against the pre-lattice upstream OcclusionCuller API: it wraps the isWithinFrustum(Viewport,
481+
// OcclusionNode) calls inside isSectionVisible and tryVisitNode (require=2 total) and the
482+
// isWithinRenderDistance(CameraTransform, OcclusionNode, float) call inside isSectionVisible
483+
// (require=1), expanding the culling bounds for its chunk-spanning machines. Actinium's
484+
// lattice-based search never uses object nodes, so the members below are never invoked by the
485+
// render path; they exist purely as injection targets. Without them the critical injections fail,
486+
// poison this class, and break world loading with a NoClassDefFoundError inside the join task
487+
// (issue #47).
488+
489+
/**
490+
* Legacy frustum test operating on an object node — HBM-CE injection target.
491+
*/
492+
public static boolean isWithinFrustum(Viewport viewport, OcclusionNode section) {
493+
return viewport.isBoxVisible(section.getOriginX() + 8, section.getOriginY() + 8, section.getOriginZ() + 8, CHUNK_SECTION_SIZE);
494+
}
495+
496+
/**
497+
* Legacy render-distance test operating on an object node — HBM-CE injection target.
498+
*/
499+
private static boolean isWithinRenderDistance(CameraTransform camera, OcclusionNode section, float maxDistance) {
500+
int ox = section.getOriginX() - camera.intX;
501+
int oy = section.getOriginY() - camera.intY;
502+
int oz = section.getOriginZ() - camera.intZ;
503+
504+
float dx = nearestToZero(ox, ox + 16) - camera.fracX;
505+
float dy = nearestToZero(oy, oy + 16) - camera.fracY;
506+
float dz = nearestToZero(oz, oz + 16) - camera.fracZ;
507+
508+
return ((((dx * dx) + (dz * dz)) < (maxDistance * maxDistance)) && (Math.abs(dy) < maxDistance));
509+
}
510+
511+
/**
512+
* Legacy per-section visibility test — HBM-CE injection target. Never called by Actinium's
513+
* render path.
514+
*/
515+
@SuppressWarnings("unused")
516+
private static boolean isSectionVisible(OcclusionNode section, Viewport viewport, float maxDistance) {
517+
return isWithinRenderDistance(viewport.getTransform(), section, maxDistance) && isWithinFrustum(viewport, section);
518+
}
519+
520+
/**
521+
* Legacy node visit — HBM-CE injection target providing the second wrapped
522+
* isWithinFrustum(Viewport, OcclusionNode) call site. Never called by Actinium's render path.
523+
*/
524+
@SuppressWarnings("unused")
525+
private static void tryVisitNode(Viewport viewport, OcclusionNode section) {
526+
if (section == null || !isWithinFrustum(viewport, section)) {
527+
return;
528+
}
529+
}
530+
476531
/**
477532
* Choose the search seed. A loaded in-world camera section is processed
478533
* inline; an out-of-height or unloaded camera is handled by scanning a
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.embeddedt.embeddium.impl.render.chunk.occlusion;
2+
3+
import org.embeddedt.embeddium.impl.render.chunk.RenderSection;
4+
import org.jetbrains.annotations.Nullable;
5+
6+
/**
7+
* Legacy object-graph occlusion node — HBM-CE compatibility seam.
8+
*
9+
* <p>Upstream Celeritas represented the visibility graph with object nodes of this type until
10+
* upstream commit {@code 450dc85f} ("Implement a better storage system for occlusion node
11+
* data") replaced them with {@link SectionLattice}'s dense cell storage, which Actinium
12+
* follows. HBM-CE's {@code MixinOcclusionCuller} still targets the object-node API: it wraps
13+
* the {@code OcclusionCuller.isWithinFrustum(Viewport, OcclusionNode)} and
14+
* {@code isWithinRenderDistance(CameraTransform, OcclusionNode, float)} call sites and reads
15+
* node origins plus the backing render section from its handlers.</p>
16+
*
17+
* <p>This class is never instantiated by Actinium's render path. It exists purely so the
18+
* third-party mixin finds its injection targets and applies cleanly; without it the critical
19+
* injections fail, poison {@link OcclusionCuller}, and break world loading with a
20+
* {@code NoClassDefFoundError} inside the join task (issue #47).</p>
21+
*/
22+
public final class OcclusionNode {
23+
private final @Nullable RenderSection section;
24+
private final int originX;
25+
private final int originY;
26+
private final int originZ;
27+
28+
public OcclusionNode(@Nullable RenderSection section, int originX, int originY, int originZ) {
29+
this.section = section;
30+
this.originX = originX;
31+
this.originY = originY;
32+
this.originZ = originZ;
33+
}
34+
35+
/**
36+
* @return the render section this node was derived from, or {@code null} for a
37+
* position-only node
38+
*/
39+
public @Nullable RenderSection getRenderSection() {
40+
return this.section;
41+
}
42+
43+
/**
44+
* @return block-space X coordinate of the section's minimum corner
45+
*/
46+
public int getOriginX() {
47+
return this.originX;
48+
}
49+
50+
/**
51+
* @return block-space Y coordinate of the section's minimum corner
52+
*/
53+
public int getOriginY() {
54+
return this.originY;
55+
}
56+
57+
/**
58+
* @return block-space Z coordinate of the section's minimum corner
59+
*/
60+
public int getOriginZ() {
61+
return this.originZ;
62+
}
63+
}

docs/architecture.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ GTNHLib ← glsm ← celeritas-common ← shader ← 根项目 src/main(compil
9999
- `mixin/features/iris`(含 `startup/`):约 35 个 Iris 兼容注入
100100
(实体、粒子、渲染器、纹理地图接入与启动期纹理注入)。
101101
- `mixin/mod/`:按模组分组的 conditional 注入 —— `betterfoliage``ccl``dh`(7 个)、
102-
`gibbed``ichunutil``lumenized``revoui``voxelmap`(3 类,小地图兼容);
102+
`gibbed``hbm`(2 类,机器状态与世界光照兼容)、`ichunutil``lumenized``revoui`
103+
`voxelmap`(3 类,小地图兼容);
103104
`stellarcore` 为空目录(规划占位)。
104105
- `mixin/vintage/`:原版 1.12.2 注入分支 —— `core`(Minecraft/RenderGlobal/Tessellator/
105106
纹理上传)、`core/collections``core/crash`(SplashProgress)、`core/frustum`
@@ -125,6 +126,8 @@ GTNHLib ← glsm ← celeritas-common ← shader ← 根项目 src/main(compil
125126
- **`compat/fluidlogged/`**`FluidloggedCompat``FluidStateStorage``FluidloggedBlockAccess`
126127
—— 流体方块状态存取,供区块克隆离线读取。
127128
- **`compat/gibbed/`**`ActiniumModelRenderer` —— Gibbed 尸块渲染模型扩展。
129+
- **`compat/hbm/`**`HbmRenderStateCompat` —— HBM attribute scope 到 GLSM 状态栈的映射,
130+
以及方块实体世界 lightmap 同步(配 `mixin/mod/hbm`)。
128131
- **`compat/ichunutil/`**`PortalViewportFactory` / `PortalViewportProvider` /
129132
`PortalChunkRenderMatrices` / `PortalRenderState` / `WorldBoxVisibility`
130133
—— 传送门视口与渲染状态管理。
@@ -422,7 +425,7 @@ LWJGL 后端(并入本子项目):
422425

423426
## Mixin 配置清单
424427

425-
`src/main/resources/` 下 10 个配置 + 1 个门控声明:
428+
`src/main/resources/` 下的 early/conditional 配置与 1 个门控声明:
426429

427430
| 配置 | 阶段 | 用途 |
428431
| --- | --- | --- |
@@ -435,6 +438,7 @@ LWJGL 后端(并入本子项目):
435438
| `mixins.actinium.revoui.json` | late/conditional(neofontrender_ui_enhancements) | `mixin/mod/revoui` 3 类 |
436439
| `mixins.actinium.betterfoliage.json` | late/conditional(betterfoliage) | `MixinChunkBuilderMeshingTaskBetterFoliage` |
437440
| `mixins.actinium.ccl.json` | late/conditional(codechickenlib) | `MixinGlStateTracker` |
441+
| `mixins.actinium.hbm.json` | late/conditional(hbm) | `MixinRenderUtil``MixinTileEntityRendererDispatcherLightmap` |
438442
| `mixins.actinium.voxelmap.json` | late/conditional(voxelmap) | `mixin/mod/voxelmap` 3 类(GLUtils/GLShim/renderMap,小地图 CPU 路径与 HudCaching alpha 保护) |
439443

440444
门控映射在 `mixins.actinium.conditions.properties`(mixin loader 不认 json 自定义字段),

docs/compatibility-matrix.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Actinium 兼容性矩阵
22

3-
最后更新:2026-08-31
3+
最后更新:2026-09-02
44

55
状态定义:`已验证` 表示在记录的版本和场景中通过;`部分` 表示能运行但存在已知缺口;
66
`无法启用` 表示光影包不能成功开启;`未验证` 不代表不兼容。更新记录时必须填写 Actinium commit、
@@ -64,6 +64,10 @@ Windows 10、NVIDIA GeForce RTX 5070 Laptop GPU(驱动 610.74)。
6464
> [docs/compat/oldresearch.md](compat/oldresearch.md)。dev 人工回归确认研究笔记 GUI 不再卡死,
6565
> 优化后约 500+ FPS,与背包界面同量级;研究树视觉回归仍待补充。
6666
67+
> 2026-08-29 追加:HBM's Nuclear Tech - Community Edition 2.5.0.5 的机器黑色剪影、
68+
> lightmap 和深度状态异常修复——见下方 [模组与环境](#模组与环境) 的 HBM 行。
69+
> dev 实际场景回归覆盖 FENSU 与其他 HBM 机器,模型不再显示为黑色剪影。
70+
6771
> 2026-09-02 追加:BetterPortals Refitted 0.4.1 末地传送门无看穿效果(洞口只见星野贴图)+
6872
> 视觉位置低约一格 + 修复后星野被拉成竖直条纹的修复——见下方 [模组与环境](#模组与环境)
6973
> BetterPortals Refitted 行与 [docs/compat/betterportals.md](compat/betterportals.md)
@@ -102,6 +106,7 @@ Windows 10、NVIDIA GeForce RTX 5070 Laptop GPU(驱动 610.74)。
102106
| Chunk Animator | 部分 | 条件桥(ChunkAnimationProvider)+ 动画 section 单独绘制 | 1.12.2-1.2.1(236484:3850023)dev 运行通过(coremod 加载、兼容层启用、进世界无异常);动画视觉确认待补,详见 [docs/compat/chunkanimator.md](compat/chunkanimator.md) |
103107
| VoxelMap | 部分 | 条件 Mixin(CPU 纹理路径 + 线性过滤 + scissor 重路由 + HudCaching alpha 保护) | 1.9.25 小地图黑屏/黑块已修复(dev 验证圆内正常显示地图内容、HUD 不被缓存隐藏,见 [docs/compat/voxelmap.md](compat/voxelmap.md));已知缺口:与 StellarCore `HudCaching` 组合时小地图圆周仍可能残留黑块(VoxelMap 全屏清 alpha + DST_ALPHA 混合与 HUD 缓存 FBO 的第三方冲突,`HudCaching=false` 即消失,非本模组缺陷);验证 VoxelMap 需停用 JourneyMap(二者频道冲突) |
104108
| ModernUI | 代码支持 | GUI scale hook | 尚缺当前运行时验证记录 |
109+
| HBM's Nuclear Tech - Community Edition | 已验证 | 条件 Mixin(RenderUtil 状态栈 + TileEntityRendererDispatcher 世界 lightmap 同步) | 2.5.0.5(CurseForge 1312314:8330665):FENSU 与其他 HBM 机器的 WaveFront raw VAO 模型在实际场景中正常显示;修复前的 stale lightmap、黑色剪影和 depth 恢复异常不再复现;Java 25.0.3、Cleanroom 0.6.12-alpha dev 回归通过 |
105110
| Depths Update | 已验证 | 兼容门控(`compat/depthsupdate`:公开 API 推导 section 范围 + storage 索引映射) | 1.0.0-a10:扩展世界高度(默认 -64..320)下 Y<0 与 Y>255 的方块不再缺失(渲染器原先硬编码 0-255);dev 实测正常;无 Depths 时回退 vanilla 行为 |
106111
| EnderIO CEu / EnderCore CEu | 已验证 | 无(核心渲染语义修复,非模组接入) | 5.4.2 + EnderCore 0.5.81:光影开启时流体罐内液体被罐体玻璃窗深度遮挡的问题已修复(`cb4feaa5`,translucent terrain pass 不再写深度);MakeUp Ultra Fast 9.4c + Cleanroom 0.5.17-alpha 实测通过;2026-09-02 修复 #85`da83c59`)引入的回潮——translucent pass 被错误翻转为写深度导致有无光影流体均被玻璃遮挡,已恢复 vanilla 深度语义,双路径实测通过 |
107112
| Snow! Real Magic! | 已验证 | 兼容门控(SRM 的 snow_layer 块退回 vanilla dispatcher 路径) | 0.7.4:带雪栅栏不渲染已修复(SRM 把被覆盖方块替换为带 SnowTile 的雪层、仅在 `BlockRendererDispatcher.renderBlock` 内重绘,快速区块路径已绕过);`6aee395`,dev 运行验证通过(MakeUp Ultra Fast 下无光影 + 光影各验一次) |

0 commit comments

Comments
 (0)