From: shedaniel Date: Tue, 15 Jun 2021 13:47:54 +0000 (+0800) Subject: Update to 1.17 X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=f486673f8eabbbc5d657ed313c48e38eff1ab54e;p=LightOverlay.git Update to 1.17 Signed-off-by: shedaniel --- diff --git a/build.gradle b/build.gradle index 06d5686..59744a3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,25 +1,6 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath("commons-io:commons-io:2.6") - } -} - -import java.nio.file.FileVisitResult -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.SimpleFileVisitor -import java.nio.file.attribute.BasicFileAttributes -import java.util.stream.Stream -import java.util.zip.ZipEntry -import java.util.zip.ZipInputStream -import java.util.zip.ZipOutputStream - plugins { - id "architectury-plugin" version "3.0.76" - id "forgified-fabric-loom" version "0.6.67" apply false + id "architectury-plugin" version "3.2-SNAPSHOT" + id "dev.architectury.loom" version "0.7.2-SNAPSHOT" apply false } architectury { @@ -27,7 +8,7 @@ architectury { } subprojects { - apply plugin: "forgified-fabric-loom" + apply plugin: "dev.architectury.loom" loom { silentMojangMappingsLicense() @@ -42,141 +23,12 @@ allprojects { archivesBaseName = rootProject.name version = rootProject.mod_version - tasks.withType(JavaCompile) { - options.encoding = "UTF-8" - } -} - -task buildMerged { - allprojects { - dependsOn it.tasks.getByName("build") - } - doLast { - def folder = file(".gradle/.mergemods") - folder.mkdirs() - 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 forgeFolder = new File(folder, ".tempForge") - def mergeFolder = new File(folder, ".tempMerge") - def policyMap = new HashMap() - file("merging.policy").eachLine { - if (it.isBlank() || it.startsWith("#")) return - def env = it.substring(0, it.indexOf(' ')) - if (env == "FABRIC") - policyMap.put(it.substring(env.length() + 1), "Fabric") - else if (env == "FORGE") - policyMap.put(it.substring(env.length() + 1), "Forge") - else throw new IllegalStateException("Illegal env $env at $it") - } - forgeFolder.deleteDir() - fabricFolder.deleteDir() - mergeFolder.deleteDir() - unzip(fabricJar, fabricFolder) - unzip(forgeJar, forgeFolder) - mergeFolder.mkdirs() - Stream.of(forgeFolder, fabricFolder).each { useFolder -> - try { - Files.walkFileTree(useFolder.toPath(), new SimpleFileVisitor() { - @Override - FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - try { - File ogFile = file.toFile() - File outFile = new File(mergeFolder, ogFile.getAbsolutePath().replace(useFolder.getAbsolutePath(), "")) - outFile.getParentFile().mkdirs() - if (outFile.exists()) { - def env = useFolder.getName().substring(5) - def fileName = outFile.getAbsolutePath().replace(mergeFolder.getAbsolutePath(), "") - 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 - } - } - if (!ogFile.isDirectory()) { - org.apache.commons.io.FileUtils.copyFile(ogFile, outFile) - } else { - org.apache.commons.io.FileUtils.copyDirectory(ogFile, outFile) - } - } catch (IOException e) { - e.printStackTrace() - System.exit(0) - } - return FileVisitResult.CONTINUE - } - }) - } catch (IOException e) { - e.printStackTrace() - System.exit(0) - } - } - File finalMerge = file("build/libs/${rootProject.name}-${rootProject.mod_version}.jar") - finalMerge.parentFile.mkdirs() - finalMerge.delete() - compress(mergeFolder.toPath(), finalMerge) - folder.deleteDir() + repositories { + maven { url "https://maven.terraformersmc.com/releases" } } -} - -rootProject.subprojects.forEach { - buildMerged.mustRunAfter it.tasks.getByName("build") -} -static def compress(Path sourceDir, File zipFile) { - try { - final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(zipFile)) - Files.walkFileTree(sourceDir, new SimpleFileVisitor() { - @Override - FileVisitResult visitFile(Path file, BasicFileAttributes attributes) { - try { - Path targetFile = sourceDir.relativize(file) - outputStream.putNextEntry(new ZipEntry(targetFile.toString())) - byte[] bytes = Files.readAllBytes(file) - outputStream.write(bytes, 0, bytes.length) - outputStream.closeEntry() - } catch (IOException e) { - e.printStackTrace() - } - return FileVisitResult.CONTINUE - } - }) - outputStream.close() - } catch (IOException e) { - e.printStackTrace() + tasks.withType(JavaCompile) { + options.encoding = "UTF-8" + options.release = 16 } } - -static def unzip(File zipFile, File destDir) { - if (!destDir.exists()) - destDir.mkdirs() - FileInputStream fis - byte[] buffer = new byte[1024] - try { - fis = new FileInputStream(zipFile) - ZipInputStream zis = new ZipInputStream(fis) - ZipEntry zipEntry = zis.getNextEntry() - while (zipEntry != null) { - if (!zipEntry.isDirectory()) { - File newFile = new File(destDir, zipEntry.getName()) - new File(newFile.getParent()).mkdirs() - FileOutputStream fos = new FileOutputStream(newFile) - int len - while ((len = zis.read(buffer)) > 0) { - fos.write(buffer, 0, len) - } - fos.close() - } - zis.closeEntry() - zipEntry = zis.getNextEntry() - } - zis.closeEntry() - zis.close() - fis.close() - } catch (IOException e) { - e.printStackTrace() - } -} \ No newline at end of file diff --git a/common/build.gradle b/common/build.gradle index 377b4f2..f1f5bb3 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,13 +1,13 @@ dependencies { minecraft "com.mojang:minecraft:${rootProject.architectury.minecraft}" mappings minecraft.officialMojangMappings() - modCompile "me.shedaniel:architectury:${rootProject.architectury_version}" - modCompile "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" + modImplementation "dev.architectury:architectury:${rootProject.architectury_version}" + modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" modCompileOnly("me.shedaniel.cloth:cloth-config:${rootProject.cloth_config_version}") { exclude(group: "net.fabricmc.fabric-api") } } architectury { - common() + common(false) } \ No newline at end of file diff --git a/common/src/main/java/me/shedaniel/lightoverlay/common/ChunkData.java b/common/src/main/java/me/shedaniel/lightoverlay/common/ChunkData.java deleted file mode 100644 index e4278a1..0000000 --- a/common/src/main/java/me/shedaniel/lightoverlay/common/ChunkData.java +++ /dev/null @@ -1,131 +0,0 @@ -package me.shedaniel.lightoverlay.common; - -import it.unimi.dsi.fastutil.longs.Long2ByteMap; -import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -import org.lwjgl.opengl.GL11; - -import java.io.Closeable; - -import static me.shedaniel.lightoverlay.common.LightOverlay.*; - -public class ChunkData implements Closeable { - private static final IllegalStateException WRONG_TYPE = new IllegalStateException("Wrong type accessed!"); - private Long2ByteMap data; - private int glListIndex = 0; - private boolean generatedList = false; - - public ChunkData() { - this(new Long2ByteOpenHashMap()); - } - - public ChunkData(Long2ByteMap data) { - this.data = data; - } - - public Long2ByteMap data() { - return data; - } - - private void compileList(Level level, CollisionContext collisionContext) { - generatedList = true; - - if (data().isEmpty()) { - glListIndex = 0; - return; - } - - glListIndex = GL11.glGenLists(3); - GL11.glNewList(glListIndex, GL11.GL_COMPILE); - GL11.glBegin(GL11.GL_LINES); - color(redColor); - - BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); - for (Long2ByteMap.Entry objectEntry : data().long2ByteEntrySet()) { - byte crossType = objectEntry.getByteValue(); - mutable.set(BlockPos.getX(objectEntry.getLongKey()), BlockPos.getY(objectEntry.getLongKey()), BlockPos.getZ(objectEntry.getLongKey())); - if (crossType == CROSS_RED) { - renderCross(level, mutable, collisionContext); - } - } - - GL11.glEnd(); - GL11.glEndList(); - - GL11.glNewList(glListIndex + 1, GL11.GL_COMPILE); - GL11.glBegin(GL11.GL_LINES); - color(yellowColor); - - for (Long2ByteMap.Entry objectEntry : data().long2ByteEntrySet()) { - byte crossType = objectEntry.getByteValue(); - mutable.set(BlockPos.getX(objectEntry.getLongKey()), BlockPos.getY(objectEntry.getLongKey()), BlockPos.getZ(objectEntry.getLongKey())); - if (crossType == CROSS_YELLOW) { - renderCross(level, mutable, collisionContext); - } - } - - GL11.glEnd(); - GL11.glEndList(); - - GL11.glNewList(glListIndex + 2, GL11.GL_COMPILE); - GL11.glBegin(GL11.GL_LINES); - color(secondaryColor); - - for (Long2ByteMap.Entry objectEntry : data().long2ByteEntrySet()) { - byte crossType = objectEntry.getByteValue(); - mutable.set(BlockPos.getX(objectEntry.getLongKey()), BlockPos.getY(objectEntry.getLongKey()), BlockPos.getZ(objectEntry.getLongKey())); - if (crossType == CROSS_SECONDARY) { - renderCross(level, mutable, collisionContext); - } - } - - GL11.glEnd(); - GL11.glEndList(); - } - - public void renderList(Level level, CollisionContext collisionContext) { - if (!generatedList) { - compileList(level, collisionContext); - } - - if (glListIndex != 0) { - GL11.glCallList(glListIndex); - GL11.glCallList(glListIndex + 1); - GL11.glCallList(glListIndex + 2); - } - } - - private static void color(int color) { - int red = (color >> 16) & 255; - int green = (color >> 8) & 255; - int blue = color & 255; - GL11.glColor4f(red / 255f, green / 255f, blue / 255f, 1f); - } - - public static void renderCross(Level level, BlockPos pos, CollisionContext collisionContext) { - double blockOffset = 0; - VoxelShape upperOutlineShape = level.getBlockState(pos).getShape(level, pos, collisionContext); - if (!upperOutlineShape.isEmpty()) - blockOffset += upperOutlineShape.max(Direction.Axis.Y); - - - int x = pos.getX(); - int y = pos.getY(); - int z = pos.getZ(); - GL11.glVertex3d(x + .01, y + blockOffset, z + .01); - GL11.glVertex3d(x - .01 + 1, y + blockOffset, z - .01 + 1); - GL11.glVertex3d(x - .01 + 1, y + blockOffset, z + .01); - GL11.glVertex3d(x + .01, y + blockOffset, z - .01 + 1); - } - - @Override - public void close() { - if (glListIndex != 0) { - GL11.glDeleteLists(glListIndex, 3); - } - } -} diff --git a/common/src/main/java/me/shedaniel/lightoverlay/common/ClothScreen.java b/common/src/main/java/me/shedaniel/lightoverlay/common/ClothScreen.java index 1a71dca..5812d2f 100644 --- a/common/src/main/java/me/shedaniel/lightoverlay/common/ClothScreen.java +++ b/common/src/main/java/me/shedaniel/lightoverlay/common/ClothScreen.java @@ -31,10 +31,8 @@ public class ClothScreen { return Optional.empty(); }).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.startBooleanToggle(new TranslatableComponent("config.lightoverlay.mushroom"), LightOverlay.mushroom).setDefaultValue(false).setSaveConsumer(bool -> LightOverlay.mushroom = bool).build()); - general.addEntry(eb.startBooleanToggle(new TranslatableComponent("config.lightoverlay.useListWhileCaching"), LightOverlay.useListWhileCaching).setDefaultValue(true).setSaveConsumer(bool -> LightOverlay.useListWhileCaching = 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()); diff --git a/common/src/main/java/me/shedaniel/lightoverlay/common/CubicChunkPos.java b/common/src/main/java/me/shedaniel/lightoverlay/common/CubicChunkPos.java index 576724e..5c3a188 100644 --- a/common/src/main/java/me/shedaniel/lightoverlay/common/CubicChunkPos.java +++ b/common/src/main/java/me/shedaniel/lightoverlay/common/CubicChunkPos.java @@ -2,8 +2,6 @@ package me.shedaniel.lightoverlay.common; import net.minecraft.core.BlockPos; -import java.util.Objects; - public class CubicChunkPos { public final int x; public final int y; @@ -23,7 +21,7 @@ public class CubicChunkPos { public CubicChunkPos(BlockPos blockPos) { this.x = blockPos.getX() >> 4; - this.y = blockPos.getY() >> 4; + this.y = blockPos.getY() >> 5; this.z = blockPos.getZ() >> 4; } @@ -53,7 +51,7 @@ public class CubicChunkPos { } public int getMinBlockY() { - return this.y << 4; + return this.y << 5; } public int getMinBlockZ() { @@ -65,7 +63,7 @@ public class CubicChunkPos { } public int getMaxBlockY() { - return (this.y << 4) + 15; + return (this.y << 5) + 31; } public int getMaxBlockZ() { @@ -80,8 +78,17 @@ public class CubicChunkPos { return x == that.x && y == that.y && z == that.z; } + @Override + public String toString() { + return "CubicChunkPos{" + + "x=" + x + + ", y=" + y + + ", z=" + z + + '}'; + } + @Override public int hashCode() { - return Objects.hash(x, y, z); + return Long.hashCode(toLong()); } } diff --git a/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlay.java b/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlay.java index d3eb131..9d93dc4 100644 --- a/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlay.java +++ b/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlay.java @@ -1,63 +1,26 @@ package me.shedaniel.lightoverlay.common; -import com.google.common.collect.Maps; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.math.Transformation; -import it.unimi.dsi.fastutil.longs.Long2ByteMap; -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 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; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.culling.Frustum; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.BlockTags; -import net.minecraft.util.LazyLoadedValue; import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.MobCategory; -import net.minecraft.world.level.BlockGetter; -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 org.lwjgl.opengl.GL11; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; 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.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadPoolExecutor; +import java.util.Properties; +import java.util.function.Consumer; public class LightOverlay { public static final DecimalFormat FORMAT = new DecimalFormat("#.#"); - private static final String KEYBIND_CATEGORY = "key.lightoverlay.category"; - private static final ResourceLocation ENABLE_OVERLAY_KEYBIND = new ResourceLocation("lightoverlay", "enable_overlay"); public static int reach = 12; public static int crossLevel = 7; public static int secondaryLevel = -1; @@ -65,119 +28,32 @@ public class LightOverlay { public static int higherCrossLevel = -1; public static boolean caching = false; public static boolean showNumber = false; - public static boolean smoothLines = true; public static boolean underwater = false; public static boolean mushroom = false; - public static boolean useListWhileCaching = true; public static float lineWidth = 1.0F; public static int yellowColor = 0xFFFF00, redColor = 0xFF0000, secondaryColor = 0x0000FF; public static File configFile; - private static KeyMapping enableOverlay; - private static boolean enabled = false; - private static final LazyLoadedValue> TESTING_ENTITY_TYPE = new LazyLoadedValue<>(() -> - EntityType.Builder.createNothing(MobCategory.MONSTER).sized(0f, 0f).noSave().build(null)); - private static int threadNumber = 0; - public static Frustum frustum; - private static final ThreadPoolExecutor EXECUTOR = (ThreadPoolExecutor) Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), r -> { - Thread thread = new Thread(r, "light-overlay-" + threadNumber++); - thread.setDaemon(true); - return thread; - }); - private static final Set POS = Collections.synchronizedSet(new HashSet<>()); - private static final Set CALCULATING_POS = Collections.synchronizedSet(new HashSet<>()); - private static final Map CHUNK_MAP = Maps.newConcurrentMap(); - private static final Minecraft CLIENT = Minecraft.getInstance(); - private static long ticks = 0; + public static KeyMapping enableOverlay; + public static boolean enabled = false; + + public static LightOverlayTicker ticker = new LightOverlayTicker(); + public static LightOverlayRenderer renderer = new LightOverlayRenderer(ticker); public static void register() { // Load Config configFile = new File(Platform.getConfigFolder().toFile(), "lightoverlay.properties"); loadConfig(configFile); - enableOverlay = createKeyBinding(ENABLE_OVERLAY_KEYBIND, InputConstants.Type.KEYSYM, 296, KEYBIND_CATEGORY); - KeyBindings.registerKeyBinding(enableOverlay); + enableOverlay = createKeyBinding(new ResourceLocation("lightoverlay", "enable_overlay"), InputConstants.Type.KEYSYM, 296, "key.lightoverlay.category"); + KeyMappingRegistry.register(enableOverlay); - registerDebugRenderer(() -> { - if (enabled) { - LocalPlayer playerEntity = CLIENT.player; - int playerPosX = ((int) playerEntity.getX()) >> 4; - int playerPosZ = ((int) playerEntity.getZ()) >> 4; - CollisionContext collisionContext = CollisionContext.of(playerEntity); - Level world = CLIENT.level; - BlockPos playerPos = new BlockPos(playerEntity.getX(), playerEntity.getY(), playerEntity.getZ()); - Camera camera = CLIENT.gameRenderer.getMainCamera(); - - if (showNumber) { - RenderSystem.enableTexture(); - RenderSystem.depthMask(true); - BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); - BlockPos.MutableBlockPos downMutable = new BlockPos.MutableBlockPos(); - for (Map.Entry entry : CHUNK_MAP.entrySet()) { - if (caching && (Mth.abs(entry.getKey().x - playerPosX) > getChunkRange() || Mth.abs(entry.getKey().z - playerPosZ) > getChunkRange())) { - continue; - } - for (Long2ByteMap.Entry objectEntry : entry.getValue().data().long2ByteEntrySet()) { - mutable.set(BlockPos.getX(objectEntry.getLongKey()), BlockPos.getY(objectEntry.getLongKey()), BlockPos.getZ(objectEntry.getLongKey())); - if (mutable.closerThan(playerPos, reach)) { - 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()); - renderLevel(CLIENT, camera, world, mutable, downMutable, objectEntry.getByteValue(), collisionContext); - } - } - } - } - RenderSystem.enableDepthTest(); - } else { - boolean useList = useListWhileCaching && caching; - RenderSystem.enableDepthTest(); - RenderSystem.disableTexture(); - RenderSystem.enableBlend(); - RenderSystem.enableCull(); - RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); - if (smoothLines) GL11.glEnable(GL11.GL_LINE_SMOOTH); - GL11.glLineWidth(lineWidth); - if (!useList) GL11.glBegin(GL11.GL_LINES); - - BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos(); - - if (useList) GL11.glTranslated(-camera.getPosition().x, -camera.getPosition().y + .01D, -camera.getPosition().z); - for (Map.Entry entry : CHUNK_MAP.entrySet()) { - CubicChunkPos chunkPos = entry.getKey(); - if (caching && (Mth.abs(chunkPos.x - playerPosX) > getChunkRange() || Mth.abs(chunkPos.z - playerPosZ) > getChunkRange())) { - continue; - } - - if (useList) { - if (frustum == null || isFrustumVisible(frustum, chunkPos.getMinBlockX(), chunkPos.getMinBlockY(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), chunkPos.getMaxBlockY(), chunkPos.getMaxBlockZ())) { - entry.getValue().renderList(world, collisionContext); - } - } else { - for (Long2ByteMap.Entry objectEntry : entry.getValue().data().long2ByteEntrySet()) { - byte crossType = objectEntry.getByteValue(); - mutable.set(BlockPos.getX(objectEntry.getLongKey()), BlockPos.getY(objectEntry.getLongKey()), BlockPos.getZ(objectEntry.getLongKey())); - if (mutable.closerThan(playerPos, reach)) { - if (frustum == null || isFrustumVisible(frustum, mutable.getX(), mutable.getY(), mutable.getZ(), mutable.getX() + 1, mutable.getX() + 1, mutable.getX() + 1)) { - int color = crossType == CROSS_RED ? redColor : crossType == CROSS_YELLOW ? yellowColor : secondaryColor; - renderCross(camera, world, mutable, color, collisionContext); - } - } - } - } - } - - if (!useList) GL11.glEnd(); - RenderSystem.disableBlend(); - RenderSystem.enableTexture(); - if (smoothLines) GL11.glDisable(GL11.GL_LINE_SMOOTH); - } - } - }); + registerDebugRenderer(renderer); - GuiEvent.DEBUG_TEXT_LEFT.register(list -> { + ClientGuiEvent.DEBUG_TEXT_LEFT.register(list -> { if (enabled) { if (caching) { - list.add(String.format("[Light Overlay] Chunks to queue: %02d", POS.size())); + list.add(String.format("[Light Overlay] Chunks to queue: %02d", ticker.POS.size())); } else { list.add("[Light Overlay] Enabled"); } @@ -185,20 +61,9 @@ public class LightOverlay { list.add("[Light Overlay] Disabled"); } }); - ClientTickEvent.CLIENT_POST.register(LightOverlay::tick); + ClientTickEvent.CLIENT_POST.register(ticker::tick); } - private static void processChunk(CubicChunkPos pos, int playerPosX, int playerPosY, int playerPosZ, CollisionContext context) { - CALCULATING_POS.remove(pos); - if (Mth.abs(pos.x - playerPosX) > getChunkRange() || Mth.abs(pos.y - playerPosY) > 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(CubicChunkPos pos) { for (int xOffset = -1; xOffset <= 1; xOffset++) { @@ -211,137 +76,13 @@ public class LightOverlay { } public static void queueChunk(CubicChunkPos pos) { - if (enabled && caching && !CALCULATING_POS.contains(pos)) { - POS.add(pos); - } + ticker.queueChunk(pos); } public static int getChunkRange() { return Math.max(Mth.ceil(reach / 16f), 1); } - private static void calculateChunk(LevelChunk chunk, Level world, CubicChunkPos chunkPos, CollisionContext collisionContext) { - if (world != null && chunk != null) { - ChunkData chunkData = new ChunkData(); - LayerLightEventListener block = world.getLightEngine().getLayerListener(LightLayer.BLOCK); - LayerLightEventListener sky = 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(); - if (showNumber) { - int level = getCrossLevel(pos, down, chunk, block, collisionContext); - if (level >= 0) { - chunkData.data().put(pos.asLong(), (byte) level); - } - } else { - Biome biome = !mushroom ? world.getBiome(pos) : null; - byte type = getCrossType(pos, biome, down, chunk, block, sky, collisionContext); - if (type != CROSS_NONE) { - chunkData.data().put(pos.asLong(), type); - } - } - } - CHUNK_MAP.put(chunkPos, chunkData); - } else { - ChunkData data = CHUNK_MAP.remove(chunkPos); - - if (data != null) { - data.close(); - } - } - } - - public static 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); - if (!underwater && !blockUpperState.getFluidState().isEmpty()) - return CROSS_NONE; - // Check if the outline is full - if (Block.isFaceFull(upperCollisionShape, Direction.UP)) - return CROSS_NONE; - // TODO: Not to hard code no redstone - if (blockUpperState.isSignalSource()) - return CROSS_NONE; - // Check if the collision has a bump - if (upperCollisionShape.max(Direction.Axis.Y) > 0) - return CROSS_NONE; - if (blockUpperState.getBlock().is(BlockTags.RAILS)) - return CROSS_NONE; - // Check block state allow spawning (excludes bedrock and barriers automatically) - if (!blockBelowState.isValidSpawn(world, down, TESTING_ENTITY_TYPE.get())) - return CROSS_NONE; - if (!mushroom && Biome.BiomeCategory.MUSHROOM == biome.getBiomeCategory()) - return CROSS_NONE; - int blockLightLevel = block.getLightValue(pos); - int skyLightLevel = sky.getLightValue(pos); - if (blockLightLevel > higherCrossLevel) - return CROSS_NONE; - if (skyLightLevel > higherCrossLevel) - return CROSS_YELLOW; - return lowerCrossLevel >= 0 && blockLightLevel > lowerCrossLevel ? CROSS_SECONDARY : CROSS_RED; - } - - 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); - if (!underwater && !blockUpperState.getFluidState().isEmpty()) - return -1; - if (!blockBelowState.getFluidState().isEmpty()) - return -1; - if (blockBelowState.isAir()) - return -1; - if (Block.isFaceFull(upperCollisionShape, Direction.DOWN)) - return -1; - return view.getLightValue(pos); - } - - public static void renderCross(Camera camera, Level world, BlockPos pos, int color, CollisionContext collisionContext) { - double cameraX = camera.getPosition().x; - double cameraY = camera.getPosition().y - .005D; - double blockOffset = 0; - VoxelShape upperOutlineShape = world.getBlockState(pos).getShape(world, pos, collisionContext); - if (!upperOutlineShape.isEmpty()) - blockOffset += upperOutlineShape.max(Direction.Axis.Y); - double cameraZ = camera.getPosition().z; - - int red = (color >> 16) & 255; - int green = (color >> 8) & 255; - int blue = color & 255; - int x = pos.getX(); - int y = pos.getY(); - int z = pos.getZ(); - RenderSystem.color4f(red / 255f, green / 255f, blue / 255f, 1f); - GL11.glVertex3d(x + .01 - cameraX, y - cameraY + blockOffset, z + .01 - cameraZ); - GL11.glVertex3d(x - .01 + 1 - cameraX, y - cameraY + blockOffset, z - .01 + 1 - cameraZ); - GL11.glVertex3d(x - .01 + 1 - cameraX, y - cameraY + blockOffset, z + .01 - cameraZ); - GL11.glVertex3d(x + .01 - cameraX, y - cameraY + blockOffset, z - .01 + 1 - cameraZ); - } - - @SuppressWarnings("deprecation") - public static void renderLevel(Minecraft client, Camera camera, Level world, BlockPos pos, BlockPos down, byte level, CollisionContext collisionContext) { - String text = String.valueOf(level); - Font font = client.font; - double cameraX = camera.getPosition().x; - double cameraY = camera.getPosition().y; - VoxelShape upperOutlineShape = world.getBlockState(down).getShape(world, down, collisionContext); - if (!upperOutlineShape.isEmpty()) - cameraY += 1 - upperOutlineShape.max(Direction.Axis.Y); - double cameraZ = camera.getPosition().z; - RenderSystem.pushMatrix(); - RenderSystem.translatef((float) (pos.getX() + 0.5f - cameraX), (float) (pos.getY() - cameraY) + 0.005f, (float) (pos.getZ() + 0.5f - cameraZ)); - RenderSystem.rotatef(90, 1, 0, 0); - RenderSystem.normal3f(0.0F, 1.0F, 0.0F); - float size = 0.07F; - RenderSystem.scalef(-size, -size, size); - float float_3 = (float) (-font.width(text)) / 2.0F + 0.4f; - RenderSystem.enableAlphaTest(); - MultiBufferSource.BufferSource source = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder()); - font.drawInBatch(text, float_3, -3.5f, level > higherCrossLevel ? 0xff042404 : (lowerCrossLevel >= 0 && level > lowerCrossLevel ? 0xff0066ff : 0xff731111), false, Transformation.identity().getMatrix(), source, false, 0, 15728880); - source.endBatch(); - RenderSystem.popMatrix(); - } public static void loadConfig(File file) { try { @@ -359,10 +100,8 @@ public class LightOverlay { secondaryLevel = Integer.parseInt((String) properties.computeIfAbsent("secondaryLevel", a -> "-1")); caching = ((String) properties.computeIfAbsent("caching", a -> "false")).equalsIgnoreCase("true"); showNumber = ((String) properties.computeIfAbsent("showNumber", a -> "false")).equalsIgnoreCase("true"); - smoothLines = ((String) properties.computeIfAbsent("smoothLines", a -> "true")).equalsIgnoreCase("true"); underwater = ((String) properties.computeIfAbsent("underwater", a -> "false")).equalsIgnoreCase("true"); mushroom = ((String) properties.computeIfAbsent("mushroom", a -> "false")).equalsIgnoreCase("true"); - useListWhileCaching = ((String) properties.computeIfAbsent("useListWhileCaching", a -> "true")).equalsIgnoreCase("true"); lineWidth = Float.parseFloat((String) properties.computeIfAbsent("lineWidth", a -> "1")); { int r, g, b; @@ -397,10 +136,8 @@ public class LightOverlay { secondaryColor = 0x0000FF; caching = false; showNumber = false; - smoothLines = true; underwater = false; mushroom = false; - useListWhileCaching = true; try { saveConfig(file); } catch (IOException ex) { @@ -410,11 +147,8 @@ public class LightOverlay { if (secondaryLevel >= crossLevel) System.err.println("[Light Overlay] Secondary Level is higher than Cross Level"); lowerCrossLevel = Math.min(crossLevel, secondaryLevel); higherCrossLevel = Math.max(crossLevel, secondaryLevel); - for (ChunkData data : CHUNK_MAP.values()) { - data.close(); - } - CHUNK_MAP.clear(); - POS.clear(); + ticker.CHUNK_MAP.clear(); + ticker.POS.clear(); } public static void saveConfig(File file) throws IOException { @@ -431,14 +165,10 @@ public class LightOverlay { fos.write("\n".getBytes()); fos.write(("showNumber=" + showNumber).getBytes()); fos.write("\n".getBytes()); - fos.write(("smoothLines=" + smoothLines).getBytes()); - fos.write("\n".getBytes()); fos.write(("underwater=" + underwater).getBytes()); fos.write("\n".getBytes()); fos.write(("mushroom=" + mushroom).getBytes()); fos.write("\n".getBytes()); - fos.write(("useListWhileCaching=" + useListWhileCaching).getBytes()); - fos.write("\n".getBytes()); fos.write(("lineWidth=" + FORMAT.format(lineWidth)).getBytes()); fos.write("\n".getBytes()); fos.write(("yellowColorRed=" + ((yellowColor >> 16) & 255)).getBytes()); @@ -465,172 +195,15 @@ public class LightOverlay { return new KeyMapping("key." + id.getNamespace() + "." + id.getPath(), type, code, category); } - private static final LazyLoadedValue 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) { + private static void registerDebugRenderer(Consumer runnable) { try { - Class.forName("me.shedaniel.lightoverlay." + Platform.getModLoader() + ".LightOverlayImpl").getDeclaredField("debugRenderer").set(null, runnable); + Class.forName("me.shedaniel.lightoverlay." + ArchitecturyTarget.getCurrentTarget() + ".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(); - for (ChunkData data : CHUNK_MAP.values()) { - data.close(); - } - CHUNK_MAP.clear(); - } else { - LocalPlayer player = CLIENT.player; - ClientLevel world = CLIENT.level; - CollisionContext collisionContext = CollisionContext.of(player); - - if (!caching) { - CALCULATING_POS.clear(); - POS.clear(); - for (ChunkData data : CHUNK_MAP.values()) { - data.close(); - } - 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 iterate = BlockPos.betweenClosed(playerPos.getX() - reach, playerPos.getY() - reach, playerPos.getZ() - reach, - playerPos.getX() + reach, playerPos.getY() + reach, playerPos.getZ() + reach); - ChunkData chunkData = new ChunkData(); - CHUNK_MAP.put(new CubicChunkPos(0, 0, 0), chunkData); - 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) { - chunkData.data().put(blockPos.asLong(), (byte) level); - } - } else { - Biome biome = !mushroom ? world.getBiome(blockPos) : null; - byte type = getCrossType(blockPos, biome, downPos, world, block, sky, collisionContext); - if (type != CROSS_NONE) { - chunkData.data().put(blockPos.asLong(), type); - } - } - } - } else { - int playerPosX = ((int) player.getX()) >> 4; - int playerPosY = ((int) player.getY()) >> 4; - int playerPosZ = ((int) player.getZ()) >> 4; - for (int chunkX = playerPosX - getChunkRange(); chunkX <= playerPosX + getChunkRange(); chunkX++) { - for (int chunkY = Math.max(playerPosY - getChunkRange(), 0); chunkY <= playerPosY + getChunkRange() && chunkY <= 15; chunkY++) { - for (int chunkZ = playerPosZ - getChunkRange(); chunkZ <= playerPosZ + getChunkRange(); chunkZ++) { - if (Mth.abs(chunkX - playerPosX) > getChunkRange() || Mth.abs(chunkY - playerPosY) > getChunkRange() || Mth.abs(chunkZ - playerPosZ) > getChunkRange()) - continue; - CubicChunkPos chunkPos = new CubicChunkPos(chunkX, chunkY, 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; - CubicChunkPos c1 = null, c2 = null, c3 = null; - synchronized (POS) { - Iterator iterator = POS.iterator(); - while (iterator.hasNext()) { - CubicChunkPos pos = iterator.next(); - if (Mth.abs(pos.x - playerPosX) > getChunkRange() || Mth.abs(pos.y - playerPosY) > getChunkRange() || Mth.abs(pos.z - playerPosZ) > getChunkRange() || CALCULATING_POS.contains(pos)) { - iterator.remove(); - } else { - if (isFrustumVisible(frustum, pos.getMinBlockX(), pos.getMinBlockY(), pos.getMinBlockZ(), pos.getMaxBlockX(), pos.getMaxBlockY(), pos.getMaxBlockZ())) { - int i = Math.abs(pos.x - playerPosX); - int j = Math.abs(pos.y - playerPosY); - int k = Math.abs(pos.z - playerPosZ); - double distance = Math.sqrt(i * i + j * j + k * k); - 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(); - } - } - } - } - } - CubicChunkPos finalC1 = c1; - CubicChunkPos finalC2 = c2; - CubicChunkPos 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 playerPosY1 = ((int) CLIENT.player.getY()) >> 4; - int playerPosZ1 = ((int) CLIENT.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); - }); - } - } - if (ticks % 50 == 0) { - Iterator> iterator = CHUNK_MAP.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - if (Mth.abs(entry.getKey().x - playerPosX) > getChunkRange() * 2 || Mth.abs(entry.getKey().y - playerPosY) > getChunkRange() * 2 || Mth.abs(entry.getKey().z - playerPosZ) > getChunkRange() * 2) { - entry.getValue().close(); - iterator.remove(); - } - } - } - } - } - } catch (Throwable throwable) { - LogManager.getLogger().throwing(throwable); - } - } - public static final byte CROSS_YELLOW = 0; public static final byte CROSS_RED = 1; public static final byte CROSS_SECONDARY = 2; diff --git a/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayRenderer.java b/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayRenderer.java new file mode 100644 index 0000000..7204963 --- /dev/null +++ b/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayRenderer.java @@ -0,0 +1,183 @@ +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; +import net.minecraft.core.BlockPos; +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 { + private final Minecraft minecraft = Minecraft.getInstance(); + public Frustum frustum; + public LightOverlayTicker ticker; + + public LightOverlayRenderer(LightOverlayTicker ticker) { + this.ticker = ticker; + } + + @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(); + + if (LightOverlay.showNumber) { + renderLevels(new PoseStack(), camera, playerPos, playerPosX, playerPosY, playerPosZ, chunkRange, collisionContext); + } else { + renderCrosses(poses, camera, playerPos, playerPosX, playerPosY, playerPosZ, chunkRange, collisionContext); + } + } + } + + 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 entry : ticker.CHUNK_MAP.entrySet()) { + CubicChunkPos 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()) { + 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)) { + downMutable.set(mutable.getX(), mutable.getY() - 1, mutable.getZ()); + renderLevel(poses, source, camera, minecraft.level, mutable, downMutable, objectEntry.getByteValue(), collisionContext); + } + } + } + } + RenderSystem.enableDepthTest(); + source.endBatch(); + } + + 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); + if (!upperOutlineShape.isEmpty()) + cameraY += 1 - upperOutlineShape.max(Direction.Axis.Y); + double 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; + poses.scale(-size, -size, size); + float 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(); + } + + private void renderCrosses(PoseStack poses, Camera camera, BlockPos playerPos, int playerPosX, int playerPosY, int playerPosZ, int chunkRange, CollisionContext collisionContext) { + RenderSystem.enableDepthTest(); + RenderSystem.disableTexture(); + RenderSystem.disableBlend(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + RenderSystem.lineWidth(LightOverlay.lineWidth); + Tesselator tesselator = Tesselator.getInstance(); + BufferBuilder 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 entry : ticker.CHUNK_MAP.entrySet()) { + CubicChunkPos 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(); + 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) { + case LightOverlay.CROSS_RED -> LightOverlay.redColor; + case LightOverlay.CROSS_YELLOW -> LightOverlay.yellowColor; + default -> LightOverlay.secondaryColor; + }; + renderCross(poses.last().pose(), builder, camera, minecraft.level, mutable, color, collisionContext); + } + } + } + } + + tesselator.end(); + RenderSystem.lineWidth(1.0F); + RenderSystem.enableBlend(); + RenderSystem.enableTexture(); + } + + 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; + double blockOffset = 0; + VoxelShape upperOutlineShape = world.getBlockState(pos).getShape(world, pos, collisionContext); + if (!upperOutlineShape.isEmpty()) { + blockOffset += upperOutlineShape.max(Direction.Axis.Y); + } + double 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; + 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 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); + } catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + } +} diff --git a/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayTicker.java b/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayTicker.java new file mode 100644 index 0000000..fd0fe17 --- /dev/null +++ b/common/src/main/java/me/shedaniel/lightoverlay/common/LightOverlayTicker.java @@ -0,0 +1,272 @@ +package me.shedaniel.lightoverlay.common; + +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; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.BlockGetter; +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.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.function.Supplier; + +public class LightOverlayTicker { + private final Minecraft minecraft = Minecraft.getInstance(); + 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++); + thread.setDaemon(true); + return thread; + }); + public final Set POS = Collections.synchronizedSet(new HashSet<>()); + public final Set CALCULATING_POS = Collections.synchronizedSet(new HashSet<>()); + public final Map CHUNK_MAP = Maps.newConcurrentMap(); + private static final Supplier> TESTING_ENTITY_TYPE = Suppliers.memoize(() -> + EntityType.Builder.createNothing(MobCategory.MONSTER).sized(0f, 0f).noSave().build(null)); + + public void queueChunk(CubicChunkPos pos) { + if (LightOverlay.enabled && LightOverlay.caching && !CALCULATING_POS.contains(pos)) { + POS.add(pos); + } + } + + public void tick(Minecraft minecraft) { + while (LightOverlay.enableOverlay.consumeClick()) + LightOverlay.enabled = !LightOverlay.enabled; + + try { + ticks++; + if (minecraft.player == null || !LightOverlay.enabled) { + POS.clear(); + CALCULATING_POS.clear(); + EXECUTOR.getQueue().clear(); + CHUNK_MAP.clear(); + } else { + LocalPlayer player = minecraft.player; + ClientLevel world = minecraft.level; + CollisionContext 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 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) { + downPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ()); + if (LightOverlay.showNumber) { + int 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); + if (type != LightOverlay.CROSS_NONE) { + chunkData.put(blockPos.asLong(), type); + } + } + } + } 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 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++) { + if (Mth.abs(chunkX - playerPosX) > chunkRange || Mth.abs(chunkY - playerPosY) > chunkRange || Mth.abs(chunkZ - playerPosZ) > chunkRange) + continue; + CubicChunkPos chunkPos = new CubicChunkPos(chunkX, chunkY, 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; + CubicChunkPos c1 = null, c2 = null, c3 = null; + synchronized (POS) { + Iterator iterator = POS.iterator(); + while (iterator.hasNext()) { + CubicChunkPos 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); + if (distance < d1) { + d3 = d2; + d2 = d1; + d1 = distance; + c3 = c2; + c2 = c1; + c1 = pos; + } else if (distance < d2) { + d3 = d2; + d2 = distance; + c3 = c2; + c2 = pos; + } else if (distance < d3) { + d3 = distance; + c3 = pos; + } + } + } + } + } + CubicChunkPos finalC1 = c1; + CubicChunkPos finalC2 = c2; + CubicChunkPos finalC3 = c3; + if (finalC1 != null) { + CALCULATING_POS.add(finalC1); + POS.remove(finalC1); + if (finalC2 != null) { + CALCULATING_POS.add(finalC2); + POS.remove(finalC2); + if (finalC3 != null) { + CALCULATING_POS.add(finalC3); + POS.remove(finalC3); + } + } + 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); + }); + } + } + if (ticks % 50 == 0) { + CHUNK_MAP.entrySet().removeIf(entry -> Mth.abs(entry.getKey().x - playerPosX) > chunkRange * 2 || Mth.abs(entry.getKey().y - playerPosY) > chunkRange * 2 || Mth.abs(entry.getKey().z - playerPosZ) > chunkRange * 2); + } + } + } + } catch (Throwable throwable) { + LogManager.getLogger().throwing(throwable); + } + } + + private void processChunk(CubicChunkPos pos, int playerPosX, int playerPosY, int playerPosZ, CollisionContext context) { + CALCULATING_POS.remove(pos); + int 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; + } + try { + calculateChunk(minecraft.level.getChunkSource().getChunk(pos.x, pos.z, ChunkStatus.FULL, false), minecraft.level, pos, context); + } catch (Throwable throwable) { + LogManager.getLogger().throwing(throwable); + } + } + + private void 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(); + if (LightOverlay.showNumber) { + int 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); + if (type != LightOverlay.CROSS_NONE) { + chunkData.put(pos.asLong(), type); + } + } + } + CHUNK_MAP.put(chunkPos, chunkData); + } else { + CHUNK_MAP.remove(chunkPos); + } + } + + 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); + if (!LightOverlay.underwater && !blockUpperState.getFluidState().isEmpty()) + return LightOverlay.CROSS_NONE; + // Check if the outline is full + if (Block.isFaceFull(upperCollisionShape, Direction.UP)) + return LightOverlay.CROSS_NONE; + // TODO: Not to hard code no redstone + if (blockUpperState.isSignalSource()) + return LightOverlay.CROSS_NONE; + // Check if the collision has a bump + if (upperCollisionShape.max(Direction.Axis.Y) > 0) + return LightOverlay.CROSS_NONE; + if (blockUpperState.is(BlockTags.RAILS)) + return LightOverlay.CROSS_NONE; + // Check block state allow spawning (excludes bedrock and barriers automatically) + if (!blockBelowState.isValidSpawn(world, down, TESTING_ENTITY_TYPE.get())) + 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); + if (blockLightLevel > LightOverlay.higherCrossLevel) + return LightOverlay.CROSS_NONE; + if (skyLightLevel > LightOverlay.higherCrossLevel) + return LightOverlay.CROSS_YELLOW; + return LightOverlay.lowerCrossLevel >= 0 && blockLightLevel > LightOverlay.lowerCrossLevel ? LightOverlay.CROSS_SECONDARY : LightOverlay.CROSS_RED; + } + + 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); + if (!LightOverlay.underwater && !blockUpperState.getFluidState().isEmpty()) + return -1; + if (!blockBelowState.getFluidState().isEmpty()) + return -1; + if (blockBelowState.isAir()) + return -1; + if (Block.isFaceFull(upperCollisionShape, Direction.DOWN)) + return -1; + return view.getLightValue(pos); + } +} diff --git a/fabric/build.gradle b/fabric/build.gradle index b8a902a..72e531b 100755 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,5 +1,5 @@ plugins { - id "com.github.johnrengelman.shadow" version "5.0.0" + id "com.github.johnrengelman.shadow" version "7.0.0" } minecraft { @@ -7,7 +7,6 @@ minecraft { } architectury { - transformerVersion = "2.0.9999" platformSetupLoomIde() fabric() } @@ -20,26 +19,22 @@ processResources { } configurations { - shadow -} - -repositories { - mavenLocal() + shadowCommon } dependencies { minecraft "com.mojang:minecraft:${rootProject.architectury.minecraft}" mappings minecraft.officialMojangMappings() - modCompile "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" + modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" - modCompile "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" + modImplementation "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" modImplementation("me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_config_version}") { exclude(group: "net.fabricmc.fabric-api") } - modImplementation("io.github.prospector:modmenu:${rootProject.modmenu_version}") { + modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive = false } - modCompile("me.shedaniel:architectury:${rootProject.architectury_version}:fabric") + modImplementation("dev.architectury:architectury-fabric:${rootProject.architectury_version}") implementation(project(path: ":common")) { transitive = false @@ -47,15 +42,13 @@ dependencies { developmentFabric(project(path: ":common")) { transitive = false } - shadow(project(path: ":common", configuration: "transformProductionFabric")) { + shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive = false } } shadowJar { - relocate "me.shedaniel.lightoverlay.common", "me.shedaniel.lightoverlay.common.fabric" - - configurations = [project.configurations.shadow] + configurations = [project.configurations.shadowCommon] classifier "shadow" } diff --git a/fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LightOverlayImpl.java b/fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LightOverlayImpl.java index 56ba706..58cd0f7 100644 --- a/fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LightOverlayImpl.java +++ b/fabric/src/main/java/me/shedaniel/lightoverlay/fabric/LightOverlayImpl.java @@ -1,16 +1,19 @@ 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 Runnable debugRenderer = () -> {}; + public static Consumer debugRenderer = poses -> {}; public static void init() { LightOverlay.register(); - WorldRenderEvents.AFTER_SETUP.register(context -> LightOverlay.frustum = context.frustum()); - WorldRenderEvents.BEFORE_DEBUG_RENDER.register(context -> debugRenderer.run()); + 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) { diff --git a/fabric/src/main/java/me/shedaniel/lightoverlay/fabric/mixin/MixinClientConnection.java b/fabric/src/main/java/me/shedaniel/lightoverlay/fabric/mixin/MixinClientConnection.java index ac553e6..446f8af 100644 --- a/fabric/src/main/java/me/shedaniel/lightoverlay/fabric/mixin/MixinClientConnection.java +++ b/fabric/src/main/java/me/shedaniel/lightoverlay/fabric/mixin/MixinClientConnection.java @@ -2,6 +2,7 @@ package me.shedaniel.lightoverlay.fabric.mixin; import me.shedaniel.lightoverlay.common.CubicChunkPos; import me.shedaniel.lightoverlay.common.LightOverlay; +import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.network.Connection; import net.minecraft.network.PacketListener; import net.minecraft.network.protocol.Packet; @@ -9,6 +10,7 @@ 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.util.Mth; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -17,21 +19,30 @@ 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 CubicChunkPos(((ClientboundBlockUpdatePacket) packet).getPos())); - } else if (packet instanceof ClientboundSetChunkCacheCenterPacket) { - for (int y = 0; y <= 15; y++) { - LightOverlay.queueChunkAndNear(new CubicChunkPos(((ClientboundSetChunkCacheCenterPacket) packet).getX(), y, ((ClientboundSetChunkCacheCenterPacket) packet).getZ())); - } - } else if (packet instanceof ClientboundSectionBlocksUpdatePacket) { - for (int y = 0; y <= 15; y++) { - LightOverlay.queueChunkAndNear(new CubicChunkPos(((ClientboundSectionBlocksUpdatePacket) packet).sectionPos.getX(), y, ((ClientboundSectionBlocksUpdatePacket) packet).sectionPos.getZ())); - } - } else if (packet instanceof ClientboundLightUpdatePacket) { - for (int y = 0; y <= 15; y++) { - LightOverlay.queueChunk(new CubicChunkPos(((ClientboundLightUpdatePacket) packet).getX(), y, ((ClientboundLightUpdatePacket) packet).getZ())); + private static void handlePacket(Packet packet, PacketListener listener, CallbackInfo ci) { + try { + if (!(listener instanceof ClientPacketListener packetListener)) return; + var level = packetListener.getLevel(); + if (level == null) return; + if (packet instanceof ClientboundBlockUpdatePacket p) { + LightOverlay.queueChunkAndNear(new CubicChunkPos(p.getPos())); + } 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++) { + LightOverlay.queueChunkAndNear(new CubicChunkPos(p.getX(), y, p.getZ())); + } + } else if (packet instanceof ClientboundSectionBlocksUpdatePacket p) { + LightOverlay.queueChunkAndNear(new CubicChunkPos(p.sectionPos.getX(), p.sectionPos.getY() >> 1, p.sectionPos.getZ())); + } 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++) { + LightOverlay.queueChunk(new CubicChunkPos(p.getX(), y, p.getZ())); + } } + } catch (Throwable throwable) { + new RuntimeException("Light Overlay failed to process packet", throwable).printStackTrace(); } } } diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 93a18f6..504209a 100755 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -32,7 +32,7 @@ }, "depends": { "fabric": ">=0.29.1", - "architectury": ">=1.5.112", - "cloth-config2": ">=4.10.13" + "architectury": ">=2-", + "cloth-config2": ">=5-" } } diff --git a/forge/build.gradle b/forge/build.gradle index 95ece2e..fe2097e 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -7,7 +7,6 @@ configurations { } architectury { - transformerVersion = "2.0.9999" platformSetupLoomIde() forge() } @@ -23,10 +22,6 @@ processResources { inputs.property "META-INF/mods.toml", project.version } -repositories { - mavenLocal() -} - dependencies { minecraft("com.mojang:minecraft:${rootProject.architectury.minecraft}") mappings(minecraft.officialMojangMappings()) diff --git a/gradle.properties b/gradle.properties index 7e2573d..b18dc03 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,16 +1,16 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -mod_version=5.8.1 -minecraft_version=1.16.4 +mod_version=6.0.0 +minecraft_version=1.17 -architectury_version=1.5.112 +architectury_version=2.0.9 # fabric -fabric_loader_version=0.10.8 -fabric_api_version=0.29.1+1.16 -cloth_config_version=4.10.13 -modmenu_version=1.14.6+build.31 +fabric_loader_version=0.11.6 +fabric_api_version=0.35.1+1.17 +cloth_config_version=5.0.34 +modmenu_version=2.0.2 # forge forge_version=35.1.7 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c4bb5b2..d16afa0 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle index a232ac9..323a92b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,5 +11,5 @@ rootProject.name = "light-overlay" include("common") include("fabric") -include("forge") +//include("forge")