diff --git a/demo/src/main/java/net/minestom/demo/Main.java b/demo/src/main/java/net/minestom/demo/Main.java index 47ce1547c..8b2e5cb5a 100644 --- a/demo/src/main/java/net/minestom/demo/Main.java +++ b/demo/src/main/java/net/minestom/demo/Main.java @@ -72,6 +72,7 @@ public class Main { commandManager.register(new ConfigCommand()); commandManager.register(new SidebarCommand()); commandManager.register(new SetEntityType()); + commandManager.register(new RelightCommand()); commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED))); diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index b2be49f23..cfedb7f39 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -166,8 +166,16 @@ public class PlayerInit { InstanceManager instanceManager = MinecraftServer.getInstanceManager(); InstanceContainer instanceContainer = instanceManager.createInstanceContainer(DimensionType.OVERWORLD); - instanceContainer.setGenerator(unit -> unit.modifier().fillHeight(0, 40, Block.STONE)); + instanceContainer.setGenerator(unit -> { + unit.modifier().fillHeight(0, 40, Block.STONE); + + if (unit.absoluteStart().blockY() < 40 && unit.absoluteEnd().blockY() > 40) { + unit.modifier().setBlock(unit.absoluteStart().blockX(), 40, unit.absoluteStart().blockZ(), Block.TORCH); + } + }); instanceContainer.setChunkSupplier(LightingChunk::new); + instanceContainer.setTimeRate(0); + instanceContainer.setTime(18000); // var i2 = new InstanceContainer(UUID.randomUUID(), DimensionType.OVERWORLD, null, NamespaceID.from("minestom:demo")); // instanceManager.registerInstance(i2); @@ -181,6 +189,8 @@ public class PlayerInit { // CompletableFuture.runAsync(() -> { // CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join(); // System.out.println("load end"); + // LightingChunk.relight(instanceContainer, instanceContainer.getChunks()); + // System.out.println("light end"); // }); inventory = new Inventory(InventoryType.CHEST_1_ROW, Component.text("Test inventory")); diff --git a/demo/src/main/java/net/minestom/demo/commands/RelightCommand.java b/demo/src/main/java/net/minestom/demo/commands/RelightCommand.java new file mode 100644 index 000000000..59478c8ef --- /dev/null +++ b/demo/src/main/java/net/minestom/demo/commands/RelightCommand.java @@ -0,0 +1,21 @@ +package net.minestom.demo.commands; + +import net.minestom.server.command.builder.Command; +import net.minestom.server.entity.Player; +import net.minestom.server.instance.LightingChunk; + +public class RelightCommand extends Command { + public RelightCommand() { + super("relight"); + setDefaultExecutor((source, args) -> { + if (source instanceof Player player) { + long start = System.currentTimeMillis(); + source.sendMessage("Relighting..."); + LightingChunk.relight(player.getInstance(), player.getInstance().getChunks()); + source.sendMessage("Relighted " + player.getInstance().getChunks().size() + " chunks in " + (System.currentTimeMillis() - start) + "ms"); + player.getInstance().getChunks().forEach(chunk -> chunk.sendChunk(player)); + source.sendMessage("Chunks Received"); + } + }); + } +} diff --git a/src/main/java/net/minestom/server/instance/DynamicChunk.java b/src/main/java/net/minestom/server/instance/DynamicChunk.java index 41cf928dc..baf3f03c3 100644 --- a/src/main/java/net/minestom/server/instance/DynamicChunk.java +++ b/src/main/java/net/minestom/server/instance/DynamicChunk.java @@ -210,24 +210,7 @@ public class DynamicChunk extends Chunk { } private @NotNull ChunkDataPacket createChunkPacket() { - final NBTCompound heightmapsNBT; - // TODO: don't hardcode heightmaps - // Heightmap - { - int dimensionHeight = getInstance().getDimensionType().getHeight(); - int[] motionBlocking = new int[16 * 16]; - int[] worldSurface = new int[16 * 16]; - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - motionBlocking[x + z * 16] = 0; - worldSurface[x + z * 16] = dimensionHeight - 1; - } - } - final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight); - heightmapsNBT = NBT.Compound(Map.of( - "MOTION_BLOCKING", NBT.LongArray(encodeBlocks(motionBlocking, bitsForHeight)), - "WORLD_SURFACE", NBT.LongArray(encodeBlocks(worldSurface, bitsForHeight)))); - } + final NBTCompound heightmapsNBT = computeHeightmap(); // Data final byte[] data; @@ -238,44 +221,35 @@ public class DynamicChunk extends Chunk { })); } - if (this instanceof LightingChunk light) { - if (light.lightCache.isValid()) { - return new ChunkDataPacket(chunkX, chunkZ, - new ChunkData(heightmapsNBT, data, entries), - createLightData(true)); - } else { - // System.out.println("Regenerating light for chunk " + chunkX + " " + chunkZ); - LightingChunk.updateAfterGeneration(light); - return new ChunkDataPacket(chunkX, chunkZ, - new ChunkData(heightmapsNBT, data, entries), - createEmptyLight()); - } - } - return new ChunkDataPacket(chunkX, chunkZ, new ChunkData(heightmapsNBT, data, entries), - createLightData(true) + createLightData() ); } + protected NBTCompound computeHeightmap() { + // TODO: don't hardcode heightmaps + // Heightmap + int dimensionHeight = getInstance().getDimensionType().getHeight(); + int[] motionBlocking = new int[16 * 16]; + int[] worldSurface = new int[16 * 16]; + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + motionBlocking[x + z * 16] = 0; + worldSurface[x + z * 16] = dimensionHeight - 1; + } + } + final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight); + return NBT.Compound(Map.of( + "MOTION_BLOCKING", NBT.LongArray(encodeBlocks(motionBlocking, bitsForHeight)), + "WORLD_SURFACE", NBT.LongArray(encodeBlocks(worldSurface, bitsForHeight)))); + } + @NotNull UpdateLightPacket createLightPacket() { - return new UpdateLightPacket(chunkX, chunkZ, createLightData(false)); + return new UpdateLightPacket(chunkX, chunkZ, createLightData()); } - private LightData createEmptyLight() { - BitSet skyMask = new BitSet(); - BitSet blockMask = new BitSet(); - BitSet emptySkyMask = new BitSet(); - BitSet emptyBlockMask = new BitSet(); - List skyLights = new ArrayList<>(); - List blockLights = new ArrayList<>(); - - return new LightData(skyMask, blockMask, - emptySkyMask, emptyBlockMask, - skyLights, blockLights); - } - - protected LightData createLightData(boolean sendLater) { + protected LightData createLightData() { BitSet skyMask = new BitSet(); BitSet blockMask = new BitSet(); BitSet emptySkyMask = new BitSet(); @@ -346,7 +320,7 @@ public class DynamicChunk extends Chunk { 70409299, 70409299, 0, 69273666, 69273666, 0, 68174084, 68174084, 0, Integer.MIN_VALUE, 0, 5}; - private static long[] encodeBlocks(int[] blocks, int bitsPerEntry) { + static long[] encodeBlocks(int[] blocks, int bitsPerEntry) { final long maxEntryValue = (1L << bitsPerEntry) - 1; final char valuesPerLong = (char) (64 / bitsPerEntry); final int magicIndex = 3 * (valuesPerLong - 1); diff --git a/src/main/java/net/minestom/server/instance/LightingChunk.java b/src/main/java/net/minestom/server/instance/LightingChunk.java index dbfb8be1e..dc992db86 100644 --- a/src/main/java/net/minestom/server/instance/LightingChunk.java +++ b/src/main/java/net/minestom/server/instance/LightingChunk.java @@ -1,7 +1,5 @@ package net.minestom.server.instance; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import it.unimi.dsi.fastutil.longs.LongSet; import net.minestom.server.MinecraftServer; import net.minestom.server.ServerFlag; import net.minestom.server.collision.Shape; @@ -13,21 +11,22 @@ import net.minestom.server.instance.block.BlockHandler; import net.minestom.server.instance.light.Light; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.server.CachedPacket; +import net.minestom.server.network.packet.server.ServerPacket; +import net.minestom.server.network.packet.server.play.UpdateLightPacket; import net.minestom.server.network.packet.server.play.data.LightData; -import net.minestom.server.timer.ExecutionType; -import net.minestom.server.timer.Task; -import net.minestom.server.timer.TaskSchedule; +import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBT; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; import static net.minestom.server.instance.light.LightCompute.emptyContent; @@ -37,8 +36,9 @@ public class LightingChunk extends DynamicChunk { private int[] heightmap; final CachedPacket lightCache = new CachedPacket(this::createLightPacket); - boolean sendNeighbours = true; boolean chunkLoaded = false; + private int highestBlock; + private boolean initialLightingSent = false; enum LightType { SKY, @@ -132,17 +132,32 @@ public class LightingChunk extends DynamicChunk { @Override protected void onLoad() { - // Prefetch the chunk packet so that lazy lighting is computed chunkLoaded = true; - updateAfterGeneration(this); } - public int[] calculateHeightMap() { + public boolean isLightingCalculated() { + return initialLightingSent; + } + + @Override + protected NBTCompound computeHeightmap() { + // Heightmap + int[] heightmap = getHeightmap(); + int dimensionHeight = getInstance().getDimensionType().getHeight(); + final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight); + return NBT.Compound(Map.of( + "MOTION_BLOCKING", NBT.LongArray(encodeBlocks(heightmap, bitsForHeight)), + "WORLD_SURFACE", NBT.LongArray(encodeBlocks(heightmap, bitsForHeight)))); + } + + // Lazy compute heightmap + public int[] getHeightmap() { if (this.heightmap != null) return this.heightmap; var heightmap = new int[CHUNK_SIZE_X * CHUNK_SIZE_Z]; int minY = instance.getDimensionType().getMinY(); int maxY = instance.getDimensionType().getMinY() + instance.getDimensionType().getHeight(); + highestBlock = minY; synchronized (this) { for (int x = 0; x < CHUNK_SIZE_X; x++) { @@ -154,6 +169,7 @@ public class LightingChunk extends DynamicChunk { height--; } heightmap[z << 4 | x] = (height + 1); + if (height > highestBlock) highestBlock = height; } } } @@ -163,7 +179,12 @@ public class LightingChunk extends DynamicChunk { } @Override - protected LightData createLightData(boolean sendLater) { + protected LightData createLightData() { + if (lightCache.isValid()) { + ServerPacket packet = lightCache.packet(ConnectionState.PLAY); + return ((UpdateLightPacket) packet).lightData(); + } + synchronized (lightCache) { BitSet skyMask = new BitSet(); BitSet blockMask = new BitSet(); @@ -172,20 +193,25 @@ public class LightingChunk extends DynamicChunk { List skyLights = new ArrayList<>(); List blockLights = new ArrayList<>(); + Set combined = new HashSet<>(); + int chunkMin = instance.getDimensionType().getMinY(); + int index = 0; for (Section section : sections) { boolean wasUpdatedBlock = false; boolean wasUpdatedSky = false; if (section.blockLight().requiresUpdate()) { - relightSection(instance, this.chunkX, index + minSection, chunkZ, LightType.BLOCK); + var needsSend = relightSection(instance, this.chunkX, index + minSection, chunkZ, LightType.BLOCK); + combined.addAll(needsSend); wasUpdatedBlock = true; } else if (section.blockLight().requiresSend()) { wasUpdatedBlock = true; } if (section.skyLight().requiresUpdate()) { - relightSection(instance, this.chunkX, index + minSection, chunkZ, LightType.SKY); + var needsSend = relightSection(instance, this.chunkX, index + minSection, chunkZ, LightType.SKY); + combined.addAll(needsSend); wasUpdatedSky = true; } else if (section.skyLight().requiresSend()) { wasUpdatedSky = true; @@ -195,8 +221,9 @@ public class LightingChunk extends DynamicChunk { final byte[] skyLight = section.skyLight().array(); final byte[] blockLight = section.blockLight().array(); + final int sectionMaxY = index * 16 + chunkMin; - if ((wasUpdatedSky || sendLater) && this.instance.getDimensionType().isSkylightEnabled()) { + if ((wasUpdatedSky) && this.instance.getDimensionType().isSkylightEnabled() && sectionMaxY <= (highestBlock + 16)) { if (skyLight.length != 0 && skyLight != emptyContent) { skyLights.add(skyLight); skyMask.set(index); @@ -205,7 +232,7 @@ public class LightingChunk extends DynamicChunk { } } - if (wasUpdatedBlock || sendLater) { + if (wasUpdatedBlock) { if (blockLight.length != 0 && blockLight != emptyContent) { blockLights.add(blockLight); blockMask.set(index); @@ -215,10 +242,27 @@ public class LightingChunk extends DynamicChunk { } } - if (sendNeighbours) { - updateAfterGeneration(this); - sendNeighbours = false; - } + MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { + for (Chunk chunk : combined) { + if (chunk instanceof LightingChunk light) { + if (light.initialLightingSent) { + light.lightCache.invalidate(); + light.chunkCache.invalidate(); + + // Compute Lighting. This will ensure lighting is computed even with no players + lightCache.body(ConnectionState.PLAY); + light.sendLighting(); + + light.sections.forEach(s -> { + s.blockLight().setRequiresSend(true); + s.skyLight().setRequiresSend(true); + }); + } + } + } + + this.initialLightingSent = true; + }); return new LightData(skyMask, blockMask, emptySkyMask, emptyBlockMask, @@ -226,100 +270,23 @@ public class LightingChunk extends DynamicChunk { } } - private static final LongSet queuedChunks = new LongOpenHashSet(); - private static final List sendQueue = new ArrayList<>(); - private static Task sendingTask = null; - private static final ReentrantLock lightLock = new ReentrantLock(); - private static final ReentrantLock queueLock = new ReentrantLock(); - - static void updateAfterGeneration(LightingChunk chunk) { - for (int i = -1; i <= 1; i++) { - for (int j = -1; j <= 1; j++) { - Chunk neighborChunk = chunk.instance.getChunk(chunk.chunkX + i, chunk.chunkZ + j); - if (neighborChunk == null) continue; - - if (neighborChunk instanceof LightingChunk lightingChunk) { - queueLock.lock(); - - if (queuedChunks.add(ChunkUtils.getChunkIndex(lightingChunk.chunkX, lightingChunk.chunkZ))) { - sendQueue.add(lightingChunk); - } - queueLock.unlock(); - } - } - } - - lightLock.lock(); - if (sendingTask != null) { - lightLock.unlock(); - return; - } - - sendingTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> { - queueLock.lock(); - var copy = new ArrayList<>(sendQueue); - sendQueue.clear(); - queuedChunks.clear(); - queueLock.unlock(); - - // if (copy.size() != 0) { - // System.out.println("Sending lighting for " + copy.size() + " chunks"); - // } - - int count = 0; - - for (LightingChunk f : copy) { - f.sections.forEach(s -> { - s.blockLight().invalidate(); - s.skyLight().invalidate(); - }); - f.chunkCache.invalidate(); - f.lightCache.invalidate(); - } - - // Load all the lighting - for (LightingChunk f : copy) { - if (f.isLoaded()) { - f.lightCache.body(ConnectionState.PLAY); - } - } - - // Send it slowly - for (LightingChunk f : copy) { - if (f.isLoaded()) { - f.sendLighting(); - if (f.getViewers().size() == 0) continue; - } - count++; - - if (count % ServerFlag.LIGHTING_CHUNKS_PER_SEND == 0) { - // System.out.println("Sent " + count + " lighting chunks " + (count * 100 / copy.size()) + "%"); - try { - Thread.sleep(ServerFlag.LIGHTING_CHUNKS_SEND_DELAY); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - }, TaskSchedule.immediate(), TaskSchedule.tick(20), ExecutionType.ASYNC); - lightLock.unlock(); - } - - private static void flushQueue(Instance instance, Set queue, LightType type, QueueType queueType) { - AtomicInteger count = new AtomicInteger(0); + private static Set flushQueue(Instance instance, Set queue, LightType type, QueueType queueType) { Set sections = ConcurrentHashMap.newKeySet(); Set newQueue = ConcurrentHashMap.newKeySet(); + Set responseChunks = ConcurrentHashMap.newKeySet(); + List> tasks = new ArrayList<>(); + for (Point point : queue) { Chunk chunk = instance.getChunk(point.blockX(), point.blockZ()); - if (chunk == null) { - count.getAndIncrement(); - continue; - } + if (chunk == null) continue; - var light = type == LightType.BLOCK ? chunk.getSection(point.blockY()).blockLight() : chunk.getSection(point.blockY()).skyLight(); + var section = chunk.getSection(point.blockY()); + responseChunks.add(chunk); - pool.submit(() -> { + var light = type == LightType.BLOCK ? section.blockLight() : section.skyLight(); + + CompletableFuture task = CompletableFuture.runAsync(() -> { if (queueType == QueueType.INTERNAL) light.calculateInternal(instance, chunk.getChunkX(), point.blockY(), chunk.getChunkZ()); else light.calculateExternal(instance, chunk, point.blockY()); @@ -327,16 +294,19 @@ public class LightingChunk extends DynamicChunk { var toAdd = light.flip(); if (toAdd != null) newQueue.addAll(toAdd); + }, pool); - count.incrementAndGet(); - }); + tasks.add(task); } - while (count.get() < queue.size()) { } + tasks.forEach(CompletableFuture::join); - if (newQueue.size() > 0) { - flushQueue(instance, newQueue, type, QueueType.EXTERNAL); + if (!newQueue.isEmpty()) { + var newResponse = flushQueue(instance, newQueue, type, QueueType.EXTERNAL); + responseChunks.addAll(newResponse); } + + return responseChunks; } public static void relight(Instance instance, Collection chunks) { @@ -345,10 +315,12 @@ public class LightingChunk extends DynamicChunk { for (Chunk chunk : chunks) { if (chunk == null) continue; for (int section = chunk.minSection; section < chunk.maxSection; section++) { - chunk.getSection(section).blockLight().invalidate(); - chunk.getSection(section).skyLight().invalidate(); + if (chunk instanceof LightingChunk) { + chunk.getSection(section).blockLight().invalidate(); + chunk.getSection(section).skyLight().invalidate(); - sections.add(new Vec(chunk.getChunkX(), section, chunk.getChunkZ())); + sections.add(new Vec(chunk.getChunkX(), section, chunk.getChunkZ())); + } } } @@ -358,10 +330,23 @@ public class LightingChunk extends DynamicChunk { } } - private static Set getNearbyRequired(Instance instance, Point point) { + private static Set getNearbyRequired(Instance instance, Point point, LightType type) { Set collected = new HashSet<>(); collected.add(point); + int highestRegionPoint = instance.getDimensionType().getMinY(); + + for (int x = point.blockX() - 1; x <= point.blockX() + 1; x++) { + for (int z = point.blockZ() - 1; z <= point.blockZ() + 1; z++) { + Chunk chunkCheck = instance.getChunk(x, z); + if (chunkCheck == null) continue; + + if (chunkCheck instanceof LightingChunk lighting) { + if (lighting.highestBlock > highestRegionPoint) highestRegionPoint = lighting.highestBlock; + } + } + } + for (int x = point.blockX() - 1; x <= point.blockX() + 1; x++) { for (int z = point.blockZ() - 1; z <= point.blockZ() + 1; z++) { Chunk chunkCheck = instance.getChunk(x, z); @@ -369,6 +354,8 @@ public class LightingChunk extends DynamicChunk { for (int y = point.blockY() - 1; y <= point.blockY() + 1; y++) { Point sectionPosition = new Vec(x, y, z); + int sectionHeight = instance.getDimensionType().getMinY() + 16 * y; + if ((sectionHeight + 16) > highestRegionPoint && type == LightType.SKY) continue; if (sectionPosition.blockY() < chunkCheck.getMaxSection() && sectionPosition.blockY() >= chunkCheck.getMinSection()) { Section s = chunkCheck.getSection(sectionPosition.blockY()); @@ -383,16 +370,16 @@ public class LightingChunk extends DynamicChunk { return collected; } - private static Set collectRequiredNearby(Instance instance, Point point) { + private static Set collectRequiredNearby(Instance instance, Point point, LightType type) { final Set found = new HashSet<>(); final ArrayDeque toCheck = new ArrayDeque<>(); toCheck.add(point); found.add(point); - while (toCheck.size() > 0) { + while (!toCheck.isEmpty()) { final Point current = toCheck.poll(); - final Set nearby = getNearbyRequired(instance, current); + final Set nearby = getNearbyRequired(instance, current, type); nearby.forEach(p -> { if (!found.contains(p)) { found.add(p); @@ -404,25 +391,24 @@ public class LightingChunk extends DynamicChunk { return found; } - static void relightSection(Instance instance, int chunkX, int sectionY, int chunkZ) { - relightSection(instance, chunkX, sectionY, chunkZ, LightType.BLOCK); - relightSection(instance, chunkX, sectionY, chunkZ, LightType.SKY); + static Set relightSection(Instance instance, int chunkX, int sectionY, int chunkZ) { + var res = new HashSet<>(relightSection(instance, chunkX, sectionY, chunkZ, LightType.BLOCK)); + res.addAll(relightSection(instance, chunkX, sectionY, chunkZ, LightType.SKY)); + return res; } - private static void relightSection(Instance instance, int chunkX, int sectionY, int chunkZ, LightType type) { + private static Set relightSection(Instance instance, int chunkX, int sectionY, int chunkZ, LightType type) { Chunk c = instance.getChunk(chunkX, chunkZ); - if (c == null) return; + if (c == null) return Set.of(); synchronized (instance) { - Set collected = collectRequiredNearby(instance, new Vec(chunkX, sectionY, chunkZ)); - // System.out.println("Calculating " + chunkX + " " + sectionY + " " + chunkZ + " | " + collected.size() + " | " + type); - - relight(instance, collected, type); + Set collected = collectRequiredNearby(instance, new Vec(chunkX, sectionY, chunkZ), type); + return relight(instance, collected, type); } } - private static void relight(Instance instance, Set queue, LightType type) { - flushQueue(instance, queue, type, QueueType.INTERNAL); + private static Set relight(Instance instance, Set queue, LightType type) { + return flushQueue(instance, queue, type, QueueType.INTERNAL); } @Override diff --git a/src/main/java/net/minestom/server/instance/light/BlockLight.java b/src/main/java/net/minestom/server/instance/light/BlockLight.java index 779264616..02601a0e3 100644 --- a/src/main/java/net/minestom/server/instance/light/BlockLight.java +++ b/src/main/java/net/minestom/server/instance/light/BlockLight.java @@ -26,7 +26,7 @@ final class BlockLight implements Light { private byte[] contentPropagation; private byte[] contentPropagationSwap; - private boolean isValidBorders = true; + private boolean isValidBorders = false; private boolean needsSend = true; private Set toUpdateSet = new HashSet<>(); @@ -214,6 +214,11 @@ final class BlockLight implements Light { return res; } + @Override + public void setRequiresSend(boolean b) { + this.needsSend = b; + } + private void clearCache() { this.contentPropagation = null; isValidBorders = true; diff --git a/src/main/java/net/minestom/server/instance/light/Light.java b/src/main/java/net/minestom/server/instance/light/Light.java index a25f38eb8..fa4de8c84 100644 --- a/src/main/java/net/minestom/server/instance/light/Light.java +++ b/src/main/java/net/minestom/server/instance/light/Light.java @@ -27,6 +27,7 @@ public interface Light { } boolean requiresSend(); + void setRequiresSend(boolean b); @ApiStatus.Internal byte[] array(); diff --git a/src/main/java/net/minestom/server/instance/light/SkyLight.java b/src/main/java/net/minestom/server/instance/light/SkyLight.java index dd435dc58..931bc8742 100644 --- a/src/main/java/net/minestom/server/instance/light/SkyLight.java +++ b/src/main/java/net/minestom/server/instance/light/SkyLight.java @@ -14,9 +14,7 @@ import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.HashSet; -import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import static net.minestom.server.instance.light.LightCompute.*; @@ -27,7 +25,7 @@ final class SkyLight implements Light { private byte[] contentPropagation; private byte[] contentPropagationSwap; - private boolean isValidBorders = true; + private boolean isValidBorders = false; private boolean needsSend = true; private Set toUpdateSet = new HashSet<>(); @@ -59,7 +57,7 @@ final class SkyLight implements Light { ShortArrayFIFOQueue lightSources = new ShortArrayFIFOQueue(); if (c instanceof LightingChunk lc) { - int[] heightmap = lc.calculateHeightMap(); + int[] heightmap = lc.getHeightmap(); int maxY = c.getInstance().getDimensionType().getMinY() + c.getInstance().getDimensionType().getHeight(); int sectionMaxY = (sectionY + 1) * 16 - 1; int sectionMinY = sectionY * 16; @@ -240,6 +238,11 @@ final class SkyLight implements Light { return res; } + @Override + public void setRequiresSend(boolean b) { + this.needsSend = b; + } + private void clearCache() { this.contentPropagation = null; isValidBorders = true;