mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-30 13:08:19 +01:00
WIP support for infinite chunk height
This commit is contained in:
parent
31d2f3488b
commit
6b5125bcff
@ -15,7 +15,6 @@ import net.minestom.server.instance.block.CustomBlock;
|
||||
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.MathUtils;
|
||||
import net.minestom.server.utils.PacketUtils;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.binary.BinaryReader;
|
||||
@ -23,7 +22,6 @@ import net.minestom.server.utils.chunk.ChunkCallback;
|
||||
import net.minestom.server.utils.chunk.ChunkSupplier;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.utils.player.PlayerUtils;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import net.minestom.server.world.biomes.Biome;
|
||||
import net.minestom.server.world.biomes.BiomeManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -54,12 +52,9 @@ public abstract class Chunk implements Viewable, Tickable, DataContainer {
|
||||
protected static final BiomeManager BIOME_MANAGER = MinecraftServer.getBiomeManager();
|
||||
|
||||
public static final int CHUNK_SIZE_X = 16;
|
||||
public static final int CHUNK_SIZE_Y = 256;
|
||||
public static final int CHUNK_SIZE_Z = 16;
|
||||
public static final int CHUNK_SECTION_SIZE = 16;
|
||||
|
||||
public static final int CHUNK_SECTION_COUNT = CHUNK_SIZE_Y / CHUNK_SECTION_SIZE;
|
||||
|
||||
public static final int BIOME_COUNT = 1024; // 4x4x4 blocks group
|
||||
|
||||
private final UUID identifier;
|
||||
@ -394,10 +389,10 @@ public abstract class Chunk implements Viewable, Tickable, DataContainer {
|
||||
UpdateLightPacket updateLightPacket = new UpdateLightPacket(getIdentifier(), getLastChangeTime());
|
||||
updateLightPacket.chunkX = getChunkX();
|
||||
updateLightPacket.chunkZ = getChunkZ();
|
||||
updateLightPacket.skyLightMask = 0b111111111111111111;
|
||||
updateLightPacket.emptySkyLightMask = 0b000000000000000000;
|
||||
updateLightPacket.blockLightMask = 0b000000000000000000;
|
||||
updateLightPacket.emptyBlockLightMask = 0b111111111111111111;
|
||||
updateLightPacket.skyLightMask = 0b111111111111111111;
|
||||
updateLightPacket.emptySkyLightMask = 0b000000000000000000;
|
||||
updateLightPacket.blockLightMask = 0b000000000000000000;
|
||||
updateLightPacket.emptyBlockLightMask = 0b111111111111111111;
|
||||
byte[] bytes = new byte[2048];
|
||||
Arrays.fill(bytes, (byte) 0xFF);
|
||||
final List<byte[]> temp = new ArrayList<>(18);
|
||||
@ -538,9 +533,6 @@ public abstract class Chunk implements Viewable, Tickable, DataContainer {
|
||||
public synchronized void sendChunkSectionUpdate(int section, @NotNull Player player) {
|
||||
if (!PlayerUtils.isNettyClient(player))
|
||||
return;
|
||||
Check.argCondition(!MathUtils.isBetween(section, 0, CHUNK_SECTION_COUNT),
|
||||
"The chunk section " + section + " does not exist");
|
||||
|
||||
player.getPlayerConnection().sendPacket(createChunkSectionUpdatePacket(section));
|
||||
}
|
||||
|
||||
@ -553,9 +545,7 @@ public abstract class Chunk implements Viewable, Tickable, DataContainer {
|
||||
@NotNull
|
||||
protected ChunkDataPacket createChunkSectionUpdatePacket(int section) {
|
||||
ChunkDataPacket chunkDataPacket = createChunkPacket();
|
||||
int[] sections = new int[CHUNK_SECTION_COUNT];
|
||||
sections[section] = 1;
|
||||
chunkDataPacket.sections = sections;
|
||||
// TODO
|
||||
return chunkDataPacket;
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ public class DynamicChunk extends Chunk {
|
||||
|
||||
// Loop all blocks
|
||||
for (byte x = 0; x < CHUNK_SIZE_X; x++) {
|
||||
for (short y = 0; y < CHUNK_SIZE_Y; y++) {
|
||||
for (short y = 0; y < 256; y++) { // TODO increase max size
|
||||
for (byte z = 0; z < CHUNK_SIZE_Z; z++) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
|
||||
|
@ -258,10 +258,7 @@ public class ChunkBatch implements Batch<ChunkCallback> {
|
||||
private void updateChunk(@NotNull Instance instance, Chunk chunk, IntSet updatedSections, @Nullable ChunkCallback callback, boolean safeCallback) {
|
||||
// Refresh chunk for viewers
|
||||
ChunkDataPacket chunkDataPacket = chunk.createChunkPacket();
|
||||
int[] sections = new int[Chunk.CHUNK_SECTION_COUNT];
|
||||
for (int section : updatedSections)
|
||||
sections[section] = 1;
|
||||
chunkDataPacket.sections = sections;
|
||||
// TODO update all sections from `updatedSections`
|
||||
PacketUtils.sendGroupedPacket(chunk.getViewers(), chunkDataPacket);
|
||||
|
||||
if (instance instanceof InstanceContainer) {
|
||||
|
@ -1,16 +1,16 @@
|
||||
package net.minestom.server.instance.palette;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.utils.clone.CloneUtils;
|
||||
import net.minestom.server.utils.clone.PublicCloneable;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static net.minestom.server.instance.Chunk.CHUNK_SECTION_COUNT;
|
||||
import static net.minestom.server.instance.Chunk.CHUNK_SECTION_SIZE;
|
||||
|
||||
/**
|
||||
@ -21,7 +21,7 @@ import static net.minestom.server.instance.Chunk.CHUNK_SECTION_SIZE;
|
||||
*/
|
||||
public class PaletteStorage implements PublicCloneable<PaletteStorage> {
|
||||
|
||||
private Section[] sections = new Section[CHUNK_SECTION_COUNT];
|
||||
private Int2ObjectRBTreeMap<Section> sectionMap = new Int2ObjectRBTreeMap<>();
|
||||
|
||||
private final int defaultBitsPerEntry;
|
||||
private final int defaultBitsIncrement;
|
||||
@ -40,28 +40,21 @@ public class PaletteStorage implements PublicCloneable<PaletteStorage> {
|
||||
}
|
||||
|
||||
public void setBlockAt(int x, int y, int z, short blockId) {
|
||||
if (!MathUtils.isBetween(y, 0, Chunk.CHUNK_SIZE_Y - 1)) {
|
||||
return;
|
||||
}
|
||||
final int sectionIndex = ChunkUtils.getSectionAt(y);
|
||||
x = toChunkCoordinate(x);
|
||||
z = toChunkCoordinate(z);
|
||||
|
||||
Section section = sections[sectionIndex];
|
||||
Section section = getSection(sectionIndex);
|
||||
if (section == null) {
|
||||
section = new Section(defaultBitsPerEntry, defaultBitsIncrement);
|
||||
sections[sectionIndex] = section;
|
||||
setSection(sectionIndex, section);
|
||||
}
|
||||
section.setBlockAt(x, y, z, blockId);
|
||||
}
|
||||
|
||||
public short getBlockAt(int x, int y, int z) {
|
||||
if (y < 0 || y >= Chunk.CHUNK_SIZE_Y) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final int sectionIndex = ChunkUtils.getSectionAt(y);
|
||||
final Section section = sections[sectionIndex];
|
||||
final Section section = getSection(sectionIndex);
|
||||
if (section == null) {
|
||||
return Block.AIR.getBlockId();
|
||||
}
|
||||
@ -71,8 +64,16 @@ public class PaletteStorage implements PublicCloneable<PaletteStorage> {
|
||||
return section.getBlockAt(x, y, z);
|
||||
}
|
||||
|
||||
public Section[] getSections() {
|
||||
return sections;
|
||||
public Int2ObjectRBTreeMap<Section> getSectionMap() {
|
||||
return sectionMap;
|
||||
}
|
||||
|
||||
public @Nullable Collection<Section> getSections() {
|
||||
return sectionMap.values();
|
||||
}
|
||||
|
||||
public @Nullable Section getSection(int section) {
|
||||
return sectionMap.get(section);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,18 +83,14 @@ public class PaletteStorage implements PublicCloneable<PaletteStorage> {
|
||||
* is composed of almost-empty sections since the loop will not stop until a non-air block is discovered.
|
||||
*/
|
||||
public synchronized void clean() {
|
||||
for (Section section : sections) {
|
||||
section.clean();
|
||||
}
|
||||
getSections().forEach(Section::clean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all the data in the palette and data array.
|
||||
*/
|
||||
public void clear() {
|
||||
for (Section section : sections) {
|
||||
section.clear();
|
||||
}
|
||||
getSections().forEach(Section::clear);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@ -101,7 +98,8 @@ public class PaletteStorage implements PublicCloneable<PaletteStorage> {
|
||||
public PaletteStorage clone() {
|
||||
try {
|
||||
PaletteStorage paletteStorage = (PaletteStorage) super.clone();
|
||||
paletteStorage.sections = CloneUtils.cloneArray(sections, Section[]::new);
|
||||
// TODO deep clone
|
||||
paletteStorage.sectionMap = sectionMap.clone();//CloneUtils.cloneArray(sections, Section[]::new);
|
||||
return paletteStorage;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
MinecraftServer.getExceptionManager().handleException(e);
|
||||
@ -109,6 +107,10 @@ public class PaletteStorage implements PublicCloneable<PaletteStorage> {
|
||||
}
|
||||
}
|
||||
|
||||
private void setSection(int sectionIndex, Section section) {
|
||||
this.sectionMap.put(sectionIndex, section);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a world coordinate to a chunk one.
|
||||
*
|
||||
@ -123,5 +125,4 @@ public class PaletteStorage implements PublicCloneable<PaletteStorage> {
|
||||
|
||||
return xz;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.ints.Int2LongRBTreeMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
@ -44,8 +45,6 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket {
|
||||
public IntSet blockEntities;
|
||||
public Int2ObjectMap<Data> blocksData;
|
||||
|
||||
public int[] sections = new int[0];
|
||||
|
||||
private static final byte CHUNK_SECTION_COUNT = 16;
|
||||
private static final int MAX_BITS_PER_ENTRY = 16;
|
||||
private static final int MAX_BUFFER_SIZE = (Short.BYTES + Byte.BYTES + 5 * Byte.BYTES + (4096 * MAX_BITS_PER_ENTRY / Long.SIZE * Long.BYTES)) * CHUNK_SECTION_COUNT + 256 * Integer.BYTES;
|
||||
@ -79,26 +78,26 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket {
|
||||
writer.writeInt(chunkX);
|
||||
writer.writeInt(chunkZ);
|
||||
|
||||
int mask = 0;
|
||||
ByteBuf blocks = Unpooled.buffer(MAX_BUFFER_SIZE);
|
||||
final boolean fullChunk = sections.length == 0;
|
||||
for (byte i = 0; i < CHUNK_SECTION_COUNT; i++) {
|
||||
if (fullChunk || (sections.length == CHUNK_SECTION_COUNT && sections[i] != 0)) {
|
||||
final Section section = paletteStorage.getSections()[i];
|
||||
if (section == null) {
|
||||
// Section not loaded
|
||||
continue;
|
||||
}
|
||||
if (section.getBlocks().length > 0) { // section contains at least one block
|
||||
mask |= 1 << i;
|
||||
Utils.writeSectionBlocks(blocks, section);
|
||||
}
|
||||
}
|
||||
|
||||
Int2LongRBTreeMap maskMap = new Int2LongRBTreeMap();
|
||||
|
||||
for (var entry : paletteStorage.getSectionMap().int2ObjectEntrySet()) {
|
||||
final int index = entry.getIntKey();
|
||||
final Section section = entry.getValue();
|
||||
|
||||
final int lengthIndex = index % 64;
|
||||
final int maskIndex = index / (16 + 1);
|
||||
|
||||
long mask = maskMap.get(maskIndex);
|
||||
mask |= 1L << lengthIndex;
|
||||
maskMap.put(maskIndex, mask);
|
||||
|
||||
Utils.writeSectionBlocks(blocks, section);
|
||||
}
|
||||
|
||||
// TODO variable size
|
||||
writer.writeVarInt(1);
|
||||
writer.writeLong(mask);
|
||||
writer.writeVarInt(maskMap.size());
|
||||
maskMap.values().forEach(writer::writeLong);
|
||||
|
||||
// TODO: don't hardcode heightmaps
|
||||
// Heightmap
|
||||
@ -168,7 +167,7 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket {
|
||||
|
||||
int maskCount = reader.readVarInt();
|
||||
long[] masks = new long[maskCount];
|
||||
for(int i=0;i<maskCount;i++){
|
||||
for (int i = 0; i < maskCount; i++) {
|
||||
masks[i] = reader.readLong();
|
||||
}
|
||||
try {
|
||||
@ -195,8 +194,8 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket {
|
||||
byte bitsPerEntry = reader.readByte();
|
||||
|
||||
// Resize palette if necessary
|
||||
if (bitsPerEntry > paletteStorage.getSections()[section].getBitsPerEntry()) {
|
||||
paletteStorage.getSections()[section].resize(bitsPerEntry);
|
||||
if (bitsPerEntry > paletteStorage.getSection(section).getBitsPerEntry()) {
|
||||
paletteStorage.getSection(section).resize(bitsPerEntry);
|
||||
}
|
||||
|
||||
// Retrieve palette values
|
||||
@ -204,14 +203,14 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket {
|
||||
int paletteSize = reader.readVarInt();
|
||||
for (int i = 0; i < paletteSize; i++) {
|
||||
final int paletteValue = reader.readVarInt();
|
||||
paletteStorage.getSections()[section].getPaletteBlockMap().put((short) i, (short) paletteValue);
|
||||
paletteStorage.getSections()[section].getBlockPaletteMap().put((short) paletteValue, (short) i);
|
||||
paletteStorage.getSection(section).getPaletteBlockMap().put((short) i, (short) paletteValue);
|
||||
paletteStorage.getSection(section).getBlockPaletteMap().put((short) paletteValue, (short) i);
|
||||
}
|
||||
}
|
||||
|
||||
// Read blocks
|
||||
int dataLength = reader.readVarInt();
|
||||
long[] data = paletteStorage.getSections()[section].getBlocks();
|
||||
long[] data = paletteStorage.getSection(section).getBlocks();
|
||||
for (int i = 0; i < dataLength; i++) {
|
||||
data[i] = reader.readLong();
|
||||
}
|
||||
|
@ -22,6 +22,13 @@ public class ChunkGeneratorDemo implements ChunkGenerator {
|
||||
batch.setBlock(x, y, z, Block.STONE);
|
||||
}
|
||||
}
|
||||
|
||||
for (short x = 0; x < Chunk.CHUNK_SIZE_X; x++)
|
||||
for (short z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
|
||||
for (short y = 300; y < 500; y++) {
|
||||
batch.setBlock(x, y, z, Block.STONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user