mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-06 16:37:38 +01:00
hollow-cube/lighting-update-2
Delay light sending, send lighting slower, fix sending multiple times
---------
Co-authored-by: mworzala <mattheworzala@gmail.com>
(cherry picked from commit 8a5c610b7b
)
This commit is contained in:
parent
4a261c365c
commit
b32146a316
@ -120,6 +120,8 @@ public class PlayerInit {
|
|||||||
var itemStack = event.getItemStack();
|
var itemStack = event.getItemStack();
|
||||||
var block = event.getInstance().getBlock(event.getPosition());
|
var block = event.getInstance().getBlock(event.getPosition());
|
||||||
|
|
||||||
|
event.getPlayer().sendMessage("MESSAGE " + ThreadLocalRandom.current().nextDouble());
|
||||||
|
|
||||||
if ("false".equals(block.getProperty("waterlogged")) && itemStack.material().equals(Material.WATER_BUCKET)) {
|
if ("false".equals(block.getProperty("waterlogged")) && itemStack.material().equals(Material.WATER_BUCKET)) {
|
||||||
block = block.withProperty("waterlogged", "true");
|
block = block.withProperty("waterlogged", "true");
|
||||||
System.out.println("SET WATERLOGGER");
|
System.out.println("SET WATERLOGGER");
|
||||||
@ -139,14 +141,14 @@ public class PlayerInit {
|
|||||||
instanceContainer.setGenerator(unit -> unit.modifier().fillHeight(0, 40, Block.STONE));
|
instanceContainer.setGenerator(unit -> unit.modifier().fillHeight(0, 40, Block.STONE));
|
||||||
instanceContainer.setChunkSupplier(LightingChunk::new);
|
instanceContainer.setChunkSupplier(LightingChunk::new);
|
||||||
|
|
||||||
System.out.println("start");
|
// System.out.println("start");
|
||||||
var chunks = new ArrayList<CompletableFuture<Chunk>>();
|
// var chunks = new ArrayList<CompletableFuture<Chunk>>();
|
||||||
ChunkUtils.forChunksInRange(0, 0, 32, (x, z) -> chunks.add(instanceContainer.loadChunk(x, z)));
|
// ChunkUtils.forChunksInRange(0, 0, 32, (x, z) -> chunks.add(instanceContainer.loadChunk(x, z)));
|
||||||
|
|
||||||
CompletableFuture.runAsync(() -> {
|
// CompletableFuture.runAsync(() -> {
|
||||||
CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join();
|
// CompletableFuture.allOf(chunks.toArray(CompletableFuture[]::new)).join();
|
||||||
System.out.println("load end");
|
// System.out.println("load end");
|
||||||
});
|
// });
|
||||||
|
|
||||||
inventory = new Inventory(InventoryType.CHEST_1_ROW, Component.text("Test inventory"));
|
inventory = new Inventory(InventoryType.CHEST_1_ROW, Component.text("Test inventory"));
|
||||||
inventory.setItemStack(3, ItemStack.of(Material.DIAMOND, 34));
|
inventory.setItemStack(3, ItemStack.of(Material.DIAMOND, 34));
|
||||||
|
@ -710,11 +710,11 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
|||||||
for (int i = 0; i < 50; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
if (!iter.hasNext()) return TaskSchedule.stop();
|
if (!iter.hasNext()) return TaskSchedule.stop();
|
||||||
|
|
||||||
var next = iter.next();
|
var next = iter.nextLong();
|
||||||
chunkAdder.accept(ChunkUtils.getChunkCoordX(next), ChunkUtils.getChunkCoordZ(next));
|
chunkAdder.accept(ChunkUtils.getChunkCoordX(next), ChunkUtils.getChunkCoordZ(next));
|
||||||
}
|
}
|
||||||
|
|
||||||
return TaskSchedule.nextTick();
|
return TaskSchedule.tick(20);
|
||||||
};
|
};
|
||||||
scheduler().submitTask(taskRunnable);
|
scheduler().submitTask(taskRunnable);
|
||||||
} else {
|
} else {
|
||||||
|
@ -211,16 +211,44 @@ 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,
|
return new ChunkDataPacket(chunkX, chunkZ,
|
||||||
new ChunkData(heightmapsNBT, data, entries),
|
new ChunkData(heightmapsNBT, data, entries),
|
||||||
createLightData(true));
|
createLightData(true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull UpdateLightPacket createLightPacket() {
|
@NotNull UpdateLightPacket createLightPacket() {
|
||||||
return new UpdateLightPacket(chunkX, chunkZ, createLightData(false));
|
return new UpdateLightPacket(chunkX, chunkZ, createLightData(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LightData createLightData(boolean sendAll) {
|
private LightData createEmptyLight() {
|
||||||
|
BitSet skyMask = new BitSet();
|
||||||
|
BitSet blockMask = new BitSet();
|
||||||
|
BitSet emptySkyMask = new BitSet();
|
||||||
|
BitSet emptyBlockMask = new BitSet();
|
||||||
|
List<byte[]> skyLights = new ArrayList<>();
|
||||||
|
List<byte[]> blockLights = new ArrayList<>();
|
||||||
|
|
||||||
|
return new LightData(skyMask, blockMask,
|
||||||
|
emptySkyMask, emptyBlockMask,
|
||||||
|
skyLights, blockLights);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected LightData createLightData(boolean sendLater) {
|
||||||
BitSet skyMask = new BitSet();
|
BitSet skyMask = new BitSet();
|
||||||
BitSet blockMask = new BitSet();
|
BitSet blockMask = new BitSet();
|
||||||
BitSet emptySkyMask = new BitSet();
|
BitSet emptySkyMask = new BitSet();
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.minestom.server.instance;
|
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.MinecraftServer;
|
||||||
import net.minestom.server.collision.Shape;
|
import net.minestom.server.collision.Shape;
|
||||||
import net.minestom.server.coordinate.Point;
|
import net.minestom.server.coordinate.Point;
|
||||||
@ -17,7 +19,6 @@ import net.minestom.server.utils.chunk.ChunkUtils;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
@ -26,6 +27,10 @@ import java.util.stream.Stream;
|
|||||||
import static net.minestom.server.instance.light.LightCompute.emptyContent;
|
import static net.minestom.server.instance.light.LightCompute.emptyContent;
|
||||||
|
|
||||||
public class LightingChunk extends DynamicChunk {
|
public class LightingChunk extends DynamicChunk {
|
||||||
|
|
||||||
|
private static final int LIGHTING_CHUNKS_PER_SEND = Integer.getInteger("minestom.lighting.chunks-per-send", 10);
|
||||||
|
private static final int LIGHTING_CHUNKS_SEND_DELAY = Integer.getInteger("minestom.lighting.chunks-send-delay", 100);
|
||||||
|
|
||||||
private int[] heightmap;
|
private int[] heightmap;
|
||||||
final CachedPacket lightCache = new CachedPacket(this::createLightPacket);
|
final CachedPacket lightCache = new CachedPacket(this::createLightPacket);
|
||||||
boolean sendNeighbours = true;
|
boolean sendNeighbours = true;
|
||||||
@ -81,9 +86,9 @@ public class LightingChunk extends DynamicChunk {
|
|||||||
Chunk neighborChunk = instance.getChunk(chunkX + i, chunkZ + j);
|
Chunk neighborChunk = instance.getChunk(chunkX + i, chunkZ + j);
|
||||||
if (neighborChunk == null) continue;
|
if (neighborChunk == null) continue;
|
||||||
|
|
||||||
if (neighborChunk instanceof LightingChunk lightingChunk) {
|
if (neighborChunk instanceof LightingChunk light) {
|
||||||
lightingChunk.lightCache.invalidate();
|
light.lightCache.invalidate();
|
||||||
lightingChunk.chunkCache.invalidate();
|
light.chunkCache.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int k = -1; k <= 1; k++) {
|
for (int k = -1; k <= 1; k++) {
|
||||||
@ -115,7 +120,7 @@ public class LightingChunk extends DynamicChunk {
|
|||||||
@Override
|
@Override
|
||||||
protected void onLoad() {
|
protected void onLoad() {
|
||||||
// Prefetch the chunk packet so that lazy lighting is computed
|
// Prefetch the chunk packet so that lazy lighting is computed
|
||||||
chunkCache.body();
|
updateAfterGeneration(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] calculateHeightMap() {
|
public int[] calculateHeightMap() {
|
||||||
@ -144,7 +149,7 @@ public class LightingChunk extends DynamicChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LightData createLightData(boolean sendAll) {
|
protected LightData createLightData(boolean sendLater) {
|
||||||
BitSet skyMask = new BitSet();
|
BitSet skyMask = new BitSet();
|
||||||
BitSet blockMask = new BitSet();
|
BitSet blockMask = new BitSet();
|
||||||
BitSet emptySkyMask = new BitSet();
|
BitSet emptySkyMask = new BitSet();
|
||||||
@ -176,10 +181,8 @@ public class LightingChunk extends DynamicChunk {
|
|||||||
final byte[] skyLight = section.skyLight().array();
|
final byte[] skyLight = section.skyLight().array();
|
||||||
final byte[] blockLight = section.blockLight().array();
|
final byte[] blockLight = section.blockLight().array();
|
||||||
|
|
||||||
// System.out.println("Relit sky: " + wasUpdatedSky + " block: " + wasUpdatedBlock + " for section " + (index + minSection) + " in chunk " + chunkX + " " + chunkZ);
|
if ((wasUpdatedSky || sendLater) && this.instance.getDimensionType().isSkylightEnabled()) {
|
||||||
|
if (skyLight.length != 0 && skyLight != emptyContent) {
|
||||||
if ((wasUpdatedSky || (sendAll && skyLight != emptyContent)) && this.instance.getDimensionType().isSkylightEnabled()) {
|
|
||||||
if (skyLight.length != 0) {
|
|
||||||
skyLights.add(skyLight);
|
skyLights.add(skyLight);
|
||||||
skyMask.set(index);
|
skyMask.set(index);
|
||||||
} else {
|
} else {
|
||||||
@ -187,8 +190,8 @@ public class LightingChunk extends DynamicChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wasUpdatedBlock || (sendAll && blockLight != emptyContent)) {
|
if (wasUpdatedBlock || sendLater) {
|
||||||
if (blockLight.length != 0) {
|
if (blockLight.length != 0 && blockLight != emptyContent) {
|
||||||
blockLights.add(blockLight);
|
blockLights.add(blockLight);
|
||||||
blockMask.set(index);
|
blockMask.set(index);
|
||||||
} else {
|
} else {
|
||||||
@ -202,49 +205,88 @@ public class LightingChunk extends DynamicChunk {
|
|||||||
sendNeighbours = false;
|
sendNeighbours = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LightData(
|
return new LightData(skyMask, blockMask,
|
||||||
skyMask, blockMask,
|
|
||||||
emptySkyMask, emptyBlockMask,
|
emptySkyMask, emptyBlockMask,
|
||||||
skyLights, blockLights
|
skyLights, blockLights);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Set<LightingChunk> sendQueue = ConcurrentHashMap.newKeySet();
|
private static final LongSet queuedChunks = new LongOpenHashSet();
|
||||||
private static final ReentrantLock sendQueueLock = new ReentrantLock();
|
private static final List<LightingChunk> sendQueue = new ArrayList<>();
|
||||||
private static Task sendingTask = null;
|
private static Task sendingTask = null;
|
||||||
|
private static final ReentrantLock lightLock = new ReentrantLock();
|
||||||
|
private static final ReentrantLock queueLock = new ReentrantLock();
|
||||||
|
|
||||||
private static void updateAfterGeneration(LightingChunk chunk) {
|
static void updateAfterGeneration(LightingChunk chunk) {
|
||||||
for (int i = -1; i <= 1; i++) {
|
for (int i = -1; i <= 1; i++) {
|
||||||
for (int j = -1; j <= 1; j++) {
|
for (int j = -1; j <= 1; j++) {
|
||||||
Chunk neighborChunk = chunk.instance.getChunk(chunk.chunkX + i, chunk.chunkZ + j);
|
Chunk neighborChunk = chunk.instance.getChunk(chunk.chunkX + i, chunk.chunkZ + j);
|
||||||
if (neighborChunk == null) continue;
|
if (neighborChunk == null) continue;
|
||||||
|
|
||||||
if (neighborChunk instanceof LightingChunk lightingChunk) {
|
if (neighborChunk instanceof LightingChunk lightingChunk) {
|
||||||
sendQueue.add(lightingChunk);
|
queueLock.lock();
|
||||||
|
|
||||||
|
if (queuedChunks.add(ChunkUtils.getChunkIndex(lightingChunk.chunkX, lightingChunk.chunkZ))) {
|
||||||
|
sendQueue.add(lightingChunk);
|
||||||
|
}
|
||||||
|
queueLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendQueueLock.lock();
|
lightLock.lock();
|
||||||
if (sendingTask != null) sendingTask.cancel();
|
if (sendingTask != null) {
|
||||||
|
lightLock.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sendingTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> {
|
sendingTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> {
|
||||||
sendingTask = null;
|
queueLock.lock();
|
||||||
|
var copy = new ArrayList<>(sendQueue);
|
||||||
|
sendQueue.clear();
|
||||||
|
queuedChunks.clear();
|
||||||
|
queueLock.unlock();
|
||||||
|
|
||||||
for (LightingChunk f : sendQueue) {
|
// 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()) {
|
if (f.isLoaded()) {
|
||||||
f.sections.forEach(s -> {
|
f.lightCache.body();
|
||||||
s.blockLight().invalidate();
|
|
||||||
s.skyLight().invalidate();
|
|
||||||
});
|
|
||||||
|
|
||||||
f.chunkCache.invalidate();
|
|
||||||
f.lightCache.invalidate();
|
|
||||||
f.sendLighting();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendQueue.clear();
|
|
||||||
}, TaskSchedule.tick(10), TaskSchedule.stop(), ExecutionType.ASYNC);
|
// Send it slowly
|
||||||
sendQueueLock.unlock();
|
for (LightingChunk f : copy) {
|
||||||
|
if (f.isLoaded()) {
|
||||||
|
f.sendLighting();
|
||||||
|
if (f.getViewers().size() == 0) return;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count % LIGHTING_CHUNKS_PER_SEND == 0) {
|
||||||
|
// System.out.println("Sent " + count + " lighting chunks " + (count * 100 / copy.size()) + "%");
|
||||||
|
try {
|
||||||
|
Thread.sleep(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<Point> queue, LightType type) {
|
private static void flushQueue(Instance instance, Set<Point> queue, LightType type) {
|
||||||
|
@ -54,4 +54,8 @@ public final class CachedPacket implements SendablePacket {
|
|||||||
}
|
}
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return packet != null && packet.get() != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user