Implement support for 1.13+ chunks and some fixes

This commit is contained in:
Lukas Rieger (Blue) 2024-02-05 16:38:33 +01:00
parent f3488f34f1
commit edee956893
No known key found for this signature in database
GPG Key ID: 2D09EC5ED2687FF2
8 changed files with 326 additions and 296 deletions

View File

@ -239,7 +239,7 @@ public class BlueMapService implements Closeable {
try {
Logger.global.logInfo("Loading map '" + name + "'...");
Logger.global.logInfo("Loading map '" + id + "'...");
BmMap map = new BmMap(
id,
name,

View File

@ -42,6 +42,14 @@ import java.util.Map;
@DebugDump
public class BlockColorCalculatorFactory {
private static final int
AVERAGE_MIN_X = - 2,
AVERAGE_MAX_X = 2,
AVERAGE_MIN_Y = - 1,
AVERAGE_MAX_Y = 1,
AVERAGE_MIN_Z = - 2,
AVERAGE_MAX_Z = 2;
private final int[] foliageMap = new int[65536];
private final int[] grassMap = new int[65536];
@ -133,18 +141,12 @@ public class BlockColorCalculatorFactory {
public Color getWaterAverageColor(BlockNeighborhood<?> block, Color target) {
target.set(0, 0, 0, 0, true);
int x, y, z,
minX = - 2,
maxX = 2,
minY = - 1,
maxY = 1,
minZ = - 2,
maxZ = 2;
int x, y, z;
Biome biome;
for (x = minX; x <= maxX; x++) {
for (y = minY; y <= maxY; y++) {
for (z = minZ; z <= maxZ; z++) {
for (y = AVERAGE_MIN_Y; y <= AVERAGE_MAX_Y; y++) {
for (x = AVERAGE_MIN_X; x <= AVERAGE_MAX_X; x++) {
for (z = AVERAGE_MIN_Z; z <= AVERAGE_MAX_Z; z++) {
biome = block.getNeighborBlock(x, y, z).getBiome();
target.add(biome.getWaterColor());
}
@ -157,18 +159,12 @@ public class BlockColorCalculatorFactory {
public Color getFoliageAverageColor(BlockNeighborhood<?> block, Color target) {
target.set(0, 0, 0, 0, true);
int x, y, z,
minX = - 2,
maxX = 2,
minY = - 1,
maxY = 1,
minZ = - 2,
maxZ = 2;
int x, y, z;
Biome biome;
for (y = minY; y <= maxY; y++) {
for (x = minX; x <= maxX; x++) {
for (z = minZ; z <= maxZ; z++) {
for (y = AVERAGE_MIN_Y; y <= AVERAGE_MAX_Y; y++) {
for (x = AVERAGE_MIN_X; x <= AVERAGE_MAX_X; x++) {
for (z = AVERAGE_MIN_Z; z <= AVERAGE_MAX_Z; z++) {
biome = block.getNeighborBlock(x, y, z).getBiome();
target.add(getFoliageColor(biome, tempColor));
}
@ -186,18 +182,12 @@ public class BlockColorCalculatorFactory {
public Color getGrassAverageColor(BlockNeighborhood<?> block, Color target) {
target.set(0, 0, 0, 0, true);
int x, y, z,
minX = - 2,
maxX = 2,
minY = - 1,
maxY = 1,
minZ = - 2,
maxZ = 2;
int x, y, z;
Biome biome;
for (y = minY; y <= maxY; y++) {
for (x = minX; x <= maxX; x++) {
for (z = minZ; z <= maxZ; z++) {
for (y = AVERAGE_MIN_Y; y <= AVERAGE_MAX_Y; y++) {
for (x = AVERAGE_MIN_X; x <= AVERAGE_MAX_X; x++) {
for (z = AVERAGE_MIN_Z; z <= AVERAGE_MAX_Z; z++) {
biome = block.getNeighborBlock(x, y, z).getBiome();
target.add(getGrassColor(biome, tempColor));
}

View File

@ -25,6 +25,11 @@ public class DataPack {
public static final Key DIMENSION_THE_NETHER = new Key("minecraft", "the_nether");
public static final Key DIMENSION_THE_END = new Key("minecraft", "the_end");
public static final Key DIMENSION_TYPE_OVERWORLD = new Key("minecraft", "overworld");
public static final Key DIMENSION_TYPE_OVERWORLD_CAVES = new Key("minecraft", "overworld_caves");
public static final Key DIMENSION_TYPE_THE_NETHER = new Key("minecraft", "the_nether");
public static final Key DIMENSION_TYPE_THE_END = new Key("minecraft", "the_end");
private final Map<Key, DimensionType> dimensionTypes = new HashMap<>();
@Nullable
@ -80,10 +85,10 @@ public class DataPack {
}
public void bake() {
dimensionTypes.putIfAbsent(new Key("minecraft", "overworld"), DimensionType.OVERWORLD);
dimensionTypes.putIfAbsent(new Key("minecraft", "overworld_caves"), DimensionType.OVERWORLD_CAVES);
dimensionTypes.putIfAbsent(new Key("minecraft", "the_nether"), DimensionType.NETHER);
dimensionTypes.putIfAbsent(new Key("minecraft", "the_end"), DimensionType.END);
dimensionTypes.putIfAbsent(DIMENSION_TYPE_OVERWORLD, DimensionType.OVERWORLD);
dimensionTypes.putIfAbsent(DIMENSION_TYPE_OVERWORLD_CAVES, DimensionType.OVERWORLD_CAVES);
dimensionTypes.putIfAbsent(DIMENSION_TYPE_THE_NETHER, DimensionType.NETHER);
dimensionTypes.putIfAbsent(DIMENSION_TYPE_THE_END, DimensionType.END);
}
private static Stream<Path> list(Path root) {

View File

@ -61,7 +61,7 @@ public class MCAWorld implements World {
.build(this::loadRegion);
private final LoadingCache<Vector2i, Chunk> chunkCache = Caffeine.newBuilder()
.executor(BlueMap.THREAD_POOL)
.maximumSize(2048) // 2 regions worth of chunks
.maximumSize(10240) // 10 regions worth of chunks
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(this::loadChunk);
@ -72,16 +72,22 @@ public class MCAWorld implements World {
this.levelData = levelData;
this.dataPack = dataPack;
LevelData.Dimension dim = levelData.getData().getWorldGenSettings().getDimensions().get(dimension.getFormatted());
if (dim == null) {
Logger.global.logWarning("The level-data does not contain any dimension with the id '" + dimension +
"', using fallback.");
dim = new LevelData.Dimension();
LevelData.Dimension dimensionData = levelData.getData().getWorldGenSettings().getDimensions().get(dimension.getFormatted());
if (dimensionData == null) {
if (DataPack.DIMENSION_OVERWORLD.equals(dimension)) dimensionData = new LevelData.Dimension(DataPack.DIMENSION_TYPE_OVERWORLD.getFormatted());
else if (DataPack.DIMENSION_THE_NETHER.equals(dimension)) dimensionData = new LevelData.Dimension(DataPack.DIMENSION_TYPE_THE_NETHER.getFormatted());
else if (DataPack.DIMENSION_THE_END.equals(dimension)) dimensionData = new LevelData.Dimension(DataPack.DIMENSION_TYPE_THE_END.getFormatted());
else {
Logger.global.logWarning("The level-data does not contain any dimension with the id '" + dimension +
"', using fallback.");
dimensionData = new LevelData.Dimension();
}
}
DimensionType dimensionType = dataPack.getDimensionType(new Key(dim.getType()));
DimensionType dimensionType = dataPack.getDimensionType(new Key(dimensionData.getType()));
if (dimensionType == null) {
Logger.global.logWarning("The data-pack for world '" + worldFolder +
"' does not contain any dimension-type with the id '" + dim.getType() + "', using fallback.");
"' does not contain any dimension-type with the id '" + dimensionData.getType() + "', using fallback.");
dimensionType = DimensionType.OVERWORLD;
}

View File

@ -18,10 +18,10 @@ public class ChunkLoader {
// sorted list of chunk-versions, loaders at the start of the list are preferred over loaders at the end
private static final List<ChunkVersionLoader<?>> CHUNK_VERSION_LOADERS = List.of(
//new ChunkVersionLoader<>(Chunk_1_13.Data.class, Chunk_1_13::new, 0),
new ChunkVersionLoader<>(Chunk_1_15.Data.class, Chunk_1_15::new, 2200),
new ChunkVersionLoader<>(Chunk_1_18.Data.class, Chunk_1_18::new, 2844),
new ChunkVersionLoader<>(Chunk_1_16.Data.class, Chunk_1_16::new, 2500),
new ChunkVersionLoader<>(Chunk_1_18.Data.class, Chunk_1_18::new, 2844)
new ChunkVersionLoader<>(Chunk_1_15.Data.class, Chunk_1_15::new, 2200),
new ChunkVersionLoader<>(Chunk_1_13.Data.class, Chunk_1_13::new, 0)
);
private ChunkVersionLoader<?> lastUsedLoader = CHUNK_VERSION_LOADERS.get(0);

View File

@ -0,0 +1,274 @@
package de.bluecolored.bluemap.core.world.mca.chunk;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.util.Key;
import de.bluecolored.bluemap.core.world.Biome;
import de.bluecolored.bluemap.core.world.BlockState;
import de.bluecolored.bluemap.core.world.DimensionType;
import de.bluecolored.bluemap.core.world.LightData;
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
import de.bluecolored.bluemap.core.world.mca.region.MCARegion;
import de.bluecolored.bluenbt.NBTName;
import lombok.Getter;
import org.jetbrains.annotations.Nullable;
public class Chunk_1_13 extends MCAChunk {
private static final Level EMPTY_LEVEL = new Level();
private static final HeightmapsData EMPTY_HEIGHTMAPS_DATA = new HeightmapsData();
private static final Key STATUS_EMPTY = new Key("minecraft", "empty");
private static final Key STATUS_FULL = new Key("minecraft", "full");
private static final Key STATUS_FULLCHUNK = new Key("minecraft", "fullchunk");
private static final Key STATUS_POSTPROCESSED = new Key("minecraft", "postprocessed");
private final boolean generated;
private final boolean hasLightData;
private final long inhabitedTime;
private final int skyLight;
private final boolean hasWorldSurfaceHeights;
private final long[] worldSurfaceHeights;
private final boolean hasOceanFloorHeights;
private final long[] oceanFloorHeights;
private final Section[] sections;
private final int sectionMin, sectionMax;
final int[] biomes;
public Chunk_1_13(MCARegion region, Data data) {
super(region, data);
Level level = data.level;
this.generated = !STATUS_EMPTY.equals(level.status);
this.hasLightData =
STATUS_FULL.equals(level.status) ||
STATUS_FULLCHUNK.equals(level.status) ||
STATUS_POSTPROCESSED.equals(level.status);
this.inhabitedTime = level.inhabitedTime;
DimensionType dimensionType = getRegion().getWorld().getDimensionType();
this.skyLight = dimensionType.hasSkylight() ? 16 : 0;
this.worldSurfaceHeights = level.heightmaps.worldSurface;
this.oceanFloorHeights = level.heightmaps.oceanFloor;
this.hasWorldSurfaceHeights = this.worldSurfaceHeights.length >= 36;
this.hasOceanFloorHeights = this.oceanFloorHeights.length >= 36;
this.biomes = level.biomes;
SectionData[] sectionsData = level.sections;
if (sectionsData != null && sectionsData.length > 0) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
// find section min/max y
for (SectionData sectionData : sectionsData) {
int y = sectionData.getY();
if (min > y) min = y;
if (max < y) max = y;
}
// load sections into ordered array
this.sections = new Section[1 + max - min];
for (SectionData sectionData : sectionsData) {
Section section = new Section(sectionData);
int y = section.getSectionY();
if (min > y) min = y;
if (max < y) max = y;
this.sections[section.sectionY - min] = section;
}
this.sectionMin = min;
this.sectionMax = max;
} else {
this.sections = new Section[0];
this.sectionMin = 0;
this.sectionMax = 0;
}
}
@Override
public boolean isGenerated() {
return generated;
}
@Override
public boolean hasLightData() {
return hasLightData;
}
@Override
public long getInhabitedTime() {
return inhabitedTime;
}
@Override
public BlockState getBlockState(int x, int y, int z) {
Section section = getSection(y >> 4);
if (section == null) return BlockState.AIR;
return section.getBlockState(x, y, z);
}
@Override
public String getBiome(int x, int y, int z) {
if (this.biomes.length < 256) return Biome.DEFAULT.getFormatted();
int biomeIntIndex = (z & 0xF) << 4 | x & 0xF;
return LegacyBiomes.idFor(biomes[biomeIntIndex]);
}
@Override
public LightData getLightData(int x, int y, int z, LightData target) {
if (!hasLightData) return target.set(skyLight, 0);
int sectionY = y >> 4;
Section section = getSection(sectionY);
if (section == null) return (sectionY < sectionMin) ? target.set(0, 0) : target.set(skyLight, 0);
return section.getLightData(x, y, z, target);
}
@Override
public int getMinY(int x, int z) {
return sectionMin * 16;
}
@Override
public int getMaxY(int x, int z) {
return sectionMax * 16 + 15;
}
@Override
public boolean hasWorldSurfaceHeights() {
return hasWorldSurfaceHeights;
}
@Override
public int getWorldSurfaceY(int x, int z) {
return (int) MCAUtil.getValueFromLongStream(
worldSurfaceHeights,
(z & 0xF) << 4 | x & 0xF,
9
);
}
@Override
public boolean hasOceanFloorHeights() {
return hasOceanFloorHeights;
}
@Override
public int getOceanFloorY(int x, int z) {
return (int) MCAUtil.getValueFromLongStream(
oceanFloorHeights,
(z & 0xF) << 4 | x & 0xF,
9
);
}
private @Nullable Section getSection(int y) {
y -= sectionMin;
if (y < 0 || y >= this.sections.length) return null;
return this.sections[y];
}
protected static class Section {
private final int sectionY;
private final BlockState[] blockPalette;
private final long[] blocks;
private final byte[] blockLight;
private final byte[] skyLight;
private final int bitsPerBlock;
public Section(SectionData sectionData) {
this.sectionY = sectionData.y;
this.blockPalette = sectionData.palette;
this.blocks = sectionData.blockStates;
this.blockLight = sectionData.getBlockLight();
this.skyLight = sectionData.getSkyLight();
this.bitsPerBlock = this.blocks.length >> 6; // available longs * 64 (bits per long) / 4096 (blocks per section) (floored result)
}
public BlockState getBlockState(int x, int y, int z) {
if (blockPalette.length == 1) return blockPalette[0];
if (blockPalette.length == 0) return BlockState.AIR;
int id = (int) MCAUtil.getValueFromLongStream(
blocks,
(y & 0xF) << 8 | (z & 0xF) << 4 | x & 0xF,
bitsPerBlock
);
if (id >= blockPalette.length) {
Logger.global.noFloodWarning("palette-warning", "Got block-palette id " + id + " but palette has size of " + blockPalette.length + "! (Future occasions of this error will not be logged)");
return BlockState.MISSING;
}
return blockPalette[id];
}
public LightData getLightData(int x, int y, int z, LightData target) {
if (blockLight.length == 0 && skyLight.length == 0) return target.set(0, 0);
int blockByteIndex = (y & 0xF) << 8 | (z & 0xF) << 4 | x & 0xF;
int blockHalfByteIndex = blockByteIndex >> 1;
boolean largeHalf = (blockByteIndex & 0x1) != 0;
return target.set(
this.skyLight.length > blockHalfByteIndex ? MCAUtil.getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0,
this.blockLight.length > blockHalfByteIndex ? MCAUtil.getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0
);
}
public int getSectionY() {
return sectionY;
}
}
@Getter
@SuppressWarnings("FieldMayBeFinal")
public static class Data extends MCAChunk.Data {
private Level level = EMPTY_LEVEL;
}
@Getter
@SuppressWarnings("FieldMayBeFinal")
public static class Level {
private Key status = STATUS_EMPTY;
private long inhabitedTime = 0;
private HeightmapsData heightmaps = EMPTY_HEIGHTMAPS_DATA;
private SectionData @Nullable [] sections = null;
private int[] biomes = EMPTY_INT_ARRAY;
}
@Getter
@SuppressWarnings("FieldMayBeFinal")
protected static class HeightmapsData {
@NBTName("WORLD_SURFACE") private long[] worldSurface = EMPTY_LONG_ARRAY;
@NBTName("OCEAN_FLOOR") private long[] oceanFloor = EMPTY_LONG_ARRAY;
}
@Getter
@SuppressWarnings("FieldMayBeFinal")
protected static class SectionData {
private int y = 0;
private byte[] blockLight = EMPTY_BYTE_ARRAY;
private byte[] skyLight = EMPTY_BYTE_ARRAY;
private BlockState[] palette = EMPTY_BLOCKSTATE_ARRAY;
private long[] blockStates = EMPTY_LONG_ARRAY;
}
}

View File

@ -1,115 +1,12 @@
package de.bluecolored.bluemap.core.world.mca.chunk;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.util.Key;
import de.bluecolored.bluemap.core.world.Biome;
import de.bluecolored.bluemap.core.world.BlockState;
import de.bluecolored.bluemap.core.world.DimensionType;
import de.bluecolored.bluemap.core.world.LightData;
import de.bluecolored.bluemap.core.world.mca.MCAUtil;
import de.bluecolored.bluemap.core.world.mca.region.MCARegion;
import de.bluecolored.bluenbt.NBTName;
import lombok.Getter;
import org.jetbrains.annotations.Nullable;
public class Chunk_1_15 extends MCAChunk {
private static final Level EMPTY_LEVEL = new Level();
private static final HeightmapsData EMPTY_HEIGHTMAPS_DATA = new HeightmapsData();
private static final Key STATUS_EMPTY = new Key("minecraft", "empty");
private static final Key STATUS_FULL = new Key("minecraft", "full");
private final boolean generated;
private final boolean hasLightData;
private final long inhabitedTime;
private final int skyLight;
private final boolean hasWorldSurfaceHeights;
private final long[] worldSurfaceHeights;
private final boolean hasOceanFloorHeights;
private final long[] oceanFloorHeights;
private final Section[] sections;
private final int sectionMin, sectionMax;
private final int[] biomes;
public class Chunk_1_15 extends Chunk_1_13 {
public Chunk_1_15(MCARegion region, Data data) {
super(region, data);
Level level = data.level;
this.generated = !STATUS_EMPTY.equals(level.status);
this.hasLightData = STATUS_FULL.equals(level.status);
this.inhabitedTime = level.inhabitedTime;
DimensionType dimensionType = getRegion().getWorld().getDimensionType();
this.skyLight = dimensionType.hasSkylight() ? 16 : 0;
this.worldSurfaceHeights = level.heightmaps.worldSurface;
this.oceanFloorHeights = level.heightmaps.oceanFloor;
this.hasWorldSurfaceHeights = this.worldSurfaceHeights.length >= 36;
this.hasOceanFloorHeights = this.oceanFloorHeights.length >= 36;
this.biomes = level.biomes;
SectionData[] sectionsData = level.sections;
if (sectionsData != null && sectionsData.length > 0) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
// find section min/max y
for (SectionData sectionData : sectionsData) {
int y = sectionData.getY();
if (min > y) min = y;
if (max < y) max = y;
}
// load sections into ordered array
this.sections = new Section[1 + max - min];
for (SectionData sectionData : sectionsData) {
Section section = new Section(sectionData);
int y = section.getSectionY();
if (min > y) min = y;
if (max < y) max = y;
this.sections[section.sectionY - min] = section;
}
this.sectionMin = min;
this.sectionMax = max;
} else {
this.sections = new Section[0];
this.sectionMin = 0;
this.sectionMax = 0;
}
}
@Override
public boolean isGenerated() {
return generated;
}
@Override
public boolean hasLightData() {
return hasLightData;
}
@Override
public long getInhabitedTime() {
return inhabitedTime;
}
@Override
public BlockState getBlockState(int x, int y, int z) {
Section section = getSection(y >> 4);
if (section == null) return BlockState.AIR;
return section.getBlockState(x, y, z);
}
@Override
@ -125,150 +22,4 @@ public class Chunk_1_15 extends MCAChunk {
return LegacyBiomes.idFor(biomes[biomeIntIndex]);
}
@Override
public LightData getLightData(int x, int y, int z, LightData target) {
if (!hasLightData) return target.set(skyLight, 0);
int sectionY = y >> 4;
Section section = getSection(sectionY);
if (section == null) return (sectionY < sectionMin) ? target.set(0, 0) : target.set(skyLight, 0);
return section.getLightData(x, y, z, target);
}
@Override
public int getMinY(int x, int z) {
return sectionMin * 16;
}
@Override
public int getMaxY(int x, int z) {
return sectionMax * 16 + 15;
}
@Override
public boolean hasWorldSurfaceHeights() {
return hasWorldSurfaceHeights;
}
@Override
public int getWorldSurfaceY(int x, int z) {
return (int) MCAUtil.getValueFromLongStream(
worldSurfaceHeights,
(z & 0xF) << 4 | x & 0xF,
9
);
}
@Override
public boolean hasOceanFloorHeights() {
return hasOceanFloorHeights;
}
@Override
public int getOceanFloorY(int x, int z) {
return (int) MCAUtil.getValueFromLongStream(
oceanFloorHeights,
(z & 0xF) << 4 | x & 0xF,
9
);
}
private @Nullable Section getSection(int y) {
y -= sectionMin;
if (y < 0 || y >= this.sections.length) return null;
return this.sections[y];
}
protected static class Section {
private final int sectionY;
private final BlockState[] blockPalette;
private final long[] blocks;
private final byte[] blockLight;
private final byte[] skyLight;
private final int bitsPerBlock;
public Section(SectionData sectionData) {
this.sectionY = sectionData.y;
this.blockPalette = sectionData.palette;
this.blocks = sectionData.blockStates;
this.blockLight = sectionData.getBlockLight();
this.skyLight = sectionData.getSkyLight();
this.bitsPerBlock = this.blocks.length >> 6; // available longs * 64 (bits per long) / 4096 (blocks per section) (floored result)
}
public BlockState getBlockState(int x, int y, int z) {
if (blockPalette.length == 1) return blockPalette[0];
if (blockPalette.length == 0) return BlockState.AIR;
int id = (int) MCAUtil.getValueFromLongStream(
blocks,
(y & 0xF) << 8 | (z & 0xF) << 4 | x & 0xF,
bitsPerBlock
);
if (id >= blockPalette.length) {
Logger.global.noFloodWarning("palette-warning", "Got block-palette id " + id + " but palette has size of " + blockPalette.length + "! (Future occasions of this error will not be logged)");
return BlockState.MISSING;
}
return blockPalette[id];
}
public LightData getLightData(int x, int y, int z, LightData target) {
if (blockLight.length == 0 && skyLight.length == 0) return target.set(0, 0);
int blockByteIndex = (y & 0xF) << 8 | (z & 0xF) << 4 | x & 0xF;
int blockHalfByteIndex = blockByteIndex >> 1;
boolean largeHalf = (blockByteIndex & 0x1) != 0;
return target.set(
this.skyLight.length > blockHalfByteIndex ? MCAUtil.getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0,
this.blockLight.length > blockHalfByteIndex ? MCAUtil.getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0
);
}
public int getSectionY() {
return sectionY;
}
}
@Getter
@SuppressWarnings("FieldMayBeFinal")
public static class Data extends MCAChunk.Data {
private Level level = EMPTY_LEVEL;
}
@Getter
@SuppressWarnings("FieldMayBeFinal")
public static class Level {
private Key status = STATUS_EMPTY;
private long inhabitedTime = 0;
private HeightmapsData heightmaps = EMPTY_HEIGHTMAPS_DATA;
private SectionData @Nullable [] sections = null;
private int[] biomes = EMPTY_INT_ARRAY;
}
@Getter
@SuppressWarnings("FieldMayBeFinal")
protected static class HeightmapsData {
@NBTName("WORLD_SURFACE") private long[] worldSurface = EMPTY_LONG_ARRAY;
@NBTName("OCEAN_FLOOR") private long[] oceanFloor = EMPTY_LONG_ARRAY;
}
@Getter
@SuppressWarnings("FieldMayBeFinal")
protected static class SectionData {
private int y = 0;
private byte[] blockLight = EMPTY_BYTE_ARRAY;
private byte[] skyLight = EMPTY_BYTE_ARRAY;
private BlockState[] palette = EMPTY_BLOCKSTATE_ARRAY;
private long[] blockStates = EMPTY_LONG_ARRAY;
}
}

View File

@ -1,7 +1,9 @@
package de.bluecolored.bluemap.core.world.mca.data;
import de.bluecolored.bluemap.api.debug.DebugDump;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.HashMap;
import java.util.Map;
@ -28,6 +30,8 @@ public class LevelData {
}
@Getter
@NoArgsConstructor
@AllArgsConstructor
@DebugDump
public static class Dimension {
private String type = "minecraft:overworld";