Browse Source

Migrate to architectury fully

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 4 years ago
parent
commit
d9d31380a5
29 changed files with 464 additions and 501 deletions
  1. 26 36
      build.gradle
  2. 1 4
      common/build.gradle
  3. 0 18
      common/src/main/java/me/shedaniel/lightoverlay/common/AbstractPlatform.java
  4. 189 91
      common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlay.java
  5. 11 9
      fabric/build.gradle
  6. 15 15
      fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LOModMenuEntry.java
  7. 0 45
      fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LightOverlay.java
  8. 19 0
      fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LightOverlayImpl.java
  9. 5 5
      fabric/src/main/java/me/shedaniel/lightoverlay/fabric/mixin/MixinClientConnection.java
  10. 5 1
      fabric/src/main/resources/fabric.mod.json
  11. 1 2
      fabric/src/main/resources/lightoverlay.mixins.json
  12. 29 44
      forge/build.gradle
  13. 1 0
      forge/gradle.properties
  14. 4 4
      forge/src/main/java/me/shedaniel/lightoverlay/forge/FrustumHelper.java
  15. 3 8
      forge/src/main/java/me/shedaniel/lightoverlay/forge/LightOverlay.java
  16. 0 77
      forge/src/main/java/me/shedaniel/lightoverlay/forge/LightOverlayClient.java
  17. 23 23
      forge/src/main/java/me/shedaniel/lightoverlay/forge/LightOverlayCloth.java
  18. 29 0
      forge/src/main/java/me/shedaniel/lightoverlay/forge/LightOverlayImpl.java
  19. 31 0
      forge/src/main/java/me/shedaniel/lightoverlay/forge/mixin/MixinClientConnection.java
  20. 18 0
      forge/src/main/java/me/shedaniel/lightoverlay/forge/mixin/MixinDebugRenderer.java
  21. 4 4
      forge/src/main/java/me/shedaniel/lightoverlay/forge/mixin/MixinLevelRenderer.java
  22. 0 37
      forge/src/main/resources/META-INF/NetworkManager.js
  23. 0 43
      forge/src/main/resources/META-INF/WorldRenderer.js
  24. 0 4
      forge/src/main/resources/META-INF/coremods.json
  25. 23 16
      forge/src/main/resources/META-INF/mods.toml
  26. 15 0
      forge/src/main/resources/lightoverlay-forge.mixins.json
  27. 9 8
      gradle.properties
  28. 1 3
      merging.policy
  29. 2 4
      settings.gradle

+ 26 - 36
build.gradle

@@ -7,8 +7,6 @@ buildscript {
     }
     }
 }
 }
 
 
-import org.jetbrains.gradle.ext.ActionDelegationConfig
-
 import java.nio.file.FileVisitResult
 import java.nio.file.FileVisitResult
 import java.nio.file.Files
 import java.nio.file.Files
 import java.nio.file.Path
 import java.nio.file.Path
@@ -20,54 +18,44 @@ import java.util.zip.ZipInputStream
 import java.util.zip.ZipOutputStream
 import java.util.zip.ZipOutputStream
 
 
 plugins {
 plugins {
-    id "architect-plugin" version "1.0.10"
-    id "org.jetbrains.gradle.plugin.idea-ext" version "0.7"
+    id "architectury-plugin" version "1.3.39"
+    id "forgified-fabric-loom" version "0.5.16" apply false
 }
 }
 
 
 architect {
 architect {
     minecraft = minecraft_version
     minecraft = minecraft_version
 }
 }
 
 
+subprojects {
+    apply plugin: "forgified-fabric-loom"
+
+    loom {
+        silentMojangMappingsLicense()
+    }
+}
+
 allprojects {
 allprojects {
     apply plugin: "java"
     apply plugin: "java"
-    apply plugin: "architect-plugin"
+    apply plugin: "architectury-plugin"
 
 
     group "me.shedaniel"
     group "me.shedaniel"
     archivesBaseName = rootProject.name
     archivesBaseName = rootProject.name
     version = rootProject.mod_version
     version = rootProject.mod_version
-}
 
 
-idea.project.settings {
-    delegateActions {
-        delegateBuildRunToGradle = false
-        testRunner = ActionDelegationConfig.TestRunner.PLATFORM
-    }
-    runConfigurations {
-        "Fabric: Minecraft Client"(org.jetbrains.gradle.ext.Gradle) {
-            project = rootProject.project(":fabric")
-            taskNames = Collections.singletonList("runClient")
-        }
-        "Fabric: Minecraft Server"(org.jetbrains.gradle.ext.Gradle) {
-            project = rootProject.project(":fabric")
-            taskNames = Collections.singletonList("runServer")
-        }
-        "Forge: Minecraft Client"(org.jetbrains.gradle.ext.Gradle) {
-            project = rootProject.project(":forge")
-            taskNames = Collections.singletonList("runClient")
-        }
-        "Forge: Minecraft Server"(org.jetbrains.gradle.ext.Gradle) {
-            project = rootProject.project(":forge")
-            taskNames = Collections.singletonList("runServer")
-        }
+    tasks.withType(JavaCompile) {
+        options.encoding = "UTF-8"
     }
     }
 }
 }
 
 
 task buildMerged {
 task buildMerged {
+    allprojects {
+        dependsOn it.tasks.getByName("build")
+    }
     doLast {
     doLast {
         def folder = file(".gradle/.mergemods")
         def folder = file(".gradle/.mergemods")
         folder.mkdirs()
         folder.mkdirs()
-        def fabricJar = file("fabric/build/libs/${rootProject.name}-${rootProject.mod_version}.jar")
-        def forgeJar = file("forge/build/libs/${rootProject.name}-${rootProject.mod_version}.jar")
+        def fabricJar = file("fabric/build/libs/${rootProject.name}-${rootProject.mod_version}-fabric.jar")
+        def forgeJar = file("forge/build/libs/${rootProject.name}-${rootProject.mod_version}-forge.jar")
         def fabricFolder = new File(folder, ".tempFabric")
         def fabricFolder = new File(folder, ".tempFabric")
         def forgeFolder = new File(folder, ".tempForge")
         def forgeFolder = new File(folder, ".tempForge")
         def mergeFolder = new File(folder, ".tempMerge")
         def mergeFolder = new File(folder, ".tempMerge")
@@ -99,13 +87,15 @@ task buildMerged {
                             if (outFile.exists()) {
                             if (outFile.exists()) {
                                 def env = useFolder.getName().substring(5)
                                 def env = useFolder.getName().substring(5)
                                 def fileName = outFile.getAbsolutePath().replace(mergeFolder.getAbsolutePath(), "")
                                 def fileName = outFile.getAbsolutePath().replace(mergeFolder.getAbsolutePath(), "")
-                                def policyEnv = policyMap.get(fileName)
-                                if (policyEnv == null) {
-                                    throw new IllegalStateException("Unhandled duplicate file: $fileName")
+                                if (!ogFile.isFile() || !outFile.isFile() || !Arrays.equals(ogFile.readBytes(), outFile.readBytes())) {
+                                    def policyEnv = policyMap.get(fileName)
+                                    if (policyEnv == null) {
+                                        throw new IllegalStateException("Unhandled duplicate file: $fileName")
+                                    }
+                                    println "Chose env ${policyEnv.toUpperCase(Locale.ROOT)} for duplicate file: $fileName"
+                                    if (policyEnv != env)
+                                        return FileVisitResult.CONTINUE
                                 }
                                 }
-                                println "Chose env ${policyEnv.toUpperCase(Locale.ROOT)} for duplicate file: $fileName"
-                                if (policyEnv != env)
-                                    return FileVisitResult.CONTINUE
                             }
                             }
                             if (!ogFile.isDirectory()) {
                             if (!ogFile.isDirectory()) {
                                 org.apache.commons.io.FileUtils.copyFile(ogFile, outFile)
                                 org.apache.commons.io.FileUtils.copyFile(ogFile, outFile)

+ 1 - 4
common/build.gradle

@@ -1,10 +1,7 @@
-plugins {
-    id "fabric-loom"
-}
-
 dependencies {
 dependencies {
     minecraft "com.mojang:minecraft:${rootProject.architect.minecraft}"
     minecraft "com.mojang:minecraft:${rootProject.architect.minecraft}"
     mappings minecraft.officialMojangMappings()
     mappings minecraft.officialMojangMappings()
+    modCompile "me.shedaniel:architectury:${rootProject.architectury_version}"
     modCompile "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
     modCompile "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
 }
 }
 
 

+ 0 - 18
common/src/main/java/me/shedaniel/lightoverlay/common/AbstractPlatform.java

@@ -1,18 +0,0 @@
-package me.shedaniel.lightoverlay.common;
-
-import net.minecraft.client.KeyMapping;
-import net.minecraft.client.renderer.culling.Frustum;
-
-import java.nio.file.Path;
-
-public interface AbstractPlatform {
-    Path getConfigDir();
-    
-    void registerClientTick(Runnable runnable);
-    
-    void registerDebugRenderer(Runnable runnable);
-    
-    KeyMapping registerKeyBinding(KeyMapping keyMapping);
-    
-    boolean isFrustumVisible(Frustum frustum, double minX, double minY, double minZ, double maxX, double maxY, double maxZ);
-}

+ 189 - 91
common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayCore.java → common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlay.java

@@ -1,6 +1,5 @@
 package me.shedaniel.lightoverlay.common;
 package me.shedaniel.lightoverlay.common;
 
 
-import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Maps;
 import com.mojang.blaze3d.platform.GlStateManager;
 import com.mojang.blaze3d.platform.GlStateManager;
 import com.mojang.blaze3d.platform.InputConstants;
 import com.mojang.blaze3d.platform.InputConstants;
@@ -9,6 +8,10 @@ import com.mojang.blaze3d.vertex.Tesselator;
 import com.mojang.math.Transformation;
 import com.mojang.math.Transformation;
 import it.unimi.dsi.fastutil.longs.Long2ReferenceMap;
 import it.unimi.dsi.fastutil.longs.Long2ReferenceMap;
 import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
 import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
+import me.shedaniel.architectury.event.events.GuiEvent;
+import me.shedaniel.architectury.event.events.client.ClientTickEvent;
+import me.shedaniel.architectury.platform.Platform;
+import me.shedaniel.architectury.registry.KeyBindings;
 import net.minecraft.client.Camera;
 import net.minecraft.client.Camera;
 import net.minecraft.client.KeyMapping;
 import net.minecraft.client.KeyMapping;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.Minecraft;
@@ -44,15 +47,15 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 import java.text.DecimalFormat;
 import java.text.DecimalFormat;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
+import java.util.*;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.ThreadPoolExecutor;
 
 
-public class LightOverlayCore {
+public class LightOverlay {
     public static final DecimalFormat FORMAT = new DecimalFormat("#.#");
     public static final DecimalFormat FORMAT = new DecimalFormat("#.#");
     private static final String KEYBIND_CATEGORY = "key.lightoverlay.category";
     private static final String KEYBIND_CATEGORY = "key.lightoverlay.category";
     private static final ResourceLocation ENABLE_OVERLAY_KEYBIND = new ResourceLocation("lightoverlay", "enable_overlay");
     private static final ResourceLocation ENABLE_OVERLAY_KEYBIND = new ResourceLocation("lightoverlay", "enable_overlay");
@@ -79,19 +82,21 @@ public class LightOverlayCore {
         thread.setDaemon(true);
         thread.setDaemon(true);
         return thread;
         return thread;
     });
     });
-    private static final List<ChunkPos> POS = Lists.newCopyOnWriteArrayList();
+    private static final Set<ChunkPos> POS = Collections.synchronizedSet(new HashSet<>());
+    private static final Set<ChunkPos> CALCULATING_POS = Collections.synchronizedSet(new HashSet<>());
     private static final Map<ChunkPos, Long2ReferenceMap<Object>> CHUNK_MAP = Maps.newConcurrentMap();
     private static final Map<ChunkPos, Long2ReferenceMap<Object>> CHUNK_MAP = Maps.newConcurrentMap();
     private static final Minecraft CLIENT = Minecraft.getInstance();
     private static final Minecraft CLIENT = Minecraft.getInstance();
     private static long ticks = 0;
     private static long ticks = 0;
     
     
-    public static void register(AbstractPlatform platform) {
+    public static void register() {
         // Load Config
         // Load Config
-        configFile = new File(platform.getConfigDir().toFile(), "lightoverlay.properties");
+        configFile = new File(Platform.getConfigFolder().toFile(), "lightoverlay.properties");
         loadConfig(configFile);
         loadConfig(configFile);
         
         
-        enableOverlay = platform.registerKeyBinding(createKeyBinding(ENABLE_OVERLAY_KEYBIND, InputConstants.Type.KEYSYM, 296, KEYBIND_CATEGORY));
+        enableOverlay = createKeyBinding(ENABLE_OVERLAY_KEYBIND, InputConstants.Type.KEYSYM, 296, KEYBIND_CATEGORY);
+        KeyBindings.registerKeyBinding(enableOverlay);
         
         
-        platform.registerDebugRenderer(() -> {
+        registerDebugRenderer(() -> {
             if (enabled) {
             if (enabled) {
                 LocalPlayer playerEntity = CLIENT.player;
                 LocalPlayer playerEntity = CLIENT.player;
                 int playerPosX = ((int) playerEntity.getX()) >> 4;
                 int playerPosX = ((int) playerEntity.getX()) >> 4;
@@ -114,7 +119,7 @@ public class LightOverlayCore {
                             if (objectEntry.getValue() instanceof Byte) {
                             if (objectEntry.getValue() instanceof Byte) {
                                 mutable.set(BlockPos.getX(objectEntry.getLongKey()), BlockPos.getY(objectEntry.getLongKey()), BlockPos.getZ(objectEntry.getLongKey()));
                                 mutable.set(BlockPos.getX(objectEntry.getLongKey()), BlockPos.getY(objectEntry.getLongKey()), BlockPos.getZ(objectEntry.getLongKey()));
                                 if (mutable.closerThan(playerPos, reach)) {
                                 if (mutable.closerThan(playerPos, reach)) {
-                                    if (frustum == null || platform.isFrustumVisible(frustum, mutable.getX(), mutable.getY(), mutable.getZ(), mutable.getX() + 1, mutable.getX() + 1, mutable.getX() + 1)) {
+                                    if (frustum == null || isFrustumVisible(frustum, mutable.getX(), mutable.getY(), mutable.getZ(), mutable.getX() + 1, mutable.getX() + 1, mutable.getX() + 1)) {
                                         downMutable.set(mutable.getX(), mutable.getY() - 1, mutable.getZ());
                                         downMutable.set(mutable.getX(), mutable.getY() - 1, mutable.getZ());
                                         renderLevel(CLIENT, camera, world, mutable, downMutable, (Byte) objectEntry.getValue(), collisionContext);
                                         renderLevel(CLIENT, camera, world, mutable, downMutable, (Byte) objectEntry.getValue(), collisionContext);
                                     }
                                     }
@@ -140,7 +145,7 @@ public class LightOverlayCore {
                             if (objectEntry.getValue() instanceof CrossType) {
                             if (objectEntry.getValue() instanceof CrossType) {
                                 mutable.set(BlockPos.getX(objectEntry.getLongKey()), BlockPos.getY(objectEntry.getLongKey()), BlockPos.getZ(objectEntry.getLongKey()));
                                 mutable.set(BlockPos.getX(objectEntry.getLongKey()), BlockPos.getY(objectEntry.getLongKey()), BlockPos.getZ(objectEntry.getLongKey()));
                                 if (mutable.closerThan(playerPos, reach)) {
                                 if (mutable.closerThan(playerPos, reach)) {
-                                    if (frustum == null || platform.isFrustumVisible(frustum, mutable.getX(), mutable.getY(), mutable.getZ(), mutable.getX() + 1, mutable.getX() + 1, mutable.getX() + 1)) {
+                                    if (frustum == null || isFrustumVisible(frustum, mutable.getX(), mutable.getY(), mutable.getZ(), mutable.getX() + 1, mutable.getX() + 1, mutable.getX() + 1)) {
                                         int color = objectEntry.getValue() == CrossType.RED ? redColor : objectEntry.getValue() == CrossType.YELLOW ? yellowColor : secondaryColor;
                                         int color = objectEntry.getValue() == CrossType.RED ? redColor : objectEntry.getValue() == CrossType.YELLOW ? yellowColor : secondaryColor;
                                         renderCross(camera, world, mutable, color, collisionContext);
                                         renderCross(camera, world, mutable, color, collisionContext);
                                     }
                                     }
@@ -155,85 +160,31 @@ public class LightOverlayCore {
                 }
                 }
             }
             }
         });
         });
-        
-        platform.registerClientTick(() -> {
-            while (enableOverlay.consumeClick())
-                enabled = !enabled;
-            
-            try {
-                ticks++;
-                if (CLIENT.player == null || !enabled) {
-                    POS.clear();
-                    CHUNK_MAP.clear();
+    
+        GuiEvent.DEBUG_TEXT_LEFT.register(list -> {
+            if (enabled) {
+                if (caching) {
+                    list.add(String.format("[Light Overlay] Chunks to queue: %02d", POS.size()));
                 } else {
                 } else {
-                    LocalPlayer player = CLIENT.player;
-                    ClientLevel world = CLIENT.level;
-                    CollisionContext collisionContext = CollisionContext.of(player);
-                    
-                    if (!caching) {
-                        POS.clear();
-                        CHUNK_MAP.clear();
-                        BlockPos playerPos = player.blockPosition();
-                        LayerLightEventListener block = world.getLightEngine().getLayerListener(LightLayer.BLOCK);
-                        LayerLightEventListener sky = showNumber ? null : world.getLightEngine().getLayerListener(LightLayer.SKY);
-                        BlockPos.MutableBlockPos downPos = new BlockPos.MutableBlockPos();
-                        Iterable<BlockPos> iterate = BlockPos.betweenClosed(playerPos.getX() - reach, playerPos.getY() - reach, playerPos.getZ() - reach,
-                                playerPos.getX() + reach, playerPos.getY() + reach, playerPos.getZ() + reach);
-                        Long2ReferenceMap<Object> map = new Long2ReferenceOpenHashMap<>();
-                        CHUNK_MAP.put(new ChunkPos(0, 0), map);
-                        for (BlockPos blockPos : iterate) {
-                            downPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ());
-                            if (showNumber) {
-                                int level = getCrossLevel(blockPos, downPos, world, block, collisionContext);
-                                if (level >= 0) {
-                                    map.put(blockPos.asLong(), Byte.valueOf((byte) level));
-                                }
-                            } else {
-                                CrossType type = getCrossType(blockPos, downPos, world, block, sky, collisionContext);
-                                if (type != CrossType.NONE) {
-                                    map.put(blockPos.asLong(), type);
-                                }
-                            }
-                        }
-                    } else {
-                        int playerPosX = ((int) player.getX()) >> 4;
-                        int playerPosZ = ((int) player.getZ()) >> 4;
-                        if (ticks % 20 == 0) {
-                            for (int chunkX = playerPosX - getChunkRange(); chunkX <= playerPosX + getChunkRange(); chunkX++) {
-                                for (int chunkZ = playerPosZ - getChunkRange(); chunkZ <= playerPosZ + getChunkRange(); chunkZ++) {
-                                    ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
-                                    if (!CHUNK_MAP.containsKey(chunkPos))
-                                        queueChunk(chunkPos);
-                                }
-                            }
-                        }
-                        POS.removeIf(pos -> Mth.abs(pos.x - playerPosX) > getChunkRange() || Mth.abs(pos.z - playerPosZ) > getChunkRange());
-                        for (int k = 0; k < 2; k++) {
-                            if (!POS.isEmpty()) {
-                                ChunkPos pos = POS.stream().min(Comparator.comparingDouble(value -> {
-                                    int i = Math.abs(value.x - playerPosX);
-                                    int j = Math.abs(value.z - playerPosZ);
-                                    return i * i + j * j;
-                                })).get();
-                                POS.remove(pos);
-                                EXECUTOR.submit(() -> {
-                                    try {
-                                        calculateChunk(world.getChunkSource().getChunk(pos.x, pos.z, ChunkStatus.FULL, false), world, pos, collisionContext);
-                                    } catch (Throwable throwable) {
-                                        LogManager.getLogger().throwing(throwable);
-                                    }
-                                });
-                            }
-                        }
-                        if (ticks % 50 == 0) {
-                            CHUNK_MAP.entrySet().removeIf(pos -> Mth.abs(pos.getKey().x - playerPosX) > getChunkRange() * 2 || Mth.abs(pos.getKey().z - playerPosZ) > getChunkRange() * 2);
-                        }
-                    }
+                    list.add("[Light Overlay] Enabled");
                 }
                 }
-            } catch (Throwable throwable) {
-                LogManager.getLogger().throwing(throwable);
+            }else {
+                list.add("[Light Overlay] Disabled");
             }
             }
         });
         });
+        ClientTickEvent.CLIENT_POST.register(LightOverlay::tick);
+    }
+    
+    private static void processChunk(ChunkPos pos, int playerPosX, int playerPosZ, CollisionContext context) {
+        CALCULATING_POS.remove(pos);
+        if (Mth.abs(pos.x - playerPosX) > getChunkRange() || Mth.abs(pos.z - playerPosZ) > getChunkRange() || POS.contains(pos)) {
+            return;
+        }
+        try {
+            calculateChunk(CLIENT.level.getChunkSource().getChunk(pos.x, pos.z, ChunkStatus.FULL, false), CLIENT.level, pos, context);
+        } catch (Throwable throwable) {
+            LogManager.getLogger().throwing(throwable);
+        }
     }
     }
     
     
     public static void queueChunkAndNear(ChunkPos pos) {
     public static void queueChunkAndNear(ChunkPos pos) {
@@ -245,9 +196,9 @@ public class LightOverlayCore {
     }
     }
     
     
     public static void queueChunk(ChunkPos pos) {
     public static void queueChunk(ChunkPos pos) {
-        if (caching)
-            if (!POS.contains(pos))
-                POS.add(0, pos);
+        if (enabled && caching && !CALCULATING_POS.contains(pos)) {
+            POS.add(pos);
+        }
     }
     }
     
     
     public static int getChunkRange() {
     public static int getChunkRange() {
@@ -480,6 +431,153 @@ public class LightOverlayCore {
         return new KeyMapping("key." + id.getNamespace() + "." + id.getPath(), type, code, category);
         return new KeyMapping("key." + id.getNamespace() + "." + id.getPath(), type, code, category);
     }
     }
     
     
+    private static final LazyLoadedValue<MethodHandle> IS_FRUSTUM_VISIBLE = new LazyLoadedValue<>(() -> {
+        try {
+            return MethodHandles.lookup().findStatic(Class.forName("me.shedaniel.lightoverlay." + Platform.getModLoader() + ".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);
+        }
+    });
+    
+    private static boolean isFrustumVisible(Frustum frustum, double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
+        try {
+            return (boolean) IS_FRUSTUM_VISIBLE.get().invokeExact(frustum, minX, minY, minZ, maxX, maxY, maxZ);
+        } catch (Throwable throwable) {
+            throw new RuntimeException(throwable);
+        }
+    }
+    
+    private static void registerDebugRenderer(Runnable runnable) {
+        try {
+            Class.forName("me.shedaniel.lightoverlay." + Platform.getModLoader() + ".LightOverlayImpl").getDeclaredField("debugRenderer").set(null, runnable);
+        } catch (Throwable throwable) {
+            throw new RuntimeException(throwable);
+        }
+    }
+    
+    private static void tick(Minecraft minecraft) {
+        while (enableOverlay.consumeClick())
+            enabled = !enabled;
+    
+        try {
+            ticks++;
+            if (CLIENT.player == null || !enabled) {
+                POS.clear();
+                CALCULATING_POS.clear();
+                EXECUTOR.getQueue().clear();
+                CHUNK_MAP.clear();
+            } else {
+                LocalPlayer player = CLIENT.player;
+                ClientLevel world = CLIENT.level;
+                CollisionContext collisionContext = CollisionContext.of(player);
+            
+                if (!caching) {
+                    CALCULATING_POS.clear();
+                    POS.clear();
+                    CHUNK_MAP.clear();
+                    BlockPos playerPos = player.blockPosition();
+                    LayerLightEventListener block = world.getLightEngine().getLayerListener(LightLayer.BLOCK);
+                    LayerLightEventListener sky = showNumber ? null : world.getLightEngine().getLayerListener(LightLayer.SKY);
+                    BlockPos.MutableBlockPos downPos = new BlockPos.MutableBlockPos();
+                    Iterable<BlockPos> iterate = BlockPos.betweenClosed(playerPos.getX() - reach, playerPos.getY() - reach, playerPos.getZ() - reach,
+                            playerPos.getX() + reach, playerPos.getY() + reach, playerPos.getZ() + reach);
+                    Long2ReferenceMap<Object> map = new Long2ReferenceOpenHashMap<>();
+                    CHUNK_MAP.put(new ChunkPos(0, 0), map);
+                    for (BlockPos blockPos : iterate) {
+                        downPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ());
+                        if (showNumber) {
+                            int level = getCrossLevel(blockPos, downPos, world, block, collisionContext);
+                            if (level >= 0) {
+                                map.put(blockPos.asLong(), Byte.valueOf((byte) level));
+                            }
+                        } else {
+                            CrossType type = getCrossType(blockPos, downPos, world, block, sky, collisionContext);
+                            if (type != CrossType.NONE) {
+                                map.put(blockPos.asLong(), type);
+                            }
+                        }
+                    }
+                } else {
+                    int playerPosX = ((int) player.getX()) >> 4;
+                    int playerPosZ = ((int) player.getZ()) >> 4;
+                    for (int chunkX = playerPosX - getChunkRange(); chunkX <= playerPosX + getChunkRange(); chunkX++) {
+                        for (int chunkZ = playerPosZ - getChunkRange(); chunkZ <= playerPosZ + getChunkRange(); chunkZ++) {
+                            if (Mth.abs(chunkX - playerPosX) > getChunkRange() || Mth.abs(chunkZ - playerPosZ) > getChunkRange())
+                                continue;
+                            ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
+                            if (!CHUNK_MAP.containsKey(chunkPos))
+                                queueChunk(chunkPos);
+                        }
+                    }
+                    for (int 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;
+                        ChunkPos c1 = null, c2 = null, c3 = null;
+                        synchronized (POS) {
+                            Iterator<ChunkPos> iterator = POS.iterator();
+                            while (iterator.hasNext()) {
+                                ChunkPos pos = iterator.next();
+                                if (Mth.abs(pos.x - playerPosX) > getChunkRange() || Mth.abs(pos.z - playerPosZ) > getChunkRange() || CALCULATING_POS.contains(pos)) {
+                                    iterator.remove();
+                                } else {
+                                    if (isFrustumVisible(frustum, pos.getMinBlockX(), 0, pos.getMinBlockZ(), pos.getMaxBlockX(), 256, pos.getMaxBlockZ())) {
+                                        int i = Math.abs(pos.x - playerPosX);
+                                        int j = Math.abs(pos.z - playerPosZ);
+                                        double distance = Math.sqrt(i * i + j * j);
+                                        if (distance < d1) {
+                                            d3 = d2;
+                                            d2 = d1;
+                                            d1 = distance;
+                                            c3 = c2;
+                                            c2 = c1;
+                                            c1 = pos;
+                                            iterator.remove();
+                                        } else if (distance < d2) {
+                                            d3 = d2;
+                                            d2 = distance;
+                                            c3 = c2;
+                                            c2 = pos;
+                                            iterator.remove();
+                                        } else if (distance < d3) {
+                                            d3 = distance;
+                                            c3 = pos;
+                                            iterator.remove();
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        ChunkPos finalC1 = c1;
+                        ChunkPos finalC2 = c2;
+                        ChunkPos finalC3 = c3;
+                        if (finalC1 != null) {
+                            CALCULATING_POS.add(finalC1);
+                            if (finalC2 != null) {
+                                CALCULATING_POS.add(finalC2);
+                                if (finalC3 != null) {
+                                    CALCULATING_POS.add(finalC3);
+                                }
+                            }
+                            EXECUTOR.submit(() -> {
+                                int playerPosX1 = ((int) CLIENT.player.getX()) >> 4;
+                                int playerPosZ1 = ((int) CLIENT.player.getZ()) >> 4;
+                                if (finalC1 != null) processChunk(finalC1, playerPosX1, playerPosZ1, collisionContext);
+                                if (finalC2 != null) processChunk(finalC2, playerPosX1, playerPosZ1, collisionContext);
+                                if (finalC3 != null) processChunk(finalC3, playerPosX1, playerPosZ1, collisionContext);
+                            });
+                        }
+                    }
+                    if (ticks % 50 == 0) {
+                        CHUNK_MAP.entrySet().removeIf(pos -> Mth.abs(pos.getKey().x - playerPosX) > getChunkRange() * 2 || Mth.abs(pos.getKey().z - playerPosZ) > getChunkRange() * 2);
+                    }
+                }
+            }
+        } catch (Throwable throwable) {
+            LogManager.getLogger().throwing(throwable);
+        }
+    }
+    
     private enum CrossType {
     private enum CrossType {
         YELLOW,
         YELLOW,
         RED,
         RED,

+ 11 - 9
fabric/build.gradle

@@ -1,5 +1,4 @@
 plugins {
 plugins {
-    id "fabric-loom"
     id "com.github.johnrengelman.shadow" version "5.0.0"
     id "com.github.johnrengelman.shadow" version "5.0.0"
 }
 }
 
 
@@ -7,6 +6,10 @@ minecraft {
     accessWidener = file("src/main/resources/lightoverlay.accesswidener")
     accessWidener = file("src/main/resources/lightoverlay.accesswidener")
 }
 }
 
 
+architectury {
+    platformSetupLoomIde()
+}
+
 processResources {
 processResources {
     filesMatching("fabric.mod.json") {
     filesMatching("fabric.mod.json") {
         expand "version": project.version
         expand "version": project.version
@@ -24,26 +27,24 @@ dependencies {
     modCompile "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
     modCompile "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
 
 
     modCompile "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
     modCompile "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
-    modCompile("me.shedaniel.cloth.api:cloth-client-events-v0:${rootProject.cloth_version}") {
-        transitive = false
-    }
     modImplementation("me.shedaniel.cloth:config-2:${rootProject.cloth_config_version}") {
     modImplementation("me.shedaniel.cloth:config-2:${rootProject.cloth_config_version}") {
         exclude(group: "net.fabricmc.fabric-api")
         exclude(group: "net.fabricmc.fabric-api")
     }
     }
     modImplementation("io.github.prospector:modmenu:${rootProject.modmenu_version}") {
     modImplementation("io.github.prospector:modmenu:${rootProject.modmenu_version}") {
         transitive = false
         transitive = false
     }
     }
-    include("me.shedaniel.cloth.api:cloth-client-events-v0:${rootProject.cloth_version}") {
-        transitive = false
-    }
     include("me.shedaniel.cloth:config-2:${rootProject.cloth_config_version}") {
     include("me.shedaniel.cloth:config-2:${rootProject.cloth_config_version}") {
         transitive = false
         transitive = false
     }
     }
+    modCompile("me.shedaniel:architectury:${rootProject.architectury_version}:fabric")
 
 
-    compile(project(":common")) {
+    compileOnly(project(path: ":common")) {
+        transitive = false
+    }
+    runtimeOnly(project(path: ":common", configuration: "transformedRuntime")) {
         transitive = false
         transitive = false
     }
     }
-    shadow(project(":common")) {
+    shadow(project(path: ":common", configuration: "transformed")) {
         transitive = false
         transitive = false
     }
     }
 }
 }
@@ -58,4 +59,5 @@ shadowJar {
 remapJar {
 remapJar {
     dependsOn(shadowJar)
     dependsOn(shadowJar)
     input.set(shadowJar.archivePath)
     input.set(shadowJar.archivePath)
+    archiveClassifier = "fabric"
 }
 }

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

@@ -6,7 +6,7 @@ import me.shedaniel.clothconfig2.api.ConfigBuilder;
 import me.shedaniel.clothconfig2.api.ConfigCategory;
 import me.shedaniel.clothconfig2.api.ConfigCategory;
 import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
 import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
 import me.shedaniel.clothconfig2.gui.entries.IntegerSliderEntry;
 import me.shedaniel.clothconfig2.gui.entries.IntegerSliderEntry;
-import me.shedaniel.lightoverlay.common.LightOverlayCore;
+import me.shedaniel.lightoverlay.common.LightOverlay;
 import net.minecraft.client.gui.screens.Screen;
 import net.minecraft.client.gui.screens.Screen;
 import net.minecraft.client.resources.language.I18n;
 import net.minecraft.client.resources.language.I18n;
 import net.minecraft.network.chat.Component;
 import net.minecraft.network.chat.Component;
@@ -28,31 +28,31 @@ public class LOModMenuEntry implements ModMenuApi {
         ConfigEntryBuilder eb = builder.entryBuilder();
         ConfigEntryBuilder eb = builder.entryBuilder();
         ConfigCategory general = builder.getOrCreateCategory(new TranslatableComponent("config.lightoverlay.general"));
         ConfigCategory general = builder.getOrCreateCategory(new TranslatableComponent("config.lightoverlay.general"));
         general.addEntry(eb.startTextDescription(Component.nullToEmpty("§7" + I18n.get("description.lightoverlay.caching"))).build());
         general.addEntry(eb.startTextDescription(Component.nullToEmpty("§7" + I18n.get("description.lightoverlay.caching"))).build());
-        general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.caching"), LightOverlayCore.caching).setDefaultValue(false).setSaveConsumer(bool -> LightOverlayCore.caching = bool).build());
-        general.addEntry(eb.startIntSlider(new TranslatableComponent("config.lightoverlay.reach"), LightOverlayCore.reach, 1, 64).setDefaultValue(12).setTextGetter(integer -> Component.nullToEmpty("Reach: " + integer + " Blocks")).setSaveConsumer(integer -> LightOverlayCore.reach = integer).build());
-        IntegerSliderEntry crossLevel = eb.startIntSlider(new TranslatableComponent("config.lightoverlay.crossLevel"), LightOverlayCore.crossLevel, 0, 15).setDefaultValue(7).setTextGetter(integer -> Component.nullToEmpty("Cross Level: " + integer)).setSaveConsumer(integer -> LightOverlayCore.crossLevel = integer).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();
         general.addEntry(crossLevel);
         general.addEntry(crossLevel);
-        general.addEntry(eb.startIntSlider(new TranslatableComponent("config.lightoverlay.secondaryLevel"), LightOverlayCore.secondaryLevel, -1, 15)
+        general.addEntry(eb.startIntSlider(new TranslatableComponent("config.lightoverlay.secondaryLevel"), LightOverlay.secondaryLevel, -1, 15)
                 .setErrorSupplier(integer -> {
                 .setErrorSupplier(integer -> {
                     if (integer >= 0 && integer >= crossLevel.getValue())
                     if (integer >= 0 && integer >= crossLevel.getValue())
                         return Optional.of(new TextComponent("Secondary Level cannot be higher than Cross Level!"));
                         return Optional.of(new TextComponent("Secondary Level cannot be higher than Cross Level!"));
                     return Optional.empty();
                     return Optional.empty();
-                }).setDefaultValue(-1).setTextGetter(integer -> new TextComponent(integer < 0 ? "Off" : "Level: " + integer)).setSaveConsumer(integer -> LightOverlayCore.secondaryLevel = integer).build());
-        general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.showNumber"), LightOverlayCore.showNumber).setDefaultValue(false).setSaveConsumer(bool -> LightOverlayCore.showNumber = bool).build());
-        general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.smoothLines"), LightOverlayCore.smoothLines).setDefaultValue(true).setSaveConsumer(bool -> LightOverlayCore.smoothLines = bool).build());
-        general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.underwater"), LightOverlayCore.underwater).setDefaultValue(false).setSaveConsumer(bool -> LightOverlayCore.underwater = bool).build());
-        general.addEntry(eb.startIntSlider(new TranslatableComponent("config.lightoverlay.lineWidth"), Mth.floor(LightOverlayCore.lineWidth * 100), 100, 700).setDefaultValue(100).setTextGetter(integer -> new TextComponent("Light Width: " + LightOverlayCore.FORMAT.format(integer / 100d))).setSaveConsumer(integer -> LightOverlayCore.lineWidth = integer / 100f).build());
-        general.addEntry(eb.startColorField(new TranslatableComponent("config.lightoverlay.yellowColor"), LightOverlayCore.yellowColor).setDefaultValue(0xFFFF00).setSaveConsumer(color -> LightOverlayCore.yellowColor = color).build());
-        general.addEntry(eb.startColorField(new TranslatableComponent("config.lightoverlay.redColor"), LightOverlayCore.redColor).setDefaultValue(0xFF0000).setSaveConsumer(color -> LightOverlayCore.redColor = color).build());
-        general.addEntry(eb.startColorField(new TranslatableComponent("config.lightoverlay.secondaryColor"), LightOverlayCore.secondaryColor).setDefaultValue(0x0000FF).setSaveConsumer(color -> LightOverlayCore.secondaryColor = color).build());
+                }).setDefaultValue(-1).setTextGetter(integer -> new TextComponent(integer < 0 ? "Off" : "Level: " + integer)).setSaveConsumer(integer -> LightOverlay.secondaryLevel = integer).build());
+        general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.showNumber"), LightOverlay.showNumber).setDefaultValue(false).setSaveConsumer(bool -> LightOverlay.showNumber = bool).build());
+        general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.smoothLines"), LightOverlay.smoothLines).setDefaultValue(true).setSaveConsumer(bool -> LightOverlay.smoothLines = bool).build());
+        general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.underwater"), LightOverlay.underwater).setDefaultValue(false).setSaveConsumer(bool -> LightOverlay.underwater = bool).build());
+        general.addEntry(eb.startIntSlider(new TranslatableComponent("config.lightoverlay.lineWidth"), Mth.floor(LightOverlay.lineWidth * 100), 100, 700).setDefaultValue(100).setTextGetter(integer -> new TextComponent("Light Width: " + LightOverlay.FORMAT.format(integer / 100d))).setSaveConsumer(integer -> LightOverlay.lineWidth = integer / 100f).build());
+        general.addEntry(eb.startColorField(new TranslatableComponent("config.lightoverlay.yellowColor"), LightOverlay.yellowColor).setDefaultValue(0xFFFF00).setSaveConsumer(color -> LightOverlay.yellowColor = color).build());
+        general.addEntry(eb.startColorField(new TranslatableComponent("config.lightoverlay.redColor"), LightOverlay.redColor).setDefaultValue(0xFF0000).setSaveConsumer(color -> LightOverlay.redColor = color).build());
+        general.addEntry(eb.startColorField(new TranslatableComponent("config.lightoverlay.secondaryColor"), LightOverlay.secondaryColor).setDefaultValue(0x0000FF).setSaveConsumer(color -> LightOverlay.secondaryColor = color).build());
         
         
         return builder.setSavingRunnable(() -> {
         return builder.setSavingRunnable(() -> {
             try {
             try {
-                LightOverlayCore.saveConfig(LightOverlayCore.configFile);
+                LightOverlay.saveConfig(LightOverlay.configFile);
             } catch (Exception e) {
             } catch (Exception e) {
                 e.printStackTrace();
                 e.printStackTrace();
             }
             }
-            LightOverlayCore.loadConfig(LightOverlayCore.configFile);
+            LightOverlay.loadConfig(LightOverlay.configFile);
         }).build();
         }).build();
     }
     }
 }
 }

+ 0 - 45
fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LightOverlay.java

@@ -1,45 +0,0 @@
-package me.shedaniel.lightoverlay.fabric;
-
-import me.shedaniel.cloth.api.client.events.v0.ClothClientHooks;
-import me.shedaniel.lightoverlay.common.AbstractPlatform;
-import me.shedaniel.lightoverlay.common.LightOverlayCore;
-import net.fabricmc.api.ClientModInitializer;
-import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
-import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
-import net.fabricmc.loader.api.FabricLoader;
-import net.minecraft.client.KeyMapping;
-import net.minecraft.client.renderer.culling.Frustum;
-
-import java.nio.file.Path;
-
-public class LightOverlay implements ClientModInitializer, AbstractPlatform {
-    @Override
-    public void onInitializeClient() {
-        LightOverlayCore.register(this);
-    }
-    
-    @Override
-    public Path getConfigDir() {
-        return FabricLoader.getInstance().getConfigDir();
-    }
-    
-    @Override
-    public void registerClientTick(Runnable runnable) {
-        ClientTickEvents.END_CLIENT_TICK.register(minecraft -> runnable.run());
-    }
-    
-    @Override
-    public void registerDebugRenderer(Runnable runnable) {
-        ClothClientHooks.DEBUG_RENDER_PRE.register(runnable);
-    }
-    
-    @Override
-    public KeyMapping registerKeyBinding(KeyMapping keyMapping) {
-        return KeyBindingHelper.registerKeyBinding(keyMapping);
-    }
-    
-    @Override
-    public 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);
-    }
-}

+ 19 - 0
fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LightOverlayImpl.java

@@ -0,0 +1,19 @@
+package me.shedaniel.lightoverlay.fabric;
+
+import me.shedaniel.lightoverlay.common.LightOverlay;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
+import net.minecraft.client.renderer.culling.Frustum;
+
+public class LightOverlayImpl {
+    public static Runnable debugRenderer = () -> {};
+    
+    public static void init() {
+        LightOverlay.register();
+        WorldRenderEvents.AFTER_SETUP.register(context -> LightOverlay.frustum = context.frustum());
+        WorldRenderEvents.BEFORE_DEBUG_RENDER.register(context -> debugRenderer.run());
+    }
+    
+    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);
+    }
+}

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

@@ -1,6 +1,6 @@
 package me.shedaniel.lightoverlay.fabric.mixin;
 package me.shedaniel.lightoverlay.fabric.mixin;
 
 
-import me.shedaniel.lightoverlay.common.LightOverlayCore;
+import me.shedaniel.lightoverlay.common.LightOverlay;
 import net.minecraft.network.Connection;
 import net.minecraft.network.Connection;
 import net.minecraft.network.PacketListener;
 import net.minecraft.network.PacketListener;
 import net.minecraft.network.protocol.Packet;
 import net.minecraft.network.protocol.Packet;
@@ -19,13 +19,13 @@ public class MixinClientConnection {
     @Inject(method = "genericsFtw", at = @At("HEAD"))
     @Inject(method = "genericsFtw", at = @At("HEAD"))
     private static void handlePacket(Packet packet, PacketListener listener, CallbackInfo ci) {
     private static void handlePacket(Packet packet, PacketListener listener, CallbackInfo ci) {
         if (packet instanceof ClientboundBlockUpdatePacket) {
         if (packet instanceof ClientboundBlockUpdatePacket) {
-            LightOverlayCore.queueChunkAndNear(new ChunkPos(((ClientboundBlockUpdatePacket) packet).getPos()));
+            LightOverlay.queueChunkAndNear(new ChunkPos(((ClientboundBlockUpdatePacket) packet).getPos()));
         } else if (packet instanceof ClientboundSetChunkCacheCenterPacket) {
         } else if (packet instanceof ClientboundSetChunkCacheCenterPacket) {
-            LightOverlayCore.queueChunkAndNear(new ChunkPos(((ClientboundSetChunkCacheCenterPacket) packet).getX(), ((ClientboundSetChunkCacheCenterPacket) packet).getZ()));
+            LightOverlay.queueChunkAndNear(new ChunkPos(((ClientboundSetChunkCacheCenterPacket) packet).getX(), ((ClientboundSetChunkCacheCenterPacket) packet).getZ()));
         } else if (packet instanceof ClientboundSectionBlocksUpdatePacket) {
         } else if (packet instanceof ClientboundSectionBlocksUpdatePacket) {
-            LightOverlayCore.queueChunkAndNear(new ChunkPos(((ClientboundSectionBlocksUpdatePacket) packet).sectionPos.getX(), ((ClientboundSectionBlocksUpdatePacket) packet).sectionPos.getZ()));
+            LightOverlay.queueChunkAndNear(new ChunkPos(((ClientboundSectionBlocksUpdatePacket) packet).sectionPos.getX(), ((ClientboundSectionBlocksUpdatePacket) packet).sectionPos.getZ()));
         } else if (packet instanceof ClientboundLightUpdatePacket) {
         } else if (packet instanceof ClientboundLightUpdatePacket) {
-            LightOverlayCore.queueChunk(new ChunkPos(((ClientboundLightUpdatePacket) packet).getX(), ((ClientboundLightUpdatePacket) packet).getZ()));
+            LightOverlay.queueChunk(new ChunkPos(((ClientboundLightUpdatePacket) packet).getX(), ((ClientboundLightUpdatePacket) packet).getZ()));
         }
         }
     }
     }
 }
 }

+ 5 - 1
fabric/src/main/resources/fabric.mod.json

@@ -15,7 +15,7 @@
   },
   },
   "entrypoints": {
   "entrypoints": {
     "client": [
     "client": [
-      "me.shedaniel.lightoverlay.fabric.LightOverlay"
+      "me.shedaniel.lightoverlay.fabric.LightOverlayImpl::init"
     ],
     ],
     "modmenu": [
     "modmenu": [
       "me.shedaniel.lightoverlay.fabric.LOModMenuEntry"
       "me.shedaniel.lightoverlay.fabric.LOModMenuEntry"
@@ -29,5 +29,9 @@
   "accessWidener": "lightoverlay.accesswidener",
   "accessWidener": "lightoverlay.accesswidener",
   "custom": {
   "custom": {
     "modmenu:clientsideOnly": true
     "modmenu:clientsideOnly": true
+  },
+  "depends": {
+    "fabric-api": ">=0.29.1",
+    "architectury": ">=1.2.67"
   }
   }
 }
 }

+ 1 - 2
fabric/src/main/resources/lightoverlay.mixins.json

@@ -5,8 +5,7 @@
   "compatibilityLevel": "JAVA_8",
   "compatibilityLevel": "JAVA_8",
   "mixins": [],
   "mixins": [],
   "client": [
   "client": [
-    "MixinClientConnection",
-    "MixinWorldRenderer"
+    "MixinClientConnection"
   ],
   ],
   "injectors": {
   "injectors": {
     "defaultRequire": 1
     "defaultRequire": 1

+ 29 - 44
forge/build.gradle

@@ -1,62 +1,45 @@
-buildscript {
-    repositories {
-        maven { url "https://files.minecraftforge.net/maven" }
-        jcenter()
-        mavenCentral()
-    }
-    dependencies {
-        classpath(group: "net.minecraftforge.gradle", name: "ForgeGradle", version: "3.+", changing: true)
-    }
-}
-
 plugins {
 plugins {
     id "com.github.johnrengelman.shadow" version "5.0.0"
     id "com.github.johnrengelman.shadow" version "5.0.0"
-    id "eclipse"
 }
 }
 
 
-apply plugin: "net.minecraftforge.gradle"
+configurations {
+    shadow
+}
 
 
-minecraft {
-    mappings(channel: "official", version: rootProject.architect.minecraft)
-    accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
-    runs {
-        client {
-            workingDirectory project.file("run")
-            mods {
-                examplemod {
-                    source sourceSets.main
-                }
-            }
-        }
-        server {
-            workingDirectory project.file("run")
-            mods {
-                examplemod {
-                    source sourceSets.main
-                }
-            }
-        }
-    }
+architectury {
+    platformSetupLoomIde()
+}
+
+loom {
+    mixinConfig = "lightoverlay-forge.mixins.json"
 }
 }
 
 
 repositories {
 repositories {
     jcenter()
     jcenter()
-    maven { url "https://files.minecraftforge.net/maven" }
     maven { url "https://dl.bintray.com/shedaniel/cloth-config-2" }
     maven { url "https://dl.bintray.com/shedaniel/cloth-config-2" }
 }
 }
 
 
-configurations {
-    shadow
+processResources {
+    filesMatching("META-INF/mods.toml") {
+        expand "version": project.version
+    }
+    inputs.property "META-INF/mods.toml", project.version
 }
 }
 
 
 dependencies {
 dependencies {
-    minecraft("net.minecraftforge:forge:${rootProject.architect.minecraft}-${project.forge_version}")
-    implementation(fg.deobf("me.shedaniel.cloth:cloth-config-forge:${rootProject.cloth_config_forge}"))
+    minecraft("com.mojang:minecraft:${rootProject.architect.minecraft}")
+    mappings(minecraft.officialMojangMappings())
+    forge("net.minecraftforge:forge:${rootProject.architect.minecraft}-${project.forge_version}")
+    modCompile("me.shedaniel.cloth:cloth-config-forge:${rootProject.cloth_config_forge}")
+    modCompile("me.shedaniel:architectury:${rootProject.architectury_version}:forge")
 
 
-    compile(project(path: ":common", configuration: "mcpGenerateMod")) {
+    compileOnly(project(path: ":common")) {
+        transitive = false
+    }
+    runtimeOnly(project(path: ":common", configuration: "transformForgeFakeMod")) {
         transitive = false
         transitive = false
     }
     }
-    shadow(project(path: ":common", configuration: "mcp")) {
+    shadow(project(path: ":common", configuration: "transformForge")) {
         transitive = false
         transitive = false
     }
     }
 }
 }
@@ -66,9 +49,11 @@ shadowJar {
     exclude "fabric.mod.json"
     exclude "fabric.mod.json"
 
 
     configurations = [project.configurations.shadow]
     configurations = [project.configurations.shadow]
-    classifier null
+    classifier "shadow"
 }
 }
 
 
-reobf {
-    shadowJar {}
+remapJar {
+    dependsOn(shadowJar)
+    input.set(shadowJar.archivePath)
+    archiveClassifier = "forge"
 }
 }

+ 1 - 0
forge/gradle.properties

@@ -0,0 +1 @@
+loom.forge=true

+ 4 - 4
forge/src/main/java/me/shedaniel/lightoverlay/forge/FrustumHelper.java

@@ -1,10 +1,10 @@
 package me.shedaniel.lightoverlay.forge;
 package me.shedaniel.lightoverlay.forge;
 
 
-import net.minecraft.client.renderer.culling.ClippingHelper;
-import net.minecraft.util.math.vector.Vector4f;
+import com.mojang.math.Vector4f;
+import net.minecraft.client.renderer.culling.Frustum;
 
 
 public class FrustumHelper {
 public class FrustumHelper {
-    public static boolean isVisible(ClippingHelper frustum, double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
+    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 x1 = (float) (minX - frustum.camX);
         float y1 = (float) (minY - frustum.camY);
         float y1 = (float) (minY - frustum.camY);
         float z1 = (float) (minZ - frustum.camZ);
         float z1 = (float) (minZ - frustum.camZ);
@@ -14,7 +14,7 @@ public class FrustumHelper {
         return isAnyCornerVisible(frustum, x1, y1, z1, x2, y2, z2);
         return isAnyCornerVisible(frustum, x1, y1, z1, x2, y2, z2);
     }
     }
     
     
-    private static boolean isAnyCornerVisible(ClippingHelper frustum, float x1, float y1, float z1, float x2, float y2, float z2) {
+    private static boolean isAnyCornerVisible(Frustum frustum, float x1, float y1, float z1, float x2, float y2, float z2) {
         Vector4f[] homogeneousCoordinates = frustum.frustumData;
         Vector4f[] homogeneousCoordinates = frustum.frustumData;
         for (Vector4f vector4f : homogeneousCoordinates) {
         for (Vector4f 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) {
             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) {

+ 3 - 8
forge/src/main/java/me/shedaniel/lightoverlay/forge/LightOverlay.java

@@ -1,22 +1,17 @@
 package me.shedaniel.lightoverlay.forge;
 package me.shedaniel.lightoverlay.forge;
 
 
-import net.minecraft.network.IPacket;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.Dist;
-import net.minecraftforge.fml.ExtensionPoint;
 import net.minecraftforge.fml.DistExecutor;
 import net.minecraftforge.fml.DistExecutor;
+import net.minecraftforge.fml.ExtensionPoint;
 import net.minecraftforge.fml.ModLoadingContext;
 import net.minecraftforge.fml.ModLoadingContext;
 import net.minecraftforge.fml.common.Mod;
 import net.minecraftforge.fml.common.Mod;
 import net.minecraftforge.fml.network.FMLNetworkConstants;
 import net.minecraftforge.fml.network.FMLNetworkConstants;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.commons.lang3.tuple.Pair;
 
 
-@Mod("lightoverlay-forge")
+@Mod("lightoverlay")
 public class LightOverlay {
 public class LightOverlay {
     public LightOverlay() {
     public LightOverlay() {
         ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true));
         ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true));
-        DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> LightOverlayClient::register);
-    }
-    
-    public static void processPacket(IPacket<?> packet) {
-        DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> LightOverlayClient.processPacket(packet));
+        DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> LightOverlayImpl::register);
     }
     }
 }
 }

+ 0 - 77
forge/src/main/java/me/shedaniel/lightoverlay/forge/LightOverlayClient.java

@@ -1,77 +0,0 @@
-package me.shedaniel.lightoverlay.forge;
-
-import me.shedaniel.lightoverlay.common.AbstractPlatform;
-import me.shedaniel.lightoverlay.common.LightOverlayCore;
-import net.minecraft.client.renderer.culling.ClippingHelper;
-import net.minecraft.client.settings.KeyBinding;
-import net.minecraft.network.IPacket;
-import net.minecraft.network.play.server.SChangeBlockPacket;
-import net.minecraft.network.play.server.SChunkDataPacket;
-import net.minecraft.network.play.server.SMultiBlockChangePacket;
-import net.minecraft.network.play.server.SUpdateLightPacket;
-import net.minecraft.util.math.ChunkPos;
-import net.minecraftforge.api.distmarker.Dist;
-import net.minecraftforge.common.MinecraftForge;
-import net.minecraftforge.event.TickEvent;
-import net.minecraftforge.fml.DistExecutor;
-import net.minecraftforge.fml.client.registry.ClientRegistry;
-import net.minecraftforge.fml.loading.FMLPaths;
-
-import java.nio.file.Path;
-
-public class LightOverlayClient {
-    private static Runnable debugRenderer = () -> {};
-    
-    public static void register() {
-        LightOverlayCore.register(new AbstractPlatform() {
-            @Override
-            public Path getConfigDir() {
-                return FMLPaths.CONFIGDIR.get();
-            }
-            
-            @Override
-            public void registerClientTick(Runnable runnable) {
-                MinecraftForge.EVENT_BUS.<TickEvent.ClientTickEvent>addListener(event -> runnable.run());
-            }
-            
-            @Override
-            public void registerDebugRenderer(Runnable runnable) {
-                debugRenderer = runnable;
-            }
-            
-            @Override
-            public KeyBinding registerKeyBinding(KeyBinding keyBinding) {
-                ClientRegistry.registerKeyBinding(keyBinding);
-                return keyBinding;
-            }
-            
-            @Override
-            public boolean isFrustumVisible(ClippingHelper clippingHelper, double v, double v1, double v2, double v3, double v4, double v5) {
-                return FrustumHelper.isVisible(clippingHelper, v, v1, v2, v3, v4, v5);
-            }
-        });
-        
-        try {
-            //noinspection Convert2MethodRef
-            DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> LightOverlayCloth.register());
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-    
-    public static void renderWorldLast() {
-        debugRenderer.run();
-    }
-    
-    public static void processPacket(IPacket<?> packet) {
-        if (packet instanceof SChangeBlockPacket) {
-            LightOverlayCore.queueChunkAndNear(new ChunkPos(((SChangeBlockPacket) packet).getPos()));
-        } else if (packet instanceof SChunkDataPacket) {
-            LightOverlayCore.queueChunkAndNear(new ChunkPos(((SChunkDataPacket) packet).getX(), ((SChunkDataPacket) packet).getZ()));
-        } else if (packet instanceof SMultiBlockChangePacket) {
-            LightOverlayCore.queueChunkAndNear(new ChunkPos(((SMultiBlockChangePacket) packet).sectionPos.getX(), ((SMultiBlockChangePacket) packet).sectionPos.getZ()));
-        } else if (packet instanceof SUpdateLightPacket) {
-            LightOverlayCore.queueChunkAndNear(new ChunkPos(((SUpdateLightPacket) packet).getX(), ((SUpdateLightPacket) packet).getZ()));
-        }
-    }
-}

+ 23 - 23
forge/src/main/java/me/shedaniel/lightoverlay/forge/LightOverlayCloth.java

@@ -4,11 +4,11 @@ import me.shedaniel.clothconfig2.forge.api.ConfigBuilder;
 import me.shedaniel.clothconfig2.forge.api.ConfigCategory;
 import me.shedaniel.clothconfig2.forge.api.ConfigCategory;
 import me.shedaniel.clothconfig2.forge.api.ConfigEntryBuilder;
 import me.shedaniel.clothconfig2.forge.api.ConfigEntryBuilder;
 import me.shedaniel.clothconfig2.forge.gui.entries.IntegerSliderEntry;
 import me.shedaniel.clothconfig2.forge.gui.entries.IntegerSliderEntry;
-import me.shedaniel.lightoverlay.common.LightOverlayCore;
-import net.minecraft.client.resources.I18n;
-import net.minecraft.util.math.MathHelper;
-import net.minecraft.util.text.ITextComponent;
-import net.minecraft.util.text.TranslationTextComponent;
+import me.shedaniel.lightoverlay.common.LightOverlay;
+import net.minecraft.client.resources.language.I18n;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.TranslatableComponent;
+import net.minecraft.util.Mth;
 import net.minecraftforge.fml.ExtensionPoint;
 import net.minecraftforge.fml.ExtensionPoint;
 import net.minecraftforge.fml.ModLoadingContext;
 import net.minecraftforge.fml.ModLoadingContext;
 
 
@@ -17,36 +17,36 @@ import java.util.Optional;
 public class LightOverlayCloth {
 public class LightOverlayCloth {
     public static void register() {
     public static void register() {
         ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY, () -> (client, parent) -> {
         ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY, () -> (client, parent) -> {
-            ConfigBuilder builder = ConfigBuilder.create().setParentScreen(parent).setTitle(new TranslationTextComponent("key.lightoverlay.category"));
+            ConfigBuilder builder = ConfigBuilder.create().setParentScreen(parent).setTitle(new TranslatableComponent("key.lightoverlay.category"));
             
             
             ConfigEntryBuilder eb = builder.entryBuilder();
             ConfigEntryBuilder eb = builder.entryBuilder();
-            ConfigCategory general = builder.getOrCreateCategory(new TranslationTextComponent("config.lightoverlay.general"));
-            general.addEntry(eb.startTextDescription(ITextComponent.nullToEmpty("§7" + I18n.get("description.lightoverlay.caching"))).build());
-            general.addEntry(eb.startBooleanToggle(new TranslationTextComponent("config.lightoverlay.caching"), LightOverlayCore.caching).setDefaultValue(false).setSaveConsumer(bool -> LightOverlayCore.caching = bool).build());
-            general.addEntry(eb.startIntSlider(new TranslationTextComponent("config.lightoverlay.reach"), LightOverlayCore.reach, 1, 64).setDefaultValue(12).setTextGetter(integer -> ITextComponent.nullToEmpty("Reach: " + integer + " Blocks")).setSaveConsumer(integer -> LightOverlayCore.reach = integer).build());
-            IntegerSliderEntry crossLevel = eb.startIntSlider(new TranslationTextComponent("config.lightoverlay.crossLevel"), LightOverlayCore.crossLevel, 0, 15).setDefaultValue(7).setTextGetter(integer -> ITextComponent.nullToEmpty("Cross Level: " + integer)).setSaveConsumer(integer -> LightOverlayCore.crossLevel = integer).build();
+            ConfigCategory 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();
             general.addEntry(crossLevel);
             general.addEntry(crossLevel);
-            general.addEntry(eb.startIntSlider(new TranslationTextComponent("config.lightoverlay.secondaryLevel"), LightOverlayCore.secondaryLevel, -1, 15)
+            general.addEntry(eb.startIntSlider(new TranslatableComponent("config.lightoverlay.secondaryLevel"), LightOverlay.secondaryLevel, -1, 15)
                     .setErrorSupplier(integer -> {
                     .setErrorSupplier(integer -> {
                         if (integer >= 0 && integer >= crossLevel.getValue())
                         if (integer >= 0 && integer >= crossLevel.getValue())
-                            return Optional.of(ITextComponent.nullToEmpty("Secondary Level cannot be higher than Cross Level!"));
+                            return Optional.of(Component.nullToEmpty("Secondary Level cannot be higher than Cross Level!"));
                         return Optional.empty();
                         return Optional.empty();
-                    }).setDefaultValue(-1).setTextGetter(integer -> ITextComponent.nullToEmpty(integer < 0 ? "Off" : "Level: " + integer)).setSaveConsumer(integer -> LightOverlayCore.secondaryLevel = integer).build());
-            general.addEntry(eb.startBooleanToggle(new TranslationTextComponent("config.lightoverlay.showNumber"), LightOverlayCore.showNumber).setDefaultValue(false).setSaveConsumer(bool -> LightOverlayCore.showNumber = bool).build());
-            general.addEntry(eb.startBooleanToggle(new TranslationTextComponent("config.lightoverlay.smoothLines"), LightOverlayCore.smoothLines).setDefaultValue(true).setSaveConsumer(bool -> LightOverlayCore.smoothLines = bool).build());
-            general.addEntry(eb.startBooleanToggle(new TranslationTextComponent("config.lightoverlay.underwater"), LightOverlayCore.underwater).setDefaultValue(false).setSaveConsumer(bool -> LightOverlayCore.underwater = bool).build());
-            general.addEntry(eb.startIntSlider(new TranslationTextComponent("config.lightoverlay.lineWidth"), MathHelper.floor(LightOverlayCore.lineWidth * 100), 100, 700).setDefaultValue(100).setTextGetter(integer -> ITextComponent.nullToEmpty("Light Width: " + LightOverlayCore.FORMAT.format(integer / 100d))).setSaveConsumer(integer -> LightOverlayCore.lineWidth = integer / 100f).build());
-            general.addEntry(eb.startColorField(new TranslationTextComponent("config.lightoverlay.yellowColor"), LightOverlayCore.yellowColor).setDefaultValue(0xFFFF00).setSaveConsumer(color -> LightOverlayCore.yellowColor = color).build());
-            general.addEntry(eb.startColorField(new TranslationTextComponent("config.lightoverlay.redColor"), LightOverlayCore.redColor).setDefaultValue(0xFF0000).setSaveConsumer(color -> LightOverlayCore.redColor = color).build());
-            general.addEntry(eb.startColorField(new TranslationTextComponent("config.lightoverlay.secondaryColor"), LightOverlayCore.secondaryColor).setDefaultValue(0x0000FF).setSaveConsumer(color -> LightOverlayCore.secondaryColor = color).build());
+                    }).setDefaultValue(-1).setTextGetter(integer -> Component.nullToEmpty(integer < 0 ? "Off" : "Level: " + integer)).setSaveConsumer(integer -> LightOverlay.secondaryLevel = integer).build());
+            general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.showNumber"), LightOverlay.showNumber).setDefaultValue(false).setSaveConsumer(bool -> LightOverlay.showNumber = bool).build());
+            general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.smoothLines"), LightOverlay.smoothLines).setDefaultValue(true).setSaveConsumer(bool -> LightOverlay.smoothLines = bool).build());
+            general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.underwater"), LightOverlay.underwater).setDefaultValue(false).setSaveConsumer(bool -> LightOverlay.underwater = bool).build());
+            general.addEntry(eb.startIntSlider(new TranslatableComponent("config.lightoverlay.lineWidth"), Mth.floor(LightOverlay.lineWidth * 100), 100, 700).setDefaultValue(100).setTextGetter(integer -> Component.nullToEmpty("Light Width: " + LightOverlay.FORMAT.format(integer / 100d))).setSaveConsumer(integer -> LightOverlay.lineWidth = integer / 100f).build());
+            general.addEntry(eb.startColorField(new TranslatableComponent("config.lightoverlay.yellowColor"), LightOverlay.yellowColor).setDefaultValue(0xFFFF00).setSaveConsumer(color -> LightOverlay.yellowColor = color).build());
+            general.addEntry(eb.startColorField(new TranslatableComponent("config.lightoverlay.redColor"), LightOverlay.redColor).setDefaultValue(0xFF0000).setSaveConsumer(color -> LightOverlay.redColor = color).build());
+            general.addEntry(eb.startColorField(new TranslatableComponent("config.lightoverlay.secondaryColor"), LightOverlay.secondaryColor).setDefaultValue(0x0000FF).setSaveConsumer(color -> LightOverlay.secondaryColor = color).build());
             
             
             return builder.setSavingRunnable(() -> {
             return builder.setSavingRunnable(() -> {
                 try {
                 try {
-                    LightOverlayCore.saveConfig(LightOverlayCore.configFile);
+                    LightOverlay.saveConfig(LightOverlay.configFile);
                 } catch (Exception e) {
                 } catch (Exception e) {
                     e.printStackTrace();
                     e.printStackTrace();
                 }
                 }
-                LightOverlayCore.loadConfig(LightOverlayCore.configFile);
+                LightOverlay.loadConfig(LightOverlay.configFile);
             }).build();
             }).build();
         });
         });
     }
     }

+ 29 - 0
forge/src/main/java/me/shedaniel/lightoverlay/forge/LightOverlayImpl.java

@@ -0,0 +1,29 @@
+package me.shedaniel.lightoverlay.forge;
+
+import me.shedaniel.lightoverlay.common.LightOverlay;
+import net.minecraft.client.renderer.culling.Frustum;
+import net.minecraftforge.api.distmarker.Dist;
+import net.minecraftforge.fml.DistExecutor;
+
+public class LightOverlayImpl {
+    public static Runnable debugRenderer = () -> {};
+    
+    public static void register() {
+        LightOverlay.register();
+        
+        try {
+            //noinspection Convert2MethodRef
+            DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> LightOverlayCloth.register());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
+    public static boolean isFrustumVisible(Frustum clippingHelper, double v, double v1, double v2, double v3, double v4, double v5) {
+        return FrustumHelper.isVisible(clippingHelper, v, v1, v2, v3, v4, v5);
+    }
+    
+    public static void renderWorldLast() {
+        debugRenderer.run();
+    }
+}

+ 31 - 0
forge/src/main/java/me/shedaniel/lightoverlay/forge/mixin/MixinClientConnection.java

@@ -0,0 +1,31 @@
+package me.shedaniel.lightoverlay.forge.mixin;
+
+import me.shedaniel.lightoverlay.common.LightOverlay;
+import net.minecraft.network.Connection;
+import net.minecraft.network.PacketListener;
+import net.minecraft.network.protocol.Packet;
+import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
+import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket;
+import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket;
+import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket;
+import net.minecraft.world.level.ChunkPos;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(Connection.class)
+public class MixinClientConnection {
+    @Inject(method = "genericsFtw", at = @At("HEAD"))
+    private static void handlePacket(Packet packet, PacketListener listener, CallbackInfo ci) {
+        if (packet instanceof ClientboundBlockUpdatePacket) {
+            LightOverlay.queueChunkAndNear(new ChunkPos(((ClientboundBlockUpdatePacket) packet).getPos()));
+        } else if (packet instanceof ClientboundSetChunkCacheCenterPacket) {
+            LightOverlay.queueChunkAndNear(new ChunkPos(((ClientboundSetChunkCacheCenterPacket) packet).getX(), ((ClientboundSetChunkCacheCenterPacket) packet).getZ()));
+        } else if (packet instanceof ClientboundSectionBlocksUpdatePacket) {
+            LightOverlay.queueChunkAndNear(new ChunkPos(((ClientboundSectionBlocksUpdatePacket) packet).sectionPos.getX(), ((ClientboundSectionBlocksUpdatePacket) packet).sectionPos.getZ()));
+        } else if (packet instanceof ClientboundLightUpdatePacket) {
+            LightOverlay.queueChunk(new ChunkPos(((ClientboundLightUpdatePacket) packet).getX(), ((ClientboundLightUpdatePacket) packet).getZ()));
+        }
+    }
+}

+ 18 - 0
forge/src/main/java/me/shedaniel/lightoverlay/forge/mixin/MixinDebugRenderer.java

@@ -0,0 +1,18 @@
+package me.shedaniel.lightoverlay.forge.mixin;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.lightoverlay.forge.LightOverlayImpl;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.debug.DebugRenderer;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(DebugRenderer.class)
+public class MixinDebugRenderer {
+    @Inject(method = "render", at = @At("HEAD"))
+    private void render(PoseStack arg, MultiBufferSource.BufferSource arg2, double d, double e, double f, CallbackInfo ci) {
+        LightOverlayImpl.renderWorldLast();
+    }
+}

+ 4 - 4
fabric/src/main/java/me/shedaniel/lightoverlay/fabric/mixin/MixinWorldRenderer.java → forge/src/main/java/me/shedaniel/lightoverlay/forge/mixin/MixinLevelRenderer.java

@@ -1,6 +1,6 @@
-package me.shedaniel.lightoverlay.fabric.mixin;
+package me.shedaniel.lightoverlay.forge.mixin;
 
 
-import me.shedaniel.lightoverlay.common.LightOverlayCore;
+import me.shedaniel.lightoverlay.common.LightOverlay;
 import net.minecraft.client.Camera;
 import net.minecraft.client.Camera;
 import net.minecraft.client.renderer.LevelRenderer;
 import net.minecraft.client.renderer.LevelRenderer;
 import net.minecraft.client.renderer.culling.Frustum;
 import net.minecraft.client.renderer.culling.Frustum;
@@ -10,9 +10,9 @@ import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 
 
 @Mixin(LevelRenderer.class)
 @Mixin(LevelRenderer.class)
-public class MixinWorldRenderer {
+public class MixinLevelRenderer {
     @Inject(method = "setupRender", at = @At("HEAD"))
     @Inject(method = "setupRender", at = @At("HEAD"))
     private void setupTerrain(Camera camera, Frustum frustum, boolean bl, int i, boolean bl2, CallbackInfo ci) {
     private void setupTerrain(Camera camera, Frustum frustum, boolean bl, int i, boolean bl2, CallbackInfo ci) {
-        LightOverlayCore.frustum = frustum;
+        LightOverlay.frustum = frustum;
     }
     }
 }
 }

+ 0 - 37
forge/src/main/resources/META-INF/NetworkManager.js

@@ -1,37 +0,0 @@
-var Opcodes = Java.type("org.objectweb.asm.Opcodes");
-var LabelNode = Java.type("org.objectweb.asm.tree.LabelNode");
-var VarInsnNode = Java.type("org.objectweb.asm.tree.VarInsnNode");
-var MethodInsnNode = Java.type("org.objectweb.asm.tree.MethodInsnNode");
-var ASMAPI = Java.type("net.minecraftforge.coremod.api.ASMAPI");
-
-function initializeCoreMod() {
-    return {
-        "light-overlay-forge": {
-            'target': {
-                'type': 'CLASS',
-                'name': 'net.minecraft.network.NetworkManager'
-            },
-            'transformer': function (classNode) {
-                var processPacket = ASMAPI.mapMethod("func_197664_a");
-                for (i in classNode.methods) {
-                    var method = classNode.methods[i];
-                    if (method.name === processPacket) {
-                        var instructions = method.instructions;
-                        var insnArray = instructions.toArray();
-                        for (j in insnArray) {
-                            var instruction = insnArray[j];
-                            if (instruction instanceof LabelNode) {
-                                instructions.insertBefore(instruction, new LabelNode());
-                                instructions.insertBefore(instruction, new VarInsnNode(Opcodes.ALOAD, 0));
-                                instructions.insertBefore(instruction, new MethodInsnNode(Opcodes.INVOKESTATIC, "me/shedaniel/lightoverlay/forge/LightOverlay", "processPacket", "(Lnet/minecraft/network/IPacket;)V", false));
-                                break;
-                            }
-                        }
-                        break;
-                    }
-                }
-                return classNode;
-            }
-        }
-    }
-}

+ 0 - 43
forge/src/main/resources/META-INF/WorldRenderer.js

@@ -1,43 +0,0 @@
-var Opcodes = Java.type("org.objectweb.asm.Opcodes");
-var LabelNode = Java.type("org.objectweb.asm.tree.LabelNode");
-var VarInsnNode = Java.type("org.objectweb.asm.tree.VarInsnNode");
-var MethodInsnNode = Java.type("org.objectweb.asm.tree.MethodInsnNode");
-var ASMAPI = Java.type("net.minecraftforge.coremod.api.ASMAPI");
-
-function initializeCoreMod() {
-    return {
-        "light-overlay-forge": {
-            'target': {
-                'type': 'CLASS',
-                'name': 'net.minecraft.client.renderer.debug.DebugRenderer'
-            },
-            'transformer': function (classNode) {
-                var render = ASMAPI.mapMethod("func_229019_a_");
-                var setupTerrain = ASMAPI.mapMethod("func_228437_a_");
-                for (var i in classNode.methods) {
-                    var method = classNode.methods[i];
-                    if (method.name === render) {
-                        var instructions = method.instructions;
-                        var insnArray = instructions.toArray();
-                        for (j in insnArray) {
-                            var instruction = insnArray[j];
-                            if (instruction instanceof LabelNode) {
-                                instructions.insertBefore(instruction, new LabelNode());
-                                instructions.insertBefore(instruction, new VarInsnNode(Opcodes.ALOAD, 0));
-                                instructions.insertBefore(instruction, new MethodInsnNode(Opcodes.INVOKESTATIC, "me/shedaniel/lightoverlay/forge/LightOverlayClient", "renderWorldLast", "()V", false));
-                                break;
-                            }
-                        }
-                        break;
-                    } else if (method.name === setupTerrain) {
-                        var instructions = method.instructions;
-                        instructions.insertBefore(new LabelNode());
-                        instructions.insertBefore(new VarInsnNode(Opcodes.ALOAD, 2));
-                        instructions.insertBefore(new MethodInsnNode(Opcodes.INVOKESTATIC, "me/shedaniel/lightoverlay/forge/LightOverlayClient", "updateFrustum", "(Lnet/minecraft/client/renderer/culling/ClippingHelper;)V", false));
-                    }
-                }
-                return classNode;
-            }
-        }
-    }
-}

+ 0 - 4
forge/src/main/resources/META-INF/coremods.json

@@ -1,4 +0,0 @@
-{
-  "NetworkManager": "META-INF/NetworkManager.js",
-  "WorldRenderer": "META-INF/WorldRenderer.js"
-}

+ 23 - 16
forge/src/main/resources/META-INF/mods.toml

@@ -1,20 +1,27 @@
-modLoader="javafml"
-loaderVersion="[33,)"
-issueTrackerURL="https://github.com/shedaniel/LightOverlay/issues/" #optional
-logoFile="icon.png"
-authors="shedaniel"
-license="Apache-2.0"
+modLoader = "javafml"
+loaderVersion = "[33,)"
+issueTrackerURL = "https://github.com/shedaniel/LightOverlay/issues/" #optional
+logoFile = "icon.png"
+authors = "shedaniel"
+license = "Apache-2.0"
 [[mods]]
 [[mods]]
-    modId="lightoverlay-forge"
-    version="${file.jarVersion}"
-    displayName="Light Overlay Forge"
-    description='''
+modId = "lightoverlay"
+version = "${version}"
+displayName = "Light Overlay"
+description = '''
 To provide users with NEI-like light overlay.
 To provide users with NEI-like light overlay.
 '''
 '''
 
 
-[[dependencies.lightoverlay-forge]]
-    modId="cloth-config"
-    mandatory=true
-    versionRange="[4.0,)"
-    ordering="NONE"
-    side="CLIENT"
+[[dependencies.lightoverlay]]
+modId = "cloth-config"
+mandatory = true
+versionRange = "[4.1.3,)"
+ordering = "NONE"
+side = "CLIENT"
+
+[[dependencies.lightoverlay]]
+modId = "architectury"
+mandatory = true
+versionRange = "[1.2.67,)"
+ordering = "NONE"
+side = "CLIENT"

+ 15 - 0
forge/src/main/resources/lightoverlay-forge.mixins.json

@@ -0,0 +1,15 @@
+{
+  "required": true,
+  "package": "me.shedaniel.lightoverlay.forge.mixin",
+  "minVersion": "0.7.11",
+  "compatibilityLevel": "JAVA_8",
+  "mixins": [],
+  "client": [
+    "MixinClientConnection",
+    "MixinDebugRenderer",
+    "MixinLevelRenderer"
+  ],
+  "injectors": {
+    "defaultRequire": 1
+  }
+}

+ 9 - 8
gradle.properties

@@ -1,16 +1,17 @@
 org.gradle.jvmargs=-Xmx3G
 org.gradle.jvmargs=-Xmx3G
 org.gradle.daemon=false
 org.gradle.daemon=false
 
 
-mod_version=5.5.4
-minecraft_version=1.16.2
+mod_version=5.6.0
+minecraft_version=1.16.4
+
+architectury_version=1.2.67
 
 
 # fabric
 # fabric
-fabric_loader_version=0.9.1+build.205
-fabric_api_version=0.17.2+build.396-1.16
-cloth_version=1.0.8
-cloth_config_version=4.7.0-unstable
+fabric_loader_version=0.10.8
+fabric_api_version=0.29.1+1.16
+cloth_config_version=4.8.3
 modmenu_version=1.14.6+build.31
 modmenu_version=1.14.6+build.31
 
 
 # forge
 # forge
-forge_version=33.0.57
-cloth_config_forge=4.1.0
+forge_version=35.1.7
+cloth_config_forge=4.1.3

+ 1 - 3
merging.policy

@@ -1,3 +1 @@
-FABRIC /assets/lightoverlay/lang/en_us.json
-FORGE /META-INF/MANIFEST.MF
-FABRIC /icon.png
+FORGE /META-INF/MANIFEST.MF

+ 2 - 4
settings.gradle

@@ -1,11 +1,9 @@
 pluginManagement {
 pluginManagement {
     repositories {
     repositories {
         jcenter()
         jcenter()
-        maven {
-            name = 'Fabric'
-            url = 'https://maven.fabricmc.net/'
-        }
+        maven { url "https://maven.fabricmc.net/" }
         maven { url "https://dl.bintray.com/shedaniel/cloth" }
         maven { url "https://dl.bintray.com/shedaniel/cloth" }
+        maven { url "https://files.minecraftforge.net/maven/" }
         gradlePluginPortal()
         gradlePluginPortal()
     }
     }
 }
 }