mirror of https://github.com/Minestom/Minestom.git
Fix Lighting Invalidation (#2041)
- Fix invalid lighting being sent to clients - Add cherry leaves to occludes - Fix lighting being generated when using loaded lighting - Send lighting to clients on block changes - Cleanup unused methods - Add sky lighting test for short grass
This commit is contained in:
parent
17fd82a5c1
commit
6e179dbd8a
|
@ -169,7 +169,7 @@ public class PlayerInit {
|
||||||
});
|
});
|
||||||
instanceContainer.setChunkSupplier(LightingChunk::new);
|
instanceContainer.setChunkSupplier(LightingChunk::new);
|
||||||
instanceContainer.setTimeRate(0);
|
instanceContainer.setTimeRate(0);
|
||||||
instanceContainer.setTime(6000);
|
instanceContainer.setTime(12000);
|
||||||
|
|
||||||
// var i2 = new InstanceContainer(UUID.randomUUID(), DimensionType.OVERWORLD, null, NamespaceID.from("minestom:demo"));
|
// var i2 = new InstanceContainer(UUID.randomUUID(), DimensionType.OVERWORLD, null, NamespaceID.from("minestom:demo"));
|
||||||
// instanceManager.registerInstance(i2);
|
// instanceManager.registerInstance(i2);
|
||||||
|
|
|
@ -22,6 +22,7 @@ public final class ServerFlag {
|
||||||
public static final int POOLED_BUFFER_SIZE = Integer.getInteger("minestom.pooled-buffer-size", 262_143);
|
public static final int POOLED_BUFFER_SIZE = Integer.getInteger("minestom.pooled-buffer-size", 262_143);
|
||||||
public static final int PLAYER_PACKET_PER_TICK = Integer.getInteger("minestom.packet-per-tick", 20);
|
public static final int PLAYER_PACKET_PER_TICK = Integer.getInteger("minestom.packet-per-tick", 20);
|
||||||
public static final int PLAYER_PACKET_QUEUE_SIZE = Integer.getInteger("minestom.packet-queue-size", 1000);
|
public static final int PLAYER_PACKET_QUEUE_SIZE = Integer.getInteger("minestom.packet-queue-size", 1000);
|
||||||
|
public static final int SEND_LIGHT_AFTER_BLOCK_PLACEMENT_DELAY = Integer.getInteger("minestom.send-light-after-block-placement-delay", 100);
|
||||||
|
|
||||||
// Packet sending optimizations
|
// Packet sending optimizations
|
||||||
public static final boolean GROUPED_PACKET = PropertyUtils.getBoolean("minestom.grouped-packet", true);
|
public static final boolean GROUPED_PACKET = PropertyUtils.getBoolean("minestom.grouped-packet", true);
|
||||||
|
|
|
@ -284,6 +284,11 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
|
||||||
*/
|
*/
|
||||||
protected void onLoad() {}
|
protected void onLoad() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the chunk generator has finished generating the chunk.
|
||||||
|
*/
|
||||||
|
public void onGenerate() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName() + "[" + chunkX + ":" + chunkZ + "]";
|
return getClass().getSimpleName() + "[" + chunkX + ":" + chunkZ + "]";
|
||||||
|
|
|
@ -298,7 +298,7 @@ public class InstanceContainer extends Instance {
|
||||||
return CompletableFuture.completedFuture(chunk);
|
return CompletableFuture.completedFuture(chunk);
|
||||||
} else {
|
} else {
|
||||||
// Loader couldn't load the chunk, generate it
|
// Loader couldn't load the chunk, generate it
|
||||||
return createChunk(chunkX, chunkZ);
|
return createChunk(chunkX, chunkZ).whenComplete((c, a) -> c.onGenerate());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// cache the retrieved chunk
|
// cache the retrieved chunk
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.minestom.server.instance;
|
package net.minestom.server.instance;
|
||||||
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
|
import net.minestom.server.ServerFlag;
|
||||||
import net.minestom.server.collision.Shape;
|
import net.minestom.server.collision.Shape;
|
||||||
import net.minestom.server.coordinate.Point;
|
import net.minestom.server.coordinate.Point;
|
||||||
import net.minestom.server.coordinate.Vec;
|
import net.minestom.server.coordinate.Vec;
|
||||||
|
@ -8,10 +9,7 @@ import net.minestom.server.instance.block.Block;
|
||||||
import net.minestom.server.instance.block.BlockFace;
|
import net.minestom.server.instance.block.BlockFace;
|
||||||
import net.minestom.server.instance.block.BlockHandler;
|
import net.minestom.server.instance.block.BlockHandler;
|
||||||
import net.minestom.server.instance.light.Light;
|
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.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.network.packet.server.play.data.LightData;
|
||||||
import net.minestom.server.utils.MathUtils;
|
import net.minestom.server.utils.MathUtils;
|
||||||
import net.minestom.server.utils.NamespaceID;
|
import net.minestom.server.utils.NamespaceID;
|
||||||
|
@ -26,6 +24,8 @@ import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
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;
|
import static net.minestom.server.instance.light.LightCompute.emptyContent;
|
||||||
|
|
||||||
|
@ -41,9 +41,16 @@ public class LightingChunk extends DynamicChunk {
|
||||||
|
|
||||||
private int[] heightmap;
|
private int[] heightmap;
|
||||||
final CachedPacket lightCache = new CachedPacket(this::createLightPacket);
|
final CachedPacket lightCache = new CachedPacket(this::createLightPacket);
|
||||||
|
private LightData lightData;
|
||||||
|
|
||||||
boolean chunkLoaded = false;
|
boolean chunkLoaded = false;
|
||||||
private int highestBlock;
|
private int highestBlock;
|
||||||
private boolean initialLightingSent = false;
|
|
||||||
|
private final ReentrantLock packetGenerationLock = new ReentrantLock();
|
||||||
|
private final AtomicInteger resendTimer = new AtomicInteger(-1);
|
||||||
|
private final int resendDelay = ServerFlag.SEND_LIGHT_AFTER_BLOCK_PLACEMENT_DELAY;
|
||||||
|
|
||||||
|
private boolean doneInit = false;
|
||||||
|
|
||||||
enum LightType {
|
enum LightType {
|
||||||
SKY,
|
SKY,
|
||||||
|
@ -67,6 +74,7 @@ public class LightingChunk extends DynamicChunk {
|
||||||
Block.DARK_OAK_LEAVES.namespace(),
|
Block.DARK_OAK_LEAVES.namespace(),
|
||||||
Block.FLOWERING_AZALEA_LEAVES.namespace(),
|
Block.FLOWERING_AZALEA_LEAVES.namespace(),
|
||||||
Block.JUNGLE_LEAVES.namespace(),
|
Block.JUNGLE_LEAVES.namespace(),
|
||||||
|
Block.CHERRY_LEAVES.namespace(),
|
||||||
Block.OAK_LEAVES.namespace(),
|
Block.OAK_LEAVES.namespace(),
|
||||||
Block.SPRUCE_LEAVES.namespace(),
|
Block.SPRUCE_LEAVES.namespace(),
|
||||||
Block.SPAWNER.namespace(),
|
Block.SPAWNER.namespace(),
|
||||||
|
@ -83,6 +91,7 @@ public class LightingChunk extends DynamicChunk {
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
this.lightCache.invalidate();
|
this.lightCache.invalidate();
|
||||||
this.chunkCache.invalidate();
|
this.chunkCache.invalidate();
|
||||||
|
this.lightData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LightingChunk(@NotNull Instance instance, int chunkX, int chunkZ) {
|
public LightingChunk(@NotNull Instance instance, int chunkX, int chunkZ) {
|
||||||
|
@ -107,8 +116,7 @@ public class LightingChunk extends DynamicChunk {
|
||||||
if (neighborChunk == null) continue;
|
if (neighborChunk == null) continue;
|
||||||
|
|
||||||
if (neighborChunk instanceof LightingChunk light) {
|
if (neighborChunk instanceof LightingChunk light) {
|
||||||
light.lightCache.invalidate();
|
light.invalidate();
|
||||||
light.chunkCache.invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int k = -1; k <= 1; k++) {
|
for (int k = -1; k <= 1; k++) {
|
||||||
|
@ -132,6 +140,19 @@ public class LightingChunk extends DynamicChunk {
|
||||||
if (chunkLoaded) {
|
if (chunkLoaded) {
|
||||||
invalidateSection(coordinate);
|
invalidateSection(coordinate);
|
||||||
this.lightCache.invalidate();
|
this.lightCache.invalidate();
|
||||||
|
|
||||||
|
if (doneInit) {
|
||||||
|
for (int i = -1; i <= 1; i++) {
|
||||||
|
for (int j = -1; j <= 1; j++) {
|
||||||
|
Chunk neighborChunk = instance.getChunk(chunkX + i, chunkZ + j);
|
||||||
|
if (neighborChunk == null) continue;
|
||||||
|
|
||||||
|
if (neighborChunk instanceof LightingChunk light) {
|
||||||
|
light.resendTimer.set(resendDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,10 +164,41 @@ public class LightingChunk extends DynamicChunk {
|
||||||
@Override
|
@Override
|
||||||
protected void onLoad() {
|
protected void onLoad() {
|
||||||
chunkLoaded = true;
|
chunkLoaded = true;
|
||||||
|
doneInit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLightingCalculated() {
|
@Override
|
||||||
return initialLightingSent;
|
public void onGenerate() {
|
||||||
|
super.onGenerate();
|
||||||
|
|
||||||
|
for (int section = minSection; section < maxSection; section++) {
|
||||||
|
getSection(section).blockLight().invalidate();
|
||||||
|
getSection(section).skyLight().invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> {
|
||||||
|
for (int i = -1; i <= 1; i++) {
|
||||||
|
for (int j = -1; j <= 1; j++) {
|
||||||
|
Chunk neighborChunk = instance.getChunk(chunkX + i, chunkZ + j);
|
||||||
|
if (neighborChunk == null) continue;
|
||||||
|
|
||||||
|
if (neighborChunk instanceof LightingChunk light) {
|
||||||
|
for (int section = light.minSection; section < light.maxSection; section++) {
|
||||||
|
light.getSection(section).blockLight().invalidate();
|
||||||
|
light.getSection(section).skyLight().invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
light.invalidate();
|
||||||
|
|
||||||
|
light.resendTimer.set(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
doneInit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -175,11 +227,11 @@ public class LightingChunk extends DynamicChunk {
|
||||||
int height = maxY;
|
int height = maxY;
|
||||||
while (height > minY) {
|
while (height > minY) {
|
||||||
Block block = getBlock(x, height, z, Condition.TYPE);
|
Block block = getBlock(x, height, z, Condition.TYPE);
|
||||||
|
if (block != Block.AIR) highestBlock = Math.max(highestBlock, height);
|
||||||
if (checkSkyOcclusion(block)) break;
|
if (checkSkyOcclusion(block)) break;
|
||||||
height--;
|
height--;
|
||||||
}
|
}
|
||||||
heightmap[z << 4 | x] = (height + 1);
|
heightmap[z << 4 | x] = (height + 1);
|
||||||
if (height > highestBlock) highestBlock = height;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,93 +242,95 @@ public class LightingChunk extends DynamicChunk {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LightData createLightData() {
|
protected LightData createLightData() {
|
||||||
if (lightCache.isValid()) {
|
packetGenerationLock.lock();
|
||||||
ServerPacket packet = lightCache.packet(ConnectionState.PLAY);
|
if (lightData != null) {
|
||||||
return ((UpdateLightPacket) packet).lightData();
|
packetGenerationLock.unlock();
|
||||||
|
return lightData;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (lightCache) {
|
BitSet skyMask = new BitSet();
|
||||||
BitSet skyMask = new BitSet();
|
BitSet blockMask = new BitSet();
|
||||||
BitSet blockMask = new BitSet();
|
BitSet emptySkyMask = new BitSet();
|
||||||
BitSet emptySkyMask = new BitSet();
|
BitSet emptyBlockMask = new BitSet();
|
||||||
BitSet emptyBlockMask = new BitSet();
|
List<byte[]> skyLights = new ArrayList<>();
|
||||||
List<byte[]> skyLights = new ArrayList<>();
|
List<byte[]> blockLights = new ArrayList<>();
|
||||||
List<byte[]> blockLights = new ArrayList<>();
|
|
||||||
|
|
||||||
Set<Chunk> combined = new HashSet<>();
|
int chunkMin = instance.getDimensionType().getMinY();
|
||||||
int chunkMin = instance.getDimensionType().getMinY();
|
|
||||||
|
|
||||||
int index = 0;
|
int highestNeighborBlock = instance.getDimensionType().getMinY();
|
||||||
for (Section section : sections) {
|
for (int i = -1; i <= 1; i++) {
|
||||||
boolean wasUpdatedBlock = false;
|
for (int j = -1; j <= 1; j++) {
|
||||||
boolean wasUpdatedSky = false;
|
Chunk neighborChunk = instance.getChunk(chunkX + i, chunkZ + j);
|
||||||
|
if (neighborChunk == null) continue;
|
||||||
|
|
||||||
if (section.blockLight().requiresUpdate()) {
|
if (neighborChunk instanceof LightingChunk light) {
|
||||||
var needsSend = relightSection(instance, this.chunkX, index + minSection, chunkZ, LightType.BLOCK);
|
light.getHeightmap();
|
||||||
combined.addAll(needsSend);
|
highestNeighborBlock = Math.max(highestNeighborBlock, light.highestBlock);
|
||||||
wasUpdatedBlock = true;
|
|
||||||
} else if (section.blockLight().requiresSend()) {
|
|
||||||
wasUpdatedBlock = true;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (section.skyLight().requiresUpdate()) {
|
int index = 0;
|
||||||
var needsSend = relightSection(instance, this.chunkX, index + minSection, chunkZ, LightType.SKY);
|
for (Section section : sections) {
|
||||||
combined.addAll(needsSend);
|
boolean wasUpdatedBlock = false;
|
||||||
wasUpdatedSky = true;
|
boolean wasUpdatedSky = false;
|
||||||
} else if (section.skyLight().requiresSend()) {
|
|
||||||
wasUpdatedSky = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
if (section.blockLight().requiresUpdate()) {
|
||||||
|
relightSection(instance, this.chunkX, index + minSection, chunkZ, LightType.BLOCK);
|
||||||
|
wasUpdatedBlock = true;
|
||||||
|
} else if (section.blockLight().requiresSend()) {
|
||||||
|
wasUpdatedBlock = true;
|
||||||
|
}
|
||||||
|
|
||||||
final byte[] skyLight = section.skyLight().array();
|
if (section.skyLight().requiresUpdate()) {
|
||||||
final byte[] blockLight = section.blockLight().array();
|
relightSection(instance, this.chunkX, index + minSection, chunkZ, LightType.SKY);
|
||||||
final int sectionMaxY = index * 16 + chunkMin;
|
wasUpdatedSky = true;
|
||||||
|
} else if (section.skyLight().requiresSend()) {
|
||||||
|
wasUpdatedSky = true;
|
||||||
|
}
|
||||||
|
|
||||||
if ((wasUpdatedSky) && this.instance.getDimensionType().isSkylightEnabled() && sectionMaxY <= (highestBlock + 16)) {
|
index++;
|
||||||
if (skyLight.length != 0 && skyLight != emptyContent) {
|
|
||||||
skyLights.add(skyLight);
|
|
||||||
skyMask.set(index);
|
|
||||||
} else {
|
|
||||||
emptySkyMask.set(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wasUpdatedBlock) {
|
final byte[] skyLight = section.skyLight().array();
|
||||||
if (blockLight.length != 0 && blockLight != emptyContent) {
|
final byte[] blockLight = section.blockLight().array();
|
||||||
blockLights.add(blockLight);
|
final int sectionMaxY = index * 16 + chunkMin;
|
||||||
blockMask.set(index);
|
|
||||||
} else {
|
if ((wasUpdatedSky) && this.instance.getDimensionType().isSkylightEnabled() && sectionMaxY <= (highestNeighborBlock + 16)) {
|
||||||
emptyBlockMask.set(index);
|
if (skyLight.length != 0 && skyLight != emptyContent) {
|
||||||
}
|
skyLights.add(skyLight);
|
||||||
|
skyMask.set(index);
|
||||||
|
} else {
|
||||||
|
emptySkyMask.set(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> {
|
if (wasUpdatedBlock) {
|
||||||
for (Chunk chunk : combined) {
|
if (blockLight.length != 0 && blockLight != emptyContent) {
|
||||||
if (chunk instanceof LightingChunk light) {
|
blockLights.add(blockLight);
|
||||||
if (light.initialLightingSent) {
|
blockMask.set(index);
|
||||||
light.lightCache.invalidate();
|
} else {
|
||||||
light.chunkCache.invalidate();
|
emptyBlockMask.set(index);
|
||||||
|
|
||||||
// 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;
|
this.lightData = new LightData(skyMask, blockMask,
|
||||||
});
|
emptySkyMask, emptyBlockMask,
|
||||||
|
skyLights, blockLights);
|
||||||
|
|
||||||
return new LightData(skyMask, blockMask,
|
packetGenerationLock.unlock();
|
||||||
emptySkyMask, emptyBlockMask,
|
|
||||||
skyLights, blockLights);
|
return this.lightData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(long time) {
|
||||||
|
super.tick(time);
|
||||||
|
|
||||||
|
if (doneInit && resendTimer.get() > 0) {
|
||||||
|
if (resendTimer.decrementAndGet() == 0) {
|
||||||
|
sendLighting();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,8 +398,7 @@ public class LightingChunk extends DynamicChunk {
|
||||||
sections.add(new Vec(chunk.getChunkX(), section, chunk.getChunkZ()));
|
sections.add(new Vec(chunk.getChunkX(), section, chunk.getChunkZ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
lighting.lightCache.invalidate();
|
lighting.invalidate();
|
||||||
lighting.chunkCache.invalidate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ final class BlockLight implements Light {
|
||||||
private byte[] contentPropagation;
|
private byte[] contentPropagation;
|
||||||
private byte[] contentPropagationSwap;
|
private byte[] contentPropagationSwap;
|
||||||
|
|
||||||
private boolean isValidBorders = false;
|
private boolean isValidBorders = true;
|
||||||
private boolean needsSend = true;
|
private boolean needsSend = true;
|
||||||
|
|
||||||
private Set<Point> toUpdateSet = new HashSet<>();
|
private Set<Point> toUpdateSet = new HashSet<>();
|
||||||
|
@ -34,27 +34,6 @@ final class BlockLight implements Light {
|
||||||
this.blockPalette = blockPalette;
|
this.blockPalette = blockPalette;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public void setInternalLighting(byte[] content) {
|
|
||||||
this.content = content;
|
|
||||||
this.isValidBorders = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public void setExternalLighting(byte[] content) {
|
|
||||||
this.contentPropagation = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public byte[] getInternalLighting() {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public byte[] getExternalLighting() {
|
|
||||||
return contentPropagation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Point> flip() {
|
public Set<Point> flip() {
|
||||||
if (this.contentPropagationSwap != null)
|
if (this.contentPropagationSwap != null)
|
||||||
|
@ -164,12 +143,6 @@ final class BlockLight implements Light {
|
||||||
return lightSources;
|
return lightSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void copyFrom(byte @NotNull [] array) {
|
|
||||||
if (array.length == 0) this.content = null;
|
|
||||||
else this.content = array.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Light calculateInternal(Instance instance, int chunkX, int sectionY, int chunkZ) {
|
public Light calculateInternal(Instance instance, int chunkX, int sectionY, int chunkZ) {
|
||||||
Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||||
|
@ -223,7 +196,13 @@ final class BlockLight implements Light {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(byte[] copyArray) {
|
public void set(byte[] copyArray) {
|
||||||
this.content = copyArray.clone();
|
if (copyArray.length == 0) {
|
||||||
|
this.content = emptyContent;
|
||||||
|
this.contentPropagation = emptyContent;
|
||||||
|
} else {
|
||||||
|
this.content = copyArray.clone();
|
||||||
|
this.contentPropagation = this.content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -233,11 +212,6 @@ final class BlockLight implements Light {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRequiresSend(boolean b) {
|
|
||||||
this.needsSend = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearCache() {
|
private void clearCache() {
|
||||||
this.contentPropagation = null;
|
this.contentPropagation = null;
|
||||||
isValidBorders = true;
|
isValidBorders = true;
|
||||||
|
|
|
@ -27,15 +27,12 @@ public interface Light {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean requiresSend();
|
boolean requiresSend();
|
||||||
void setRequiresSend(boolean b);
|
|
||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
byte[] array();
|
byte[] array();
|
||||||
|
|
||||||
Set<Point> flip();
|
Set<Point> flip();
|
||||||
|
|
||||||
void copyFrom(byte @NotNull [] array);
|
|
||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
Light calculateExternal(Instance instance, Chunk chunk, int sectionY);
|
Light calculateExternal(Instance instance, Chunk chunk, int sectionY);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ final class SkyLight implements Light {
|
||||||
private byte[] contentPropagation;
|
private byte[] contentPropagation;
|
||||||
private byte[] contentPropagationSwap;
|
private byte[] contentPropagationSwap;
|
||||||
|
|
||||||
private boolean isValidBorders = false;
|
private boolean isValidBorders = true;
|
||||||
private boolean needsSend = true;
|
private boolean needsSend = true;
|
||||||
|
|
||||||
private Set<Point> toUpdateSet = new HashSet<>();
|
private Set<Point> toUpdateSet = new HashSet<>();
|
||||||
|
@ -160,12 +160,6 @@ final class SkyLight implements Light {
|
||||||
return lightSources;
|
return lightSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void copyFrom(byte @NotNull [] array) {
|
|
||||||
if (array.length == 0) this.content = null;
|
|
||||||
else this.content = array.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Light calculateInternal(Instance instance, int chunkX, int sectionY, int chunkZ) {
|
public Light calculateInternal(Instance instance, int chunkX, int sectionY, int chunkZ) {
|
||||||
Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||||
|
@ -228,7 +222,13 @@ final class SkyLight implements Light {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(byte[] copyArray) {
|
public void set(byte[] copyArray) {
|
||||||
this.content = copyArray.clone();
|
if (copyArray.length == 0) {
|
||||||
|
this.content = emptyContent;
|
||||||
|
this.contentPropagation = emptyContent;
|
||||||
|
} else {
|
||||||
|
this.content = copyArray.clone();
|
||||||
|
this.contentPropagation = this.content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -238,11 +238,6 @@ final class SkyLight implements Light {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRequiresSend(boolean b) {
|
|
||||||
this.needsSend = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearCache() {
|
private void clearCache() {
|
||||||
this.contentPropagation = null;
|
this.contentPropagation = null;
|
||||||
isValidBorders = true;
|
isValidBorders = true;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.minestom.server.entity;
|
package net.minestom.server.entity;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
@ -7,12 +8,14 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
public class PlayerSkinTest {
|
public class PlayerSkinTest {
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void validName() {
|
public void validName() {
|
||||||
var skin = PlayerSkin.fromUsername("jeb_");
|
var skin = PlayerSkin.fromUsername("jeb_");
|
||||||
assertNotNull(skin);
|
assertNotNull(skin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void invalidName() {
|
public void invalidName() {
|
||||||
var skin = PlayerSkin.fromUsername("jfdsa84vvcxadubasdfcvn");
|
var skin = PlayerSkin.fromUsername("jfdsa84vvcxadubasdfcvn");
|
||||||
|
|
|
@ -414,6 +414,25 @@ public class BlockLightMergeIntegrationTest {
|
||||||
assertEquals(14, val);
|
assertEquals(14, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void skylightShortGrass(Env env) {
|
||||||
|
Instance instance = env.createFlatInstance();
|
||||||
|
instance.setChunkSupplier(LightingChunk::new);
|
||||||
|
for (int x = 4; x <= 7; x++) {
|
||||||
|
for (int z = 6; z <= 8; z++) {
|
||||||
|
instance.loadChunk(x, z).join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.setBlock(94, 50, 128, Block.SHORT_GRASS);
|
||||||
|
|
||||||
|
LightingChunk.relight(instance, instance.getChunks());
|
||||||
|
|
||||||
|
var val = lightValSky(instance, new Vec(94, 50, 128));
|
||||||
|
assertEquals(15, val);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void skylightContained(Env env) {
|
public void skylightContained(Env env) {
|
||||||
Instance instance = env.createFlatInstance();
|
Instance instance = env.createFlatInstance();
|
||||||
|
|
|
@ -159,8 +159,6 @@ public class LightParityIntegrationTest {
|
||||||
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
|
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
|
||||||
final BlockState blockState = section.get(x, y, z);
|
final BlockState blockState = section.get(x, y, z);
|
||||||
String blockName = blockState.getName();
|
String blockName = blockState.getName();
|
||||||
if (blockName.equals("minecraft:grass"))
|
|
||||||
blockName = "minecraft:short_grass";
|
|
||||||
Block block = Objects.requireNonNull(Block.fromNamespaceId(blockName), blockName)
|
Block block = Objects.requireNonNull(Block.fromNamespaceId(blockName), blockName)
|
||||||
.withProperties(blockState.getProperties());
|
.withProperties(blockState.getProperties());
|
||||||
palette.set(x, y, z, block.stateId());
|
palette.set(x, y, z, block.stateId());
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.minestom.server.utils;
|
package net.minestom.server.utils;
|
||||||
|
|
||||||
import net.minestom.server.utils.mojang.MojangUtils;
|
import net.minestom.server.utils.mojang.MojangUtils;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -10,6 +11,8 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
public class TestMojangUtils {
|
public class TestMojangUtils {
|
||||||
private final UUID JEB_UUID = UUID.fromString("853c80ef-3c37-49fd-aa49-938b674adae6");
|
private final UUID JEB_UUID = UUID.fromString("853c80ef-3c37-49fd-aa49-938b674adae6");
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testValidNameWorks() {
|
public void testValidNameWorks() {
|
||||||
var result = MojangUtils.fromUsername("jeb_");
|
var result = MojangUtils.fromUsername("jeb_");
|
||||||
|
@ -17,12 +20,14 @@ public class TestMojangUtils {
|
||||||
assertEquals("jeb_", result.get("name").getAsString());
|
assertEquals("jeb_", result.get("name").getAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidNameReturnsNull() {
|
public void testInvalidNameReturnsNull() {
|
||||||
var result = MojangUtils.fromUsername("jfdsa84vvcxadubasdfcvn"); // Longer than 16, always invalid
|
var result = MojangUtils.fromUsername("jfdsa84vvcxadubasdfcvn"); // Longer than 16, always invalid
|
||||||
assertNull(result);
|
assertNull(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testValidUuidWorks() {
|
public void testValidUuidWorks() {
|
||||||
var result = MojangUtils.fromUuid(JEB_UUID.toString());
|
var result = MojangUtils.fromUuid(JEB_UUID.toString());
|
||||||
|
@ -31,18 +36,21 @@ public class TestMojangUtils {
|
||||||
assertEquals("853c80ef3c3749fdaa49938b674adae6", result.get("id").getAsString());
|
assertEquals("853c80ef3c3749fdaa49938b674adae6", result.get("id").getAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidUuidReturnsNull() {
|
public void testInvalidUuidReturnsNull() {
|
||||||
var result = MojangUtils.fromUuid("853c80ef3c3749fdaa49938b674adae6a"); // Longer than 32, always invalid
|
var result = MojangUtils.fromUuid("853c80ef3c3749fdaa49938b674adae6a"); // Longer than 32, always invalid
|
||||||
assertNull(result);
|
assertNull(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testNonExistentUuidReturnsNull() {
|
public void testNonExistentUuidReturnsNull() {
|
||||||
var result = MojangUtils.fromUuid("00000000-0000-0000-0000-000000000000");
|
var result = MojangUtils.fromUuid("00000000-0000-0000-0000-000000000000");
|
||||||
assertNull(result);
|
assertNull(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testValidUUIDWorks() {
|
public void testValidUUIDWorks() {
|
||||||
var result = MojangUtils.fromUuid(JEB_UUID);
|
var result = MojangUtils.fromUuid(JEB_UUID);
|
||||||
|
@ -51,16 +59,19 @@ public class TestMojangUtils {
|
||||||
assertEquals("853c80ef3c3749fdaa49938b674adae6", result.get("id").getAsString());
|
assertEquals("853c80ef3c3749fdaa49938b674adae6", result.get("id").getAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testGetValidNameWorks() throws IOException {
|
public void testGetValidNameWorks() throws IOException {
|
||||||
assertEquals(JEB_UUID, MojangUtils.getUUID("jeb_"));
|
assertEquals(JEB_UUID, MojangUtils.getUUID("jeb_"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testGetValidUUIDWorks() throws IOException {
|
public void testGetValidUUIDWorks() throws IOException {
|
||||||
assertEquals("jeb_", MojangUtils.getUsername(JEB_UUID));
|
assertEquals("jeb_", MojangUtils.getUsername(JEB_UUID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Disabled
|
||||||
@Test
|
@Test
|
||||||
public void testGetInvalidNameThrows() {
|
public void testGetInvalidNameThrows() {
|
||||||
assertThrows(IOException.class, () -> MojangUtils.getUUID("a")); // Too short
|
assertThrows(IOException.class, () -> MojangUtils.getUUID("a")); // Too short
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue