From 28664aa919a9be6939969c6c9665636d2bff7024 Mon Sep 17 00:00:00 2001 From: zonix-official Date: Thu, 3 Sep 2026 23:32:10 +0100 Subject: [PATCH 1/3] Initial port of https://github.com/OpenCubicChunks/CubicChunks/pull/782 from 1.12.2 CC1 into 1.21.6 for CC3 --- .../core/client/renderer/MixinViewArea.java | 133 +++++++++++++++--- 1 file changed, 114 insertions(+), 19 deletions(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java index 1fd0bef2d..7248c93e3 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java @@ -2,15 +2,19 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.opencubicchunks.cc_core.utils.Coords; import io.github.opencubicchunks.cubicchunks.CanBeCubic; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.ViewArea; import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; import net.minecraft.core.SectionPos; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -27,6 +31,10 @@ public abstract class MixinViewArea { @Shadow private SectionPos cameraSectionPos; @Shadow @Final protected LevelRenderer levelRenderer; + @Unique private int cc_oldCameraX = Integer.MAX_VALUE; + @Unique private int cc_oldCameraY = Integer.MAX_VALUE; + @Unique private int cc_oldCameraZ = Integer.MAX_VALUE; + @Shadow protected abstract int getSectionIndex(int x, int y, int z); // This could be multiple more specific injects, but overwriting the method is probably cleaner @@ -49,7 +57,7 @@ private int cc_onCreateSections_getMinY(Level instance, Operation origi return original.call(instance); } return 0; // I don't really understand the logic here, but returning 0 makes the Y axis behave equivalently to X and Z, which *should* be what - // we want + // we want } // TODO can we do this without fully overwriting the method? @@ -69,28 +77,107 @@ private void cc_onGetRenderSection(int sectionX, int sectionY, int sectionZ, Cal } // TODO can we do this with dasm + mixin? probably too messy - // I don't really understand the coordinate maths here, but we replicate it for the Y axis + // 1.21.6+ port by Zonix-Official of daporkchop_'s fast-path logic that was implemented to 1.12.2 @Inject(method = "repositionCamera", at = @At("HEAD"), cancellable = true) private void cc_onRepositionCamera(SectionPos newSectionPos, CallbackInfo ci) { if (!((CanBeCubic) level).cc_isCubic()) { return; } ci.cancel(); - for (int sectionX = 0; sectionX < this.sectionGridSizeX; sectionX++) { - int i1 = newSectionPos.x() - this.viewDistance; - int originX = i1 + Math.floorMod(sectionX - i1, this.sectionGridSizeX); - - for (int sectionZ = 0; sectionZ < this.sectionGridSizeZ; sectionZ++) { - int i2 = newSectionPos.z() - this.viewDistance; - int originZ = i2 + Math.floorMod(sectionZ - i2, this.sectionGridSizeZ); - - for (int sectionY = 0; sectionY < this.sectionGridSizeY; sectionY++) { - int i3 = newSectionPos.y() - this.viewDistance; - int originY = i3 + Math.floorMod(sectionY - i3, this.sectionGridSizeY); - SectionRenderDispatcher.RenderSection renderSection = this.sections[this.getSectionIndex(sectionX, sectionY, sectionZ)]; - long oldSectionNode = renderSection.getSectionNode(); - if (oldSectionNode != SectionPos.asLong(originX, originY, originZ)) { - renderSection.setSectionNode(SectionPos.asLong(originX, originY, originZ)); + + Entity cameraEntity = Minecraft.getInstance().getCameraEntity(); + if (cameraEntity == null){ + return; + } + + int cameraX = Coords.blockToCube(cameraEntity.getX()); + int cameraY = Coords.blockToCube(cameraEntity.getY()); + int cameraZ = Coords.blockToCube(cameraEntity.getZ()); + + int dx = this.sectionGridSizeX; + int dy = this.sectionGridSizeY; + int dz = this.sectionGridSizeZ; + + int px = newSectionPos.x() - this.viewDistance; + int py = newSectionPos.y() - this.viewDistance; + int pz = newSectionPos.z() - this.viewDistance; + + int minX = cameraX - (dx >> 1); + int minY = cameraY - (dy >> 1); + int minZ = cameraZ - (dz >> 1); + + long changeX = (long) cameraX - this.cc_oldCameraX; + long changeY = (long) cameraY - this.cc_oldCameraY; + long changeZ = (long) cameraZ - this.cc_oldCameraZ; + this.cc_oldCameraX = cameraX; + this.cc_oldCameraY = cameraY; + this.cc_oldCameraZ = cameraZ; + + if (Math.abs(changeX) <= 1 && Math.abs(changeY) <= 1 && Math.abs(changeZ) <= 1) { + if (changeX != 0) { + int indexX = Math.floorMod(changeX < 0 ? minX - px : minX - px - 1, dx); + int originX = px + Math.floorMod(indexX - px, dx); + + for (int indexZ = 0; indexZ < dz; indexZ++) { + int idxz = indexZ * dy * dx; + int originZ = pz + Math.floorMod(indexZ - pz, dz); + + for (int indexY = 0; indexY < dy; indexY++) { + int idxyz = idxz + indexY * dx; + int originY = py + Math.floorMod(indexY - py, dy); + + cc_refreshSectionNode(idxyz + indexX, originX, originY, originZ); + } + } + } + + if (changeY != 0) { + int indexY = Math.floorMod(changeY < 0 ? minY - py : minY - py - 1, dy); + int originY = py + Math.floorMod(indexY - py, dy); + + for (int indexZ = 0; indexZ < dz; indexZ++) { + int originZ = pz + Math.floorMod(indexZ - pz, dz); + int idxZ = indexZ * dy * dx; + + int idxyz = idxZ + indexY * dx; + + for (int indexX = 0; indexX < dx; indexX++) { + int originX = px + Math.floorMod(indexX - px, dx); + + cc_refreshSectionNode(idxyz + indexX, originX, originY, originZ); + } + } + } + + if (changeZ != 0) { + int indexZ = Math.floorMod(changeZ < 0 ? minZ - pz : minZ - pz - 1, dz); + int originZ = pz + Math.floorMod(indexZ - pz, dz); + int idxz = indexZ * dy * dx; + + for (int indexY = 0; indexY < dy; indexY++) { + int originY = py + Math.floorMod(indexY - py, dy); + int idxyz = idxz + indexY * dx; + + for (int indexX = 0; indexX < dx; indexX++) { + int originX = px + Math.floorMod(indexX - px, dx); + + cc_refreshSectionNode(idxyz + indexX, originX, originY, originZ); + } + } + } + } else { + for (int indexZ = 0; indexZ < dz; indexZ++) { + int idxz = indexZ * dy * dx; + int originZ = pz + Math.floorMod(indexZ - pz, dz); + + for (int indexY = 0; indexY < dy; indexY++) { + int idxyz = idxz + indexY * dx; + int originY = py + Math.floorMod(indexY - py, dy); + + for (int indexX = 0; indexX < dx; indexX++) { + int originX = px + Math.floorMod(indexX - px, dx); + + cc_refreshSectionNode(idxyz + indexX, originX, originY, originZ); } } } @@ -100,9 +187,17 @@ private void cc_onRepositionCamera(SectionPos newSectionPos, CallbackInfo ci) { this.levelRenderer.getSectionOcclusionGraph().invalidate(); } + private void cc_refreshSectionNode(int sectionIndex, int originX, int originY, int originZ) { + SectionRenderDispatcher.RenderSection renderSection = this.sections[sectionIndex]; + long oldSectionNode = renderSection.getSectionNode(); + if (oldSectionNode != SectionPos.asLong(originX, originY, originZ)) { + renderSection.setSectionNode(SectionPos.asLong(originX, originY, originZ)); + } + } + private boolean cc_containsSection(int x, int y, int z) { return x >= this.cameraSectionPos.x() - this.viewDistance && x <= this.cameraSectionPos.x() + this.viewDistance - && y >= this.cameraSectionPos.y() - this.viewDistance && y <= this.cameraSectionPos.y() + this.viewDistance - && z >= this.cameraSectionPos.z() - this.viewDistance && z <= this.cameraSectionPos.z() + this.viewDistance; + && y >= this.cameraSectionPos.y() - this.viewDistance && y <= this.cameraSectionPos.y() + this.viewDistance + && z >= this.cameraSectionPos.z() - this.viewDistance && z <= this.cameraSectionPos.z() + this.viewDistance; } } From af780e53b7ef7fba6e353c864aed23f0c3d13f55 Mon Sep 17 00:00:00 2001 From: Zonix <64276800+Zonix-Official@users.noreply.github.com> Date: Fri, 4 Sep 2026 00:20:25 +0100 Subject: [PATCH 2/3] Resolved formatting and added missing @Unique markings to `MixinViewArea.java` --- .../core/client/renderer/MixinViewArea.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java index 7248c93e3..6c40c2a51 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java @@ -31,9 +31,12 @@ public abstract class MixinViewArea { @Shadow private SectionPos cameraSectionPos; @Shadow @Final protected LevelRenderer levelRenderer; - @Unique private int cc_oldCameraX = Integer.MAX_VALUE; - @Unique private int cc_oldCameraY = Integer.MAX_VALUE; - @Unique private int cc_oldCameraZ = Integer.MAX_VALUE; + @Unique + private int cc_oldCameraX = Integer.MAX_VALUE; + @Unique + private int cc_oldCameraY = Integer.MAX_VALUE; + @Unique + private int cc_oldCameraZ = Integer.MAX_VALUE; @Shadow protected abstract int getSectionIndex(int x, int y, int z); @@ -86,7 +89,7 @@ private void cc_onRepositionCamera(SectionPos newSectionPos, CallbackInfo ci) { ci.cancel(); Entity cameraEntity = Minecraft.getInstance().getCameraEntity(); - if (cameraEntity == null){ + if (cameraEntity == null) { return; } @@ -187,6 +190,7 @@ private void cc_onRepositionCamera(SectionPos newSectionPos, CallbackInfo ci) { this.levelRenderer.getSectionOcclusionGraph().invalidate(); } + @Unique private void cc_refreshSectionNode(int sectionIndex, int originX, int originY, int originZ) { SectionRenderDispatcher.RenderSection renderSection = this.sections[sectionIndex]; long oldSectionNode = renderSection.getSectionNode(); @@ -195,9 +199,10 @@ private void cc_refreshSectionNode(int sectionIndex, int originX, int originY, i } } + @Unique private boolean cc_containsSection(int x, int y, int z) { return x >= this.cameraSectionPos.x() - this.viewDistance && x <= this.cameraSectionPos.x() + this.viewDistance - && y >= this.cameraSectionPos.y() - this.viewDistance && y <= this.cameraSectionPos.y() + this.viewDistance - && z >= this.cameraSectionPos.z() - this.viewDistance && z <= this.cameraSectionPos.z() + this.viewDistance; + && y >= this.cameraSectionPos.y() - this.viewDistance && y <= this.cameraSectionPos.y() + this.viewDistance + && z >= this.cameraSectionPos.z() - this.viewDistance && z <= this.cameraSectionPos.z() + this.viewDistance; } } From d8e0fe5f66833133c1b1fef2afff02ebbc264c92 Mon Sep 17 00:00:00 2001 From: Zonix <64276800+Zonix-Official@users.noreply.github.com> Date: Fri, 4 Sep 2026 00:29:02 +0100 Subject: [PATCH 3/3] Added warning supression for checkstyle on guidance from notStirred --- .../cubicchunks/mixin/core/client/renderer/MixinViewArea.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java index 6c40c2a51..465ed1909 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/renderer/MixinViewArea.java @@ -81,6 +81,7 @@ private void cc_onGetRenderSection(int sectionX, int sectionY, int sectionZ, Cal // TODO can we do this with dasm + mixin? probably too messy // 1.21.6+ port by Zonix-Official of daporkchop_'s fast-path logic that was implemented to 1.12.2 + @SuppressWarnings({ "checkstyle:CyclomaticComplexity", "checkstyle:JavaNCSS", "checkstyle:NPathComplexity" }) @Inject(method = "repositionCamera", at = @At("HEAD"), cancellable = true) private void cc_onRepositionCamera(SectionPos newSectionPos, CallbackInfo ci) { if (!((CanBeCubic) level).cc_isCubic()) {