mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-08 01:17:47 +01:00
Initial light support
This commit is contained in:
parent
d27b1ff1a4
commit
735ea152f9
@ -57,31 +57,46 @@ public class AnvilLoader implements IChunkLoader {
|
||||
|
||||
private Chunk loadMCA(Instance instance, int chunkX, int chunkZ, ChunkCallback callback) throws IOException, AnvilException {
|
||||
RegionFile mcaFile = getMCAFile(chunkX, chunkZ);
|
||||
if (mcaFile != null) {
|
||||
ChunkColumn fileChunk = mcaFile.getChunk(chunkX, chunkZ);
|
||||
if (fileChunk != null) {
|
||||
Biome[] biomes;
|
||||
if (fileChunk.getGenerationStatus().compareTo(ChunkColumn.GenerationStatus.Biomes) > 0) {
|
||||
int[] fileChunkBiomes = fileChunk.getBiomes();
|
||||
biomes = new Biome[fileChunkBiomes.length];
|
||||
for (int i = 0; i < fileChunkBiomes.length; i++) {
|
||||
final int id = fileChunkBiomes[i];
|
||||
biomes[i] = Objects.requireNonNullElse(BIOME_MANAGER.getById(id), BIOME);
|
||||
}
|
||||
} else {
|
||||
biomes = new Biome[1024]; // TODO don't hardcode
|
||||
Arrays.fill(biomes, BIOME);
|
||||
}
|
||||
Chunk chunk = new DynamicChunk(instance, biomes, chunkX, chunkZ);
|
||||
placeBlocks(chunk, fileChunk);
|
||||
loadTileEntities(chunk, fileChunk);
|
||||
if (callback != null) {
|
||||
callback.accept(chunk);
|
||||
}
|
||||
return chunk;
|
||||
if (mcaFile == null)
|
||||
return null;
|
||||
ChunkColumn fileChunk = mcaFile.getChunk(chunkX, chunkZ);
|
||||
if (fileChunk == null)
|
||||
return null;
|
||||
|
||||
Biome[] biomes;
|
||||
if (fileChunk.getGenerationStatus().compareTo(ChunkColumn.GenerationStatus.Biomes) > 0) {
|
||||
int[] fileChunkBiomes = fileChunk.getBiomes();
|
||||
biomes = new Biome[fileChunkBiomes.length];
|
||||
for (int i = 0; i < fileChunkBiomes.length; i++) {
|
||||
final int id = fileChunkBiomes[i];
|
||||
biomes[i] = Objects.requireNonNullElse(BIOME_MANAGER.getById(id), BIOME);
|
||||
}
|
||||
} else {
|
||||
biomes = new Biome[1024]; // TODO don't hardcode
|
||||
Arrays.fill(biomes, BIOME);
|
||||
}
|
||||
Chunk chunk = new DynamicChunk(instance, biomes, chunkX, chunkZ);
|
||||
|
||||
// Blocks
|
||||
{
|
||||
placeBlocks(chunk, fileChunk);
|
||||
loadTileEntities(chunk, fileChunk);
|
||||
}
|
||||
|
||||
// Lights
|
||||
{
|
||||
final var chunkSections = fileChunk.getSections();
|
||||
for (var chunkSection : chunkSections) {
|
||||
Section section = chunk.getSection(chunkSection.getY());
|
||||
section.setSkyLight(chunkSection.getSkyLights());
|
||||
section.setBlockLight(chunkSection.getBlockLights());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
if (callback != null) {
|
||||
callback.accept(chunk);
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private RegionFile getMCAFile(int chunkX, int chunkZ) {
|
||||
|
@ -16,6 +16,7 @@ import net.minestom.server.instance.block.BlockSetter;
|
||||
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
|
||||
import net.minestom.server.network.packet.server.play.UpdateLightPacket;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.utils.ArrayUtils;
|
||||
import net.minestom.server.utils.PacketUtils;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
@ -108,9 +109,9 @@ public abstract class Chunk implements BlockGetter, BlockSetter, Viewable, Ticka
|
||||
@Override
|
||||
public abstract void setBlock(int x, int y, int z, @NotNull Block block);
|
||||
|
||||
public abstract @NotNull Map<Integer, Section> getSections();
|
||||
public abstract @NotNull TreeMap<Integer, Section> getSections();
|
||||
|
||||
public abstract @Nullable Section getSection(int section);
|
||||
public abstract @NotNull Section getSection(int section);
|
||||
|
||||
/**
|
||||
* Executes a chunk tick.
|
||||
@ -296,31 +297,53 @@ public abstract class Chunk implements BlockGetter, BlockSetter, Viewable, Ticka
|
||||
*/
|
||||
@NotNull
|
||||
public UpdateLightPacket getLightPacket() {
|
||||
// TODO do not hardcode light
|
||||
long skyMask = 0;
|
||||
long blockMask = 0;
|
||||
long emptySkyMask = 0;
|
||||
long emptyBlockMask = 0;
|
||||
List<byte[]> skyLights = new ArrayList<>();
|
||||
List<byte[]> blockLights = new ArrayList<>();
|
||||
|
||||
|
||||
// Creates a light packet for the given number of sections with all block light at max and no sky light.
|
||||
UpdateLightPacket updateLightPacket = new UpdateLightPacket(getIdentifier(), getLastChangeTime());
|
||||
updateLightPacket.chunkX = getChunkX();
|
||||
updateLightPacket.chunkZ = getChunkZ();
|
||||
|
||||
final int sectionCount = (getInstance().getDimensionType().getTotalHeight() / 16) + 2;
|
||||
final int maskLength = (int) Math.ceil((double) sectionCount / 64);
|
||||
updateLightPacket.skyLightMask = new long[]{skyMask};
|
||||
updateLightPacket.blockLightMask = new long[]{blockMask};
|
||||
updateLightPacket.emptySkyLightMask = new long[]{emptySkyMask};
|
||||
updateLightPacket.emptyBlockLightMask = new long[]{emptyBlockMask};
|
||||
|
||||
updateLightPacket.skyLightMask = new long[maskLength];
|
||||
updateLightPacket.blockLightMask = new long[maskLength];
|
||||
updateLightPacket.emptySkyLightMask = new long[maskLength];
|
||||
updateLightPacket.emptyBlockLightMask = new long[maskLength];
|
||||
// Set all block light and no sky light
|
||||
Arrays.fill(updateLightPacket.blockLightMask, -1L);
|
||||
Arrays.fill(updateLightPacket.emptySkyLightMask, -1L);
|
||||
updateLightPacket.skyLight = skyLights;
|
||||
updateLightPacket.blockLight = blockLights;
|
||||
|
||||
byte[] bytes = new byte[2048];
|
||||
Arrays.fill(bytes, (byte) 0xFF);
|
||||
final List<byte[]> temp = new ArrayList<>(sectionCount);
|
||||
for (int i = 0; i < sectionCount; ++i) {
|
||||
temp.add(bytes);
|
||||
emptySkyMask |= 1L << 0;
|
||||
emptyBlockMask |= 1L << 0;
|
||||
emptySkyMask |= 1L << 17;
|
||||
emptyBlockMask |= 1L << 17;
|
||||
|
||||
final var sections = getSections();
|
||||
for (var entry : sections.entrySet()) {
|
||||
final int index = entry.getKey() + 1;
|
||||
final Section section = entry.getValue();
|
||||
|
||||
final var skyLight = section.getSkyLight();
|
||||
final var blockLight = section.getBlockLight();
|
||||
|
||||
if (!ArrayUtils.empty(skyLight)) {
|
||||
skyLights.add(skyLight);
|
||||
skyMask |= 1L << index;
|
||||
} else {
|
||||
emptySkyMask |= 1L << index;
|
||||
}
|
||||
|
||||
if (!ArrayUtils.empty(blockLight)) {
|
||||
blockLights.add(blockLight);
|
||||
blockMask |= 1L << index;
|
||||
} else {
|
||||
emptyBlockMask |= 1L << index;
|
||||
}
|
||||
}
|
||||
updateLightPacket.blockLight = temp;
|
||||
return updateLightPacket;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package net.minestom.server.instance;
|
||||
|
||||
import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ShortMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
@ -28,6 +27,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Represents a {@link Chunk} which store each individual block in memory.
|
||||
@ -42,7 +42,7 @@ public class DynamicChunk extends Chunk {
|
||||
*/
|
||||
private static final int DATA_FORMAT_VERSION = 1;
|
||||
|
||||
protected final Int2ObjectRBTreeMap<Section> sectionMap = new Int2ObjectRBTreeMap<>();
|
||||
protected final TreeMap<Integer, Section> sectionMap = new TreeMap<>();
|
||||
|
||||
// Key = ChunkUtils#getBlockIndex
|
||||
protected final Int2ObjectOpenHashMap<BlockHandler> handlerMap = new Int2ObjectOpenHashMap<>();
|
||||
@ -94,13 +94,13 @@ public class DynamicChunk extends Chunk {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Map<Integer, Section> getSections() {
|
||||
public @NotNull TreeMap<Integer, Section> getSections() {
|
||||
return sectionMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Section getSection(int section) {
|
||||
return sectionMap.get(section);
|
||||
public @NotNull Section getSection(int section) {
|
||||
return sectionMap.computeIfAbsent(section, key -> new Section());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -348,7 +348,7 @@ public class DynamicChunk extends Chunk {
|
||||
packet.biomes = biomes;
|
||||
packet.chunkX = chunkX;
|
||||
packet.chunkZ = chunkZ;
|
||||
packet.sections = sectionMap.clone(); // TODO deep clone
|
||||
packet.sections = (Map<Integer, Section>) sectionMap.clone(); // TODO deep clone
|
||||
packet.handlerMap = handlerMap.clone();
|
||||
packet.nbtMap = nbtMap.clone();
|
||||
|
||||
@ -361,8 +361,8 @@ public class DynamicChunk extends Chunk {
|
||||
@Override
|
||||
public Chunk copy(@NotNull Instance instance, int chunkX, int chunkZ) {
|
||||
DynamicChunk dynamicChunk = new DynamicChunk(instance, biomes.clone(), chunkX, chunkZ);
|
||||
for (var entry : sectionMap.int2ObjectEntrySet()) {
|
||||
dynamicChunk.sectionMap.put(entry.getIntKey(), entry.getValue().clone());
|
||||
for (var entry : sectionMap.entrySet()) {
|
||||
dynamicChunk.sectionMap.put(entry.getKey(), entry.getValue().clone());
|
||||
}
|
||||
dynamicChunk.handlerMap.putAll(handlerMap);
|
||||
dynamicChunk.nbtMap.putAll(nbtMap);
|
||||
@ -379,6 +379,6 @@ public class DynamicChunk extends Chunk {
|
||||
|
||||
private @NotNull Section retrieveSection(int y) {
|
||||
final int sectionIndex = ChunkUtils.getSectionAt(y);
|
||||
return sectionMap.computeIfAbsent(sectionIndex, key -> new Section());
|
||||
return getSection(sectionIndex);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,9 @@ public class Section implements PublicCloneable<Section> {
|
||||
|
||||
private final Palette palette;
|
||||
|
||||
private byte[] skyLight = new byte[0];
|
||||
private byte[] blockLight = new byte[0];
|
||||
|
||||
private Section(Palette palette) {
|
||||
this.palette = palette;
|
||||
}
|
||||
@ -28,6 +31,22 @@ public class Section implements PublicCloneable<Section> {
|
||||
palette.setBlockAt(x, y, z, blockId);
|
||||
}
|
||||
|
||||
public byte[] getSkyLight() {
|
||||
return skyLight;
|
||||
}
|
||||
|
||||
public void setSkyLight(byte[] skyLight) {
|
||||
this.skyLight = skyLight;
|
||||
}
|
||||
|
||||
public byte[] getBlockLight() {
|
||||
return blockLight;
|
||||
}
|
||||
|
||||
public void setBlockLight(byte[] blockLight) {
|
||||
this.blockLight = blockLight;
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
palette.clean();
|
||||
}
|
||||
|
@ -117,4 +117,12 @@ public final class ArrayUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean empty(byte[] array) {
|
||||
for (byte b : array) {
|
||||
if (b != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user