Browse Source

Take advantage of updated Java, Close #100

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 4 years ago
parent
commit
9e845f5d27

+ 4 - 7
common/src/main/java/me/shedaniel/lightoverlay/common/ClothScreen.java

@@ -1,9 +1,6 @@
 package me.shedaniel.lightoverlay.common;
 
 import me.shedaniel.clothconfig2.api.ConfigBuilder;
-import me.shedaniel.clothconfig2.api.ConfigCategory;
-import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
-import me.shedaniel.clothconfig2.gui.entries.IntegerSliderEntry;
 import net.minecraft.client.gui.screens.Screen;
 import net.minecraft.client.resources.language.I18n;
 import net.minecraft.network.chat.Component;
@@ -15,14 +12,14 @@ import java.util.Optional;
 
 public class ClothScreen {
     public static Screen getConfigScreenByCloth(Screen parent) {
-        ConfigBuilder builder = ConfigBuilder.create().setParentScreen(parent).setTitle(new TranslatableComponent("key.lightoverlay.category"));
+        var builder = ConfigBuilder.create().setParentScreen(parent).setTitle(new TranslatableComponent("key.lightoverlay.category"));
         
-        ConfigEntryBuilder eb = builder.entryBuilder();
-        ConfigCategory general = builder.getOrCreateCategory(new TranslatableComponent("config.lightoverlay.general"));
+        var eb = builder.entryBuilder();
+        var general = builder.getOrCreateCategory(new TranslatableComponent("config.lightoverlay.general"));
         general.addEntry(eb.startTextDescription(Component.nullToEmpty("§7" + I18n.get("description.lightoverlay.caching"))).build());
         general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.caching"), LightOverlay.caching).setDefaultValue(false).setSaveConsumer(bool -> LightOverlay.caching = bool).build());
         general.addEntry(eb.startIntSlider(new TranslatableComponent("config.lightoverlay.reach"), LightOverlay.reach, 1, 64).setDefaultValue(12).setTextGetter(integer -> Component.nullToEmpty("Reach: " + integer + " Blocks")).setSaveConsumer(integer -> LightOverlay.reach = integer).build());
-        IntegerSliderEntry crossLevel = eb.startIntSlider(new TranslatableComponent("config.lightoverlay.crossLevel"), LightOverlay.crossLevel, 0, 15).setDefaultValue(7).setTextGetter(integer -> Component.nullToEmpty("Cross Level: " + integer)).setSaveConsumer(integer -> LightOverlay.crossLevel = integer).build();
+        var crossLevel = eb.startIntSlider(new TranslatableComponent("config.lightoverlay.crossLevel"), LightOverlay.crossLevel, 0, 15).setDefaultValue(7).setTextGetter(integer -> Component.nullToEmpty("Cross Level: " + integer)).setSaveConsumer(integer -> LightOverlay.crossLevel = integer).build();
         general.addEntry(crossLevel);
         general.addEntry(eb.startIntSlider(new TranslatableComponent("config.lightoverlay.secondaryLevel"), LightOverlay.secondaryLevel, -1, 15)
                 .setErrorSupplier(integer -> {

+ 1 - 1
common/src/main/java/me/shedaniel/lightoverlay/common/CubicChunkPos.java

@@ -74,7 +74,7 @@ public class CubicChunkPos {
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
-        CubicChunkPos that = (CubicChunkPos) o;
+        var that = (CubicChunkPos) o;
         return x == that.x && y == that.y && z == that.z;
     }
     

+ 7 - 0
common/src/main/java/me/shedaniel/lightoverlay/common/FrustumHelperAccess.java

@@ -0,0 +1,7 @@
+package me.shedaniel.lightoverlay.common;
+
+import net.minecraft.client.renderer.culling.Frustum;
+
+public interface FrustumHelperAccess {
+    boolean isVisible(Frustum frustum, double minX, double minY, double minZ, double maxX, double maxY, double maxZ);
+}

+ 9 - 22
common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlay.java

@@ -1,10 +1,8 @@
 package me.shedaniel.lightoverlay.common;
 
 import com.mojang.blaze3d.platform.InputConstants;
-import com.mojang.blaze3d.vertex.PoseStack;
 import dev.architectury.event.events.client.ClientGuiEvent;
 import dev.architectury.event.events.client.ClientTickEvent;
-import dev.architectury.injectables.targets.ArchitecturyTarget;
 import dev.architectury.platform.Platform;
 import dev.architectury.registry.client.keymappings.KeyMappingRegistry;
 import net.minecraft.client.KeyMapping;
@@ -17,7 +15,6 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.text.DecimalFormat;
 import java.util.Properties;
-import java.util.function.Consumer;
 
 public class LightOverlay {
     public static final DecimalFormat FORMAT = new DecimalFormat("#.#");
@@ -39,6 +36,7 @@ public class LightOverlay {
     
     public static LightOverlayTicker ticker = new LightOverlayTicker();
     public static LightOverlayRenderer renderer = new LightOverlayRenderer(ticker);
+    public static int blocksScanned = 0;
     
     public static void register() {
         // Load Config
@@ -48,14 +46,12 @@ public class LightOverlay {
         enableOverlay = createKeyBinding(new ResourceLocation("lightoverlay", "enable_overlay"), InputConstants.Type.KEYSYM, 296, "key.lightoverlay.category");
         KeyMappingRegistry.register(enableOverlay);
         
-        registerDebugRenderer(renderer);
-        
         ClientGuiEvent.DEBUG_TEXT_LEFT.register(list -> {
             if (enabled) {
                 if (caching) {
-                    list.add(String.format("[Light Overlay] Chunks to queue: %02d", ticker.POS.size()));
+                    list.add(String.format("[Light Overlay] Chunks to queue: %02d; %d Blocks Scanned", ticker.POS.size(), blocksScanned));
                 } else {
-                    list.add("[Light Overlay] Enabled");
+                    list.add(String.format("[Light Overlay] Enabled; %d Blocks Scanned", blocksScanned));
                 }
             } else {
                 list.add("[Light Overlay] Disabled");
@@ -66,9 +62,9 @@ public class LightOverlay {
     
     
     public static void queueChunkAndNear(CubicChunkPos pos) {
-        for (int xOffset = -1; xOffset <= 1; xOffset++) {
-            for (int yOffset = -1; yOffset <= 1; yOffset++) {
-                for (int zOffset = -1; zOffset <= 1; zOffset++) {
+        for (var xOffset = -1; xOffset <= 1; xOffset++) {
+            for (var yOffset = -1; yOffset <= 1; yOffset++) {
+                for (var zOffset = -1; zOffset <= 1; zOffset++) {
                     queueChunk(new CubicChunkPos(pos.x + xOffset, pos.y + yOffset, pos.z + zOffset));
                 }
             }
@@ -91,8 +87,8 @@ public class LightOverlay {
             secondaryColor = 0x0000FF;
             if (!file.exists() || !file.canRead())
                 saveConfig(file);
-            FileInputStream fis = new FileInputStream(file);
-            Properties properties = new Properties();
+            var fis = new FileInputStream(file);
+            var properties = new Properties();
             properties.load(fis);
             fis.close();
             reach = Integer.parseInt((String) properties.computeIfAbsent("reach", a -> "12"));
@@ -152,7 +148,7 @@ public class LightOverlay {
     }
     
     public static void saveConfig(File file) throws IOException {
-        FileOutputStream fos = new FileOutputStream(file, false);
+        var fos = new FileOutputStream(file, false);
         fos.write("# Light Overlay Config".getBytes());
         fos.write("\n".getBytes());
         fos.write(("reach=" + reach).getBytes());
@@ -195,15 +191,6 @@ public class LightOverlay {
         return new KeyMapping("key." + id.getNamespace() + "." + id.getPath(), type, code, category);
     }
     
-    
-    private static void registerDebugRenderer(Consumer<PoseStack> runnable) {
-        try {
-            Class.forName("me.shedaniel.lightoverlay." + ArchitecturyTarget.getCurrentTarget() + ".LightOverlayImpl").getDeclaredField("debugRenderer").set(null, runnable);
-        } catch (Throwable throwable) {
-            throw new RuntimeException(throwable);
-        }
-    }
-    
     public static final byte CROSS_YELLOW = 0;
     public static final byte CROSS_RED = 1;
     public static final byte CROSS_SECONDARY = 2;

+ 43 - 63
common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayRenderer.java

@@ -1,16 +1,11 @@
 package me.shedaniel.lightoverlay.common;
 
-import com.google.common.base.Suppliers;
 import com.mojang.blaze3d.systems.RenderSystem;
 import com.mojang.blaze3d.vertex.*;
 import com.mojang.math.Matrix4f;
 import com.mojang.math.Vector3f;
-import dev.architectury.injectables.targets.ArchitecturyTarget;
-import it.unimi.dsi.fastutil.longs.Long2ByteMap;
 import net.minecraft.client.Camera;
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.Font;
-import net.minecraft.client.player.LocalPlayer;
 import net.minecraft.client.renderer.GameRenderer;
 import net.minecraft.client.renderer.MultiBufferSource;
 import net.minecraft.client.renderer.culling.Frustum;
@@ -19,19 +14,14 @@ import net.minecraft.core.Direction;
 import net.minecraft.util.Mth;
 import net.minecraft.world.level.Level;
 import net.minecraft.world.phys.shapes.CollisionContext;
-import net.minecraft.world.phys.shapes.VoxelShape;
 
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.util.Map;
 import java.util.function.Consumer;
-import java.util.function.Supplier;
 
 public class LightOverlayRenderer implements Consumer<PoseStack> {
     private final Minecraft minecraft = Minecraft.getInstance();
     public Frustum frustum;
     public LightOverlayTicker ticker;
+    public FrustumHelperAccess frustumAccess;
     
     public LightOverlayRenderer(LightOverlayTicker ticker) {
         this.ticker = ticker;
@@ -40,14 +30,14 @@ public class LightOverlayRenderer implements Consumer<PoseStack> {
     @Override
     public void accept(PoseStack poses) {
         if (LightOverlay.enabled) {
-            LocalPlayer playerEntity = minecraft.player;
-            BlockPos playerPos = new BlockPos(playerEntity.getX(), playerEntity.getY(), playerEntity.getZ());
-            int playerPosX = playerPos.getX() >> 4;
-            int playerPosY = playerPos.getY() >> 5;
-            int playerPosZ = playerPos.getZ() >> 4;
-            CollisionContext collisionContext = CollisionContext.of(playerEntity);
-            Camera camera = minecraft.gameRenderer.getMainCamera();
-            int chunkRange = LightOverlay.getChunkRange();
+            var playerEntity = minecraft.player;
+            var playerPos = new BlockPos(playerEntity.getX(), playerEntity.getY(), playerEntity.getZ());
+            var playerPosX = playerPos.getX() >> 4;
+            var playerPosY = playerPos.getY() >> 5;
+            var playerPosZ = playerPos.getZ() >> 4;
+            var collisionContext = CollisionContext.of(playerEntity);
+            var camera = minecraft.gameRenderer.getMainCamera();
+            var chunkRange = LightOverlay.getChunkRange();
             
             if (LightOverlay.showNumber) {
                 renderLevels(new PoseStack(), camera, playerPos, playerPosX, playerPosY, playerPosZ, chunkRange, collisionContext);
@@ -60,15 +50,15 @@ public class LightOverlayRenderer implements Consumer<PoseStack> {
     private void renderLevels(PoseStack poses, Camera camera, BlockPos playerPos, int playerPosX, int playerPosY, int playerPosZ, int chunkRange, CollisionContext collisionContext) {
         RenderSystem.enableTexture();
         RenderSystem.depthMask(true);
-        BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
-        BlockPos.MutableBlockPos downMutable = new BlockPos.MutableBlockPos();
-        MultiBufferSource.BufferSource source = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
-        for (Map.Entry<CubicChunkPos, Long2ByteMap> entry : ticker.CHUNK_MAP.entrySet()) {
-            CubicChunkPos chunkPos = entry.getKey();
+        var mutable = new BlockPos.MutableBlockPos();
+        var downMutable = new BlockPos.MutableBlockPos();
+        var source = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
+        for (var entry : ticker.CHUNK_MAP.entrySet()) {
+            var chunkPos = entry.getKey();
             if (LightOverlay.caching && (Mth.abs(chunkPos.x - playerPosX) > chunkRange || Mth.abs(chunkPos.y - playerPosY) > Math.max(1, chunkRange >> 1) || Mth.abs(chunkPos.z - playerPosZ) > chunkRange)) {
                 continue;
             }
-            for (Long2ByteMap.Entry objectEntry : entry.getValue().long2ByteEntrySet()) {
+            for (var objectEntry : entry.getValue().long2ByteEntrySet()) {
                 mutable.set(objectEntry.getLongKey());
                 if (mutable.closerThan(playerPos, LightOverlay.reach)) {
                     if (isFrustumVisible(mutable.getX(), mutable.getY(), mutable.getZ(), mutable.getX() + 1, mutable.getX() + 1, mutable.getX() + 1)) {
@@ -83,21 +73,21 @@ public class LightOverlayRenderer implements Consumer<PoseStack> {
     }
     
     public void renderLevel(PoseStack poses, MultiBufferSource.BufferSource source, Camera camera, Level world, BlockPos pos, BlockPos down, byte level, CollisionContext collisionContext) {
-        String text = String.valueOf(level);
-        Font font = minecraft.font;
-        double cameraX = camera.getPosition().x;
-        double cameraY = camera.getPosition().y;
-        VoxelShape upperOutlineShape = world.getBlockState(down).getShape(world, down, collisionContext);
+        var text = String.valueOf(level);
+        var font = minecraft.font;
+        var cameraX = camera.getPosition().x;
+        var cameraY = camera.getPosition().y;
+        var upperOutlineShape = world.getBlockState(down).getShape(world, down, collisionContext);
         if (!upperOutlineShape.isEmpty())
             cameraY += 1 - upperOutlineShape.max(Direction.Axis.Y);
-        double cameraZ = camera.getPosition().z;
+        var cameraZ = camera.getPosition().z;
         poses.pushPose();
         poses.translate(pos.getX() + 0.5 - cameraX, pos.getY() - cameraY + 0.005, pos.getZ() + 0.5 - cameraZ);
         poses.mulPose(Vector3f.XP.rotationDegrees(90));
 //        poses.glNormal3f(0.0F, 1.0F, 0.0F);
-        float size = 0.07F;
+        var size = 0.07F;
         poses.scale(-size, -size, size);
-        float float_3 = (float) (-font.width(text)) / 2.0F + 0.4f;
+        var float_3 = (float) (-font.width(text)) / 2.0F + 0.4f;
         font.drawInBatch(text, float_3, -3.5f, level > LightOverlay.higherCrossLevel ? 0xff042404 : (LightOverlay.lowerCrossLevel >= 0 && level > LightOverlay.lowerCrossLevel ? 0xff0066ff : 0xff731111), false, poses.last().pose(), source, false, 0, 15728880);
         poses.popPose();
     }
@@ -108,24 +98,23 @@ public class LightOverlayRenderer implements Consumer<PoseStack> {
         RenderSystem.disableBlend();
         RenderSystem.setShader(GameRenderer::getPositionColorShader);
         RenderSystem.lineWidth(LightOverlay.lineWidth);
-        Tesselator tesselator = Tesselator.getInstance();
-        BufferBuilder builder = tesselator.getBuilder();
+        var tesselator = Tesselator.getInstance();
+        var builder = tesselator.getBuilder();
         builder.begin(VertexFormat.Mode.DEBUG_LINES, DefaultVertexFormat.POSITION_COLOR);
-        BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
-    
-        System.out.println(ticker.CHUNK_MAP.size());
-        for (Map.Entry<CubicChunkPos, Long2ByteMap> entry : ticker.CHUNK_MAP.entrySet()) {
-            CubicChunkPos chunkPos = entry.getKey();
+        var mutable = new BlockPos.MutableBlockPos();
+        
+        for (var entry : ticker.CHUNK_MAP.entrySet()) {
+            var chunkPos = entry.getKey();
             if (LightOverlay.caching && (Mth.abs(chunkPos.x - playerPosX) > chunkRange || Mth.abs(chunkPos.y - playerPosY) > Math.max(1, chunkRange >> 1) || Mth.abs(chunkPos.z - playerPosZ) > chunkRange)) {
                 continue;
             }
             
-            for (Long2ByteMap.Entry objectEntry : entry.getValue().long2ByteEntrySet()) {
-                byte crossType = objectEntry.getByteValue();
+            for (var objectEntry : entry.getValue().long2ByteEntrySet()) {
+                var crossType = objectEntry.getByteValue();
                 mutable.set(objectEntry.getLongKey());
                 if (mutable.closerThan(playerPos, LightOverlay.reach)) {
                     if (isFrustumVisible(mutable.getX(), mutable.getY(), mutable.getZ(), mutable.getX() + 1, mutable.getX() + 1, mutable.getX() + 1)) {
-                        int color = switch (crossType) {
+                        var color = switch (crossType) {
                             case LightOverlay.CROSS_RED -> LightOverlay.redColor;
                             case LightOverlay.CROSS_YELLOW -> LightOverlay.yellowColor;
                             default -> LightOverlay.secondaryColor;
@@ -143,39 +132,30 @@ public class LightOverlayRenderer implements Consumer<PoseStack> {
     }
     
     public void renderCross(Matrix4f pose, BufferBuilder builder, Camera camera, Level world, BlockPos pos, int color, CollisionContext collisionContext) {
-        double cameraX = camera.getPosition().x;
-        double cameraY = camera.getPosition().y - .005D;
+        var cameraX = camera.getPosition().x;
+        var cameraY = camera.getPosition().y - .005D;
         double blockOffset = 0;
-        VoxelShape upperOutlineShape = world.getBlockState(pos).getShape(world, pos, collisionContext);
+        var upperOutlineShape = world.getBlockState(pos).getShape(world, pos, collisionContext);
         if (!upperOutlineShape.isEmpty()) {
             blockOffset += upperOutlineShape.max(Direction.Axis.Y);
         }
-        double cameraZ = camera.getPosition().z;
+        var cameraZ = camera.getPosition().z;
         
-        int red = (color >> 16) & 255;
-        int green = (color >> 8) & 255;
-        int blue = color & 255;
-        double x = pos.getX() - cameraX;
-        double y = pos.getY() - cameraY + blockOffset;
-        double z = pos.getZ() - cameraZ;
+        var red = (color >> 16) & 255;
+        var green = (color >> 8) & 255;
+        var blue = color & 255;
+        var x = pos.getX() - cameraX;
+        var y = pos.getY() - cameraY + blockOffset;
+        var z = pos.getZ() - cameraZ;
         builder.vertex(x + .01, y, z + .01).color(red, green, blue, 255).endVertex();
         builder.vertex(x + .99, y, z + .99).color(red, green, blue, 255).endVertex();
         builder.vertex(x + .99, y, z + .01).color(red, green, blue, 255).endVertex();
         builder.vertex(x + .01, y, z + .99).color(red, green, blue, 255).endVertex();
     }
     
-    private static final Supplier<MethodHandle> IS_FRUSTUM_VISIBLE = Suppliers.memoize(() -> {
-        try {
-            return MethodHandles.lookup().findStatic(Class.forName("me.shedaniel.lightoverlay." + ArchitecturyTarget.getCurrentTarget() + ".LightOverlayImpl"), "isFrustumVisible",
-                    MethodType.methodType(boolean.class, Frustum.class, double.class, double.class, double.class, double.class, double.class, double.class));
-        } catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException e) {
-            throw new RuntimeException(e);
-        }
-    });
-    
     public boolean isFrustumVisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
         try {
-            return frustum == null || (boolean) IS_FRUSTUM_VISIBLE.get().invokeExact(frustum, minX, minY, minZ, maxX, maxY, maxZ);
+            return frustum == null || frustumAccess.isVisible(frustum, minX, minY, minZ, maxX, maxY, maxZ);
         } catch (Throwable throwable) {
             throw new RuntimeException(throwable);
         }

+ 74 - 62
common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayTicker.java

@@ -1,12 +1,11 @@
 package me.shedaniel.lightoverlay.common;
 
+import com.google.common.base.Stopwatch;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.Maps;
 import it.unimi.dsi.fastutil.longs.Long2ByteMap;
 import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.multiplayer.ClientLevel;
-import net.minecraft.client.player.LocalPlayer;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
 import net.minecraft.tags.BlockTags;
@@ -19,15 +18,16 @@ import net.minecraft.world.level.Level;
 import net.minecraft.world.level.LightLayer;
 import net.minecraft.world.level.biome.Biome;
 import net.minecraft.world.level.block.Block;
-import net.minecraft.world.level.block.state.BlockState;
 import net.minecraft.world.level.chunk.ChunkStatus;
 import net.minecraft.world.level.chunk.LevelChunk;
 import net.minecraft.world.level.lighting.LayerLightEventListener;
 import net.minecraft.world.phys.shapes.CollisionContext;
-import net.minecraft.world.phys.shapes.VoxelShape;
 import org.apache.logging.log4j.LogManager;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.function.Supplier;
@@ -37,7 +37,7 @@ public class LightOverlayTicker {
     private long ticks = 0;
     private static int threadNumber = 0;
     private static final ThreadPoolExecutor EXECUTOR = (ThreadPoolExecutor) Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), r -> {
-        Thread thread = new Thread(r, "light-overlay-" + threadNumber++);
+        var thread = new Thread(r, "light-overlay-" + threadNumber++);
         thread.setDaemon(true);
         return thread;
     });
@@ -65,32 +65,32 @@ public class LightOverlayTicker {
                 EXECUTOR.getQueue().clear();
                 CHUNK_MAP.clear();
             } else {
-                LocalPlayer player = minecraft.player;
-                ClientLevel world = minecraft.level;
-                CollisionContext collisionContext = CollisionContext.of(player);
+                var player = minecraft.player;
+                var world = minecraft.level;
+                var collisionContext = CollisionContext.of(player);
                 
                 if (!LightOverlay.caching) {
                     CALCULATING_POS.clear();
                     POS.clear();
                     CHUNK_MAP.clear();
-                    BlockPos playerPos = player.blockPosition();
-                    LayerLightEventListener block = world.getLightEngine().getLayerListener(LightLayer.BLOCK);
-                    LayerLightEventListener sky = LightOverlay.showNumber ? null : world.getLightEngine().getLayerListener(LightLayer.SKY);
-                    BlockPos.MutableBlockPos downPos = new BlockPos.MutableBlockPos();
-                    Iterable<BlockPos> iterate = BlockPos.betweenClosed(playerPos.getX() - LightOverlay.reach, playerPos.getY() - LightOverlay.reach, playerPos.getZ() - LightOverlay.reach,
+                    var playerPos = player.blockPosition();
+                    var block = world.getLightEngine().getLayerListener(LightLayer.BLOCK);
+                    var sky = LightOverlay.showNumber ? null : world.getLightEngine().getLayerListener(LightLayer.SKY);
+                    var downPos = new BlockPos.MutableBlockPos();
+                    var iterate = BlockPos.betweenClosed(playerPos.getX() - LightOverlay.reach, playerPos.getY() - LightOverlay.reach, playerPos.getZ() - LightOverlay.reach,
                             playerPos.getX() + LightOverlay.reach, playerPos.getY() + LightOverlay.reach, playerPos.getZ() + LightOverlay.reach);
                     Long2ByteMap chunkData = new Long2ByteOpenHashMap();
                     CHUNK_MAP.put(new CubicChunkPos(0, 0, 0), chunkData);
-                    for (BlockPos blockPos : iterate) {
+                    for (var blockPos : iterate) {
                         downPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ());
                         if (LightOverlay.showNumber) {
-                            int level = getCrossLevel(blockPos, downPos, world, block, collisionContext);
+                            var level = getCrossLevel(blockPos, downPos, world, block, collisionContext);
                             if (level >= 0) {
                                 chunkData.put(blockPos.asLong(), (byte) level);
                             }
                         } else {
-                            Biome biome = !LightOverlay.mushroom ? world.getBiome(blockPos) : null;
-                            byte type = getCrossType(blockPos, biome, downPos, world, block, sky, collisionContext);
+                            var biome = !LightOverlay.mushroom ? world.getBiome(blockPos) : null;
+                            var type = getCrossType(blockPos, biome, downPos, world, block, sky, collisionContext);
                             if (type != LightOverlay.CROSS_NONE) {
                                 chunkData.put(blockPos.asLong(), type);
                             }
@@ -99,37 +99,37 @@ public class LightOverlayTicker {
                 } else {
                     var height = Mth.ceil(Minecraft.getInstance().level.getHeight() / 32.0);
                     var start = Math.floorDiv(Minecraft.getInstance().level.getMinBuildHeight(), 32);
-                    int playerPosX = ((int) player.getX()) >> 4;
-                    int playerPosY = ((int) player.getY()) >> 5;
-                    int playerPosZ = ((int) player.getZ()) >> 4;
+                    var playerPosX = ((int) player.getX()) >> 4;
+                    var playerPosY = ((int) player.getY()) >> 5;
+                    var playerPosZ = ((int) player.getZ()) >> 4;
                     var chunkRange = LightOverlay.getChunkRange();
-                    for (int chunkX = playerPosX - chunkRange; chunkX <= playerPosX + chunkRange; chunkX++) {
-                        for (int chunkY = Math.max(playerPosY - Math.max(1, chunkRange >> 1), start); chunkY <= playerPosY + Math.max(1, chunkRange >> 1) && chunkY <= start + height; chunkY++) {
-                            for (int chunkZ = playerPosZ - chunkRange; chunkZ <= playerPosZ + chunkRange; chunkZ++) {
+                    for (var chunkX = playerPosX - chunkRange; chunkX <= playerPosX + chunkRange; chunkX++) {
+                        for (var chunkY = Math.max(playerPosY - Math.max(1, chunkRange >> 1), start); chunkY <= playerPosY + Math.max(1, chunkRange >> 1) && chunkY <= start + height; chunkY++) {
+                            for (var chunkZ = playerPosZ - chunkRange; chunkZ <= playerPosZ + chunkRange; chunkZ++) {
                                 if (Mth.abs(chunkX - playerPosX) > chunkRange || Mth.abs(chunkY - playerPosY) > chunkRange || Mth.abs(chunkZ - playerPosZ) > chunkRange)
                                     continue;
-                                CubicChunkPos chunkPos = new CubicChunkPos(chunkX, chunkY, chunkZ);
+                                var chunkPos = new CubicChunkPos(chunkX, chunkY, chunkZ);
                                 if (!CHUNK_MAP.containsKey(chunkPos))
                                     queueChunk(chunkPos);
                             }
                         }
                     }
-                    for (int p = 0; p < 3; p++) {
+                    for (var p = 0; p < 3; p++) {
                         if (EXECUTOR.getQueue().size() >= Runtime.getRuntime().availableProcessors()) break;
                         double d1 = Double.MAX_VALUE, d2 = Double.MAX_VALUE, d3 = Double.MAX_VALUE;
                         CubicChunkPos c1 = null, c2 = null, c3 = null;
                         synchronized (POS) {
-                            Iterator<CubicChunkPos> iterator = POS.iterator();
+                            var iterator = POS.iterator();
                             while (iterator.hasNext()) {
-                                CubicChunkPos pos = iterator.next();
+                                var pos = iterator.next();
                                 if (Mth.abs(pos.x - playerPosX) > chunkRange || Mth.abs(pos.y - playerPosY) > Math.max(1, chunkRange >> 1) || Mth.abs(pos.z - playerPosZ) > chunkRange || CALCULATING_POS.contains(pos)) {
                                     iterator.remove();
                                 } else {
                                     if (LightOverlay.renderer.isFrustumVisible(pos.getMinBlockX(), pos.getMinBlockY(), pos.getMinBlockZ(), pos.getMaxBlockX(), pos.getMaxBlockY(), pos.getMaxBlockZ())) {
-                                        int dx = Math.abs(pos.x - playerPosX);
-                                        int dy = Math.abs(pos.y - playerPosY) << 1;
-                                        int dz = Math.abs(pos.z - playerPosZ);
-                                        double distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
+                                        var dx = Math.abs(pos.x - playerPosX);
+                                        var dy = Math.abs(pos.y - playerPosY) << 1;
+                                        var dz = Math.abs(pos.z - playerPosZ);
+                                        var distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
                                         if (distance < d1) {
                                             d3 = d2;
                                             d2 = d1;
@@ -150,9 +150,9 @@ public class LightOverlayTicker {
                                 }
                             }
                         }
-                        CubicChunkPos finalC1 = c1;
-                        CubicChunkPos finalC2 = c2;
-                        CubicChunkPos finalC3 = c3;
+                        var finalC1 = c1;
+                        var finalC2 = c2;
+                        var finalC3 = c3;
                         if (finalC1 != null) {
                             CALCULATING_POS.add(finalC1);
                             POS.remove(finalC1);
@@ -165,12 +165,18 @@ public class LightOverlayTicker {
                                 }
                             }
                             EXECUTOR.submit(() -> {
-                                int playerPosX1 = ((int) minecraft.player.getX()) >> 4;
-                                int playerPosY1 = ((int) minecraft.player.getY()) >> 5;
-                                int playerPosZ1 = ((int) minecraft.player.getZ()) >> 4;
-                                if (finalC1 != null) processChunk(finalC1, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
-                                if (finalC2 != null) processChunk(finalC2, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
-                                if (finalC3 != null) processChunk(finalC3, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
+                                var playerPosX1 = ((int) minecraft.player.getX()) >> 4;
+                                var playerPosY1 = ((int) minecraft.player.getY()) >> 5;
+                                var playerPosZ1 = ((int) minecraft.player.getZ()) >> 4;
+                                var count = 0;
+                                var stopwatch = Stopwatch.createStarted();
+                                if (finalC1 != null) count += processChunk(finalC1, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
+                                if (finalC2 != null) count += processChunk(finalC2, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
+                                if (finalC3 != null) count += processChunk(finalC3, playerPosX1, playerPosY1, playerPosZ1, collisionContext);
+                                System.out.println(stopwatch.stop());
+                                synchronized (this) {
+                                    LightOverlay.blocksScanned += count;
+                                }
                             });
                         }
                     }
@@ -184,49 +190,55 @@ public class LightOverlayTicker {
         }
     }
     
-    private void processChunk(CubicChunkPos pos, int playerPosX, int playerPosY, int playerPosZ, CollisionContext context) {
+    private int processChunk(CubicChunkPos pos, int playerPosX, int playerPosY, int playerPosZ, CollisionContext context) {
         CALCULATING_POS.remove(pos);
-        int chunkRange = LightOverlay.getChunkRange();
+        var chunkRange = LightOverlay.getChunkRange();
         if (Mth.abs(pos.x - playerPosX) > chunkRange || Mth.abs(pos.y - playerPosY) > Math.max(1, chunkRange >> 1) || Mth.abs(pos.z - playerPosZ) > chunkRange || POS.contains(pos)) {
-            return;
+            return 0;
         }
         try {
-            calculateChunk(minecraft.level.getChunkSource().getChunk(pos.x, pos.z, ChunkStatus.FULL, false), minecraft.level, pos, context);
+            return calculateChunk(minecraft.level.getChunkSource().getChunk(pos.x, pos.z, ChunkStatus.FULL, false), minecraft.level, pos, context);
         } catch (Throwable throwable) {
             LogManager.getLogger().throwing(throwable);
         }
+        return 0;
     }
     
-    private void calculateChunk(LevelChunk chunk, Level world, CubicChunkPos chunkPos, CollisionContext collisionContext) {
+    private int calculateChunk(LevelChunk chunk, Level world, CubicChunkPos chunkPos, CollisionContext collisionContext) {
         if (world != null && chunk != null) {
             Long2ByteMap chunkData = new Long2ByteOpenHashMap();
-            LayerLightEventListener block = world.getLightEngine().getLayerListener(LightLayer.BLOCK);
-            LayerLightEventListener sky = LightOverlay.showNumber ? null : world.getLightEngine().getLayerListener(LightLayer.SKY);
-            for (BlockPos pos : BlockPos.betweenClosed(chunkPos.getMinBlockX(), chunkPos.getMinBlockY(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), chunkPos.getMaxBlockY(), chunkPos.getMaxBlockZ())) {
-                BlockPos down = pos.below();
+            var block = world.getLightEngine().getLayerListener(LightLayer.BLOCK);
+            var sky = LightOverlay.showNumber ? null : world.getLightEngine().getLayerListener(LightLayer.SKY);
+            var down = new BlockPos.MutableBlockPos();
+            var count = 0;
+            for (var pos : BlockPos.betweenClosed(chunkPos.getMinBlockX(), chunkPos.getMinBlockY(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), chunkPos.getMaxBlockY(), chunkPos.getMaxBlockZ())) {
+                down.setWithOffset(pos, 0, -1, 0);
+                count++;
                 if (LightOverlay.showNumber) {
-                    int level = getCrossLevel(pos, down, chunk, block, collisionContext);
+                    var level = getCrossLevel(pos, down, chunk, block, collisionContext);
                     if (level >= 0) {
                         chunkData.put(pos.asLong(), (byte) level);
                     }
                 } else {
-                    Biome biome = !LightOverlay.mushroom ? world.getBiome(pos) : null;
-                    byte type = getCrossType(pos, biome, down, chunk, block, sky, collisionContext);
+                    var biome = !LightOverlay.mushroom ? world.getBiome(pos) : null;
+                    var type = getCrossType(pos, biome, down, chunk, block, sky, collisionContext);
                     if (type != LightOverlay.CROSS_NONE) {
                         chunkData.put(pos.asLong(), type);
                     }
                 }
             }
             CHUNK_MAP.put(chunkPos, chunkData);
+            return count;
         } else {
             CHUNK_MAP.remove(chunkPos);
+            return 0;
         }
     }
     
     public byte getCrossType(BlockPos pos, Biome biome, BlockPos down, BlockGetter world, LayerLightEventListener block, LayerLightEventListener sky, CollisionContext entityContext) {
-        BlockState blockBelowState = world.getBlockState(down);
-        BlockState blockUpperState = world.getBlockState(pos);
-        VoxelShape upperCollisionShape = blockUpperState.getCollisionShape(world, pos, entityContext);
+        var blockBelowState = world.getBlockState(down);
+        var blockUpperState = world.getBlockState(pos);
+        var upperCollisionShape = blockUpperState.getCollisionShape(world, pos, entityContext);
         if (!LightOverlay.underwater && !blockUpperState.getFluidState().isEmpty())
             return LightOverlay.CROSS_NONE;
         // Check if the outline is full
@@ -245,8 +257,8 @@ public class LightOverlayTicker {
             return LightOverlay.CROSS_NONE;
         if (!LightOverlay.mushroom && Biome.BiomeCategory.MUSHROOM == biome.getBiomeCategory())
             return LightOverlay.CROSS_NONE;
-        int blockLightLevel = block.getLightValue(pos);
-        int skyLightLevel = sky.getLightValue(pos);
+        var blockLightLevel = block.getLightValue(pos);
+        var skyLightLevel = sky.getLightValue(pos);
         if (blockLightLevel > LightOverlay.higherCrossLevel)
             return LightOverlay.CROSS_NONE;
         if (skyLightLevel > LightOverlay.higherCrossLevel)
@@ -255,10 +267,10 @@ public class LightOverlayTicker {
     }
     
     public static int getCrossLevel(BlockPos pos, BlockPos down, BlockGetter world, LayerLightEventListener view, CollisionContext collisionContext) {
-        BlockState blockBelowState = world.getBlockState(down);
-        BlockState blockUpperState = world.getBlockState(pos);
-        VoxelShape collisionShape = blockBelowState.getCollisionShape(world, down, collisionContext);
-        VoxelShape upperCollisionShape = blockUpperState.getCollisionShape(world, pos, collisionContext);
+        var blockBelowState = world.getBlockState(down);
+        var blockUpperState = world.getBlockState(pos);
+        var collisionShape = blockBelowState.getCollisionShape(world, down, collisionContext);
+        var upperCollisionShape = blockUpperState.getCollisionShape(world, pos, collisionContext);
         if (!LightOverlay.underwater && !blockUpperState.getFluidState().isEmpty())
             return -1;
         if (!blockBelowState.getFluidState().isEmpty())

+ 8 - 8
fabric/src/main/java/me/shedaniel/lightoverlay/fabric/FrustumHelper.java

@@ -5,18 +5,18 @@ import net.minecraft.client.renderer.culling.Frustum;
 
 public class FrustumHelper {
     public static boolean isVisible(Frustum frustum, double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
-        float x1 = (float) (minX - frustum.camX);
-        float y1 = (float) (minY - frustum.camY);
-        float z1 = (float) (minZ - frustum.camZ);
-        float x2 = (float) (maxX - frustum.camX);
-        float y2 = (float) (maxY - frustum.camY);
-        float z2 = (float) (maxZ - frustum.camZ);
+        var x1 = (float) (minX - frustum.camX);
+        var y1 = (float) (minY - frustum.camY);
+        var z1 = (float) (minZ - frustum.camZ);
+        var x2 = (float) (maxX - frustum.camX);
+        var y2 = (float) (maxY - frustum.camY);
+        var z2 = (float) (maxZ - frustum.camZ);
         return isAnyCornerVisible(frustum, x1, y1, z1, x2, y2, z2);
     }
     
     private static boolean isAnyCornerVisible(Frustum frustum, float x1, float y1, float z1, float x2, float y2, float z2) {
-        Vector4f[] homogeneousCoordinates = frustum.frustumData;
-        for (Vector4f vector4f : homogeneousCoordinates) {
+        var homogeneousCoordinates = frustum.frustumData;
+        for (var vector4f : homogeneousCoordinates) {
             if (dotProduct(vector4f, x1, y1, z1, 1.0F) <= 0.0F && dotProduct(vector4f, x2, y1, z1, 1.0F) <= 0.0F && dotProduct(vector4f, x1, y2, z1, 1.0F) <= 0.0F && dotProduct(vector4f, x2, y2, z1, 1.0F) <= 0.0F && dotProduct(vector4f, x1, y1, z2, 1.0F) <= 0.0F && dotProduct(vector4f, x2, y1, z2, 1.0F) <= 0.0F && dotProduct(vector4f, x1, y2, z2, 1.0F) <= 0.0F && dotProduct(vector4f, x2, y2, z2, 1.0F) <= 0.0F) {
                 return false;
             }

+ 2 - 2
fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LOModMenuEntry.java

@@ -1,7 +1,7 @@
 package me.shedaniel.lightoverlay.fabric;
 
-import io.github.prospector.modmenu.api.ConfigScreenFactory;
-import io.github.prospector.modmenu.api.ModMenuApi;
+import com.terraformersmc.modmenu.api.ConfigScreenFactory;
+import com.terraformersmc.modmenu.api.ModMenuApi;
 import me.shedaniel.lightoverlay.common.ClothScreen;
 
 public class LOModMenuEntry implements ModMenuApi {

+ 2 - 11
fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LightOverlayImpl.java

@@ -1,22 +1,13 @@
 package me.shedaniel.lightoverlay.fabric;
 
-import com.mojang.blaze3d.vertex.PoseStack;
 import me.shedaniel.lightoverlay.common.LightOverlay;
 import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
-import net.minecraft.client.renderer.culling.Frustum;
-
-import java.util.function.Consumer;
 
 public class LightOverlayImpl {
-    public static Consumer<PoseStack> debugRenderer = poses -> {};
-    
     public static void init() {
         LightOverlay.register();
+        LightOverlay.renderer.frustumAccess = FrustumHelper::isVisible;
         WorldRenderEvents.AFTER_SETUP.register(context -> LightOverlay.renderer.frustum = context.frustum());
-        WorldRenderEvents.BEFORE_DEBUG_RENDER.register(context -> debugRenderer.accept(context.matrixStack()));
-    }
-    
-    public static boolean isFrustumVisible(Frustum frustum, double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
-        return FrustumHelper.isVisible(frustum, minX, minY, minZ, maxX, maxY, maxZ);
+        WorldRenderEvents.BEFORE_DEBUG_RENDER.register(context -> LightOverlay.renderer.accept(context.matrixStack()));
     }
 }

+ 2 - 2
fabric/src/main/java/me/shedaniel/lightoverlay/fabric/mixin/MixinClientConnection.java

@@ -29,7 +29,7 @@ public class MixinClientConnection {
             } else if (packet instanceof ClientboundSetChunkCacheCenterPacket p) {
                 var height = Mth.ceil(level.getHeight() / 32.0);
                 var start = Math.floorDiv(level.getMinBuildHeight(), 32);
-                for (int y = start; y < start + height; y++) {
+                for (var y = start; y < start + height; y++) {
                     LightOverlay.queueChunkAndNear(new CubicChunkPos(p.getX(), y, p.getZ()));
                 }
             } else if (packet instanceof ClientboundSectionBlocksUpdatePacket p) {
@@ -37,7 +37,7 @@ public class MixinClientConnection {
             } else if (packet instanceof ClientboundLightUpdatePacket p) {
                 var height = Mth.ceil(level.getHeight() / 32.0);
                 var start = Math.floorDiv(level.getMinBuildHeight(), 32);
-                for (int y = start; y < start + height; y++) {
+                for (var y = start; y < start + height; y++) {
                     LightOverlay.queueChunk(new CubicChunkPos(p.getX(), y, p.getZ()));
                 }
             }