Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ repositories {
name = "sonatypeSnapshots"
mavenContent { snapshotsOnly() }
}
maven ( "https://repo.bluecolored.de/releases" ) {
content { includeGroupByRegex ("de\\.bluecolored.*") }
}
mavenCentral()
maven("https://jitpack.io")
}
Expand All @@ -46,7 +49,7 @@ dependencies {
implementation(libs.adventurePlatformFacet)

implementation(libs.caffeine)
implementation(libs.querzNbt)
implementation(libs.bluenbt)
implementation(libs.lz4Java)
implementation(libs.simpleYaml) {
exclude("org.yaml", "snakeyaml")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ public class PackedIntArrayAccess {
private final long maxValue, indexScale, indexOffset;
private final int elementsPerLong, indexShift;

public PackedIntArrayAccess(long[] data, int elementCount) {
this(Math.max(data.length * Long.SIZE / elementCount, 1), data);
}

public PackedIntArrayAccess(int bitsPerElement, long[] data) {
this.bitsPerElement = bitsPerElement;
this.data = data;
Expand All @@ -127,4 +131,13 @@ private int storageIndex(int i) {
return (int) ((long) i * this.indexScale + this.indexOffset >> this.indexShift);
}

public int getCapacity() {
return data.length * elementsPerLong;
}

public boolean isCorrectSize(int expectedSize) {
int capacity = getCapacity();
return expectedSize <= capacity && expectedSize + elementsPerLong > capacity;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.pl3x.map.core.world;

import de.bluecolored.bluenbt.NBTReader;
import de.bluecolored.bluenbt.TypeDeserializer;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import net.pl3x.map.core.Pl3xMap;

public class BlockStateDeserializer implements TypeDeserializer<BlockState> {

@Override
public BlockState read(NBTReader reader) throws IOException {
reader.beginCompound();

String id = null;
Map<String, String> properties = null;

while (reader.hasNext()) {
switch (reader.name()) {
case "Name" -> id = reader.nextString();
case "Properties" -> {
properties = new LinkedHashMap<>();
reader.beginCompound();
while (reader.hasNext())
properties.put(reader.name(), reader.nextString());
reader.endCompound();
}
default -> reader.skip();
}
}

reader.endCompound();

if (id == null) return Blocks.AIR.getDefaultState();

Block block = Pl3xMap.api().getBlockRegistry().getOrDefault(id, Blocks.AIR);
return properties == null ? new BlockState(block) : new BlockState(block, properties);
}

}
96 changes: 46 additions & 50 deletions core/src/main/java/net/pl3x/map/core/world/Chunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,63 +23,48 @@
*/
package net.pl3x.map.core.world;

import de.bluecolored.bluenbt.NBTName;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import net.pl3x.map.core.util.Colors;
import net.querz.nbt.tag.ByteTag;
import net.querz.nbt.tag.CompoundTag;
import net.querz.nbt.tag.IntTag;
import net.querz.nbt.tag.Tag;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

@NullMarked
public abstract class Chunk {

protected static final int BLOCKS_PER_SECTION = 16 * 16 * 16;
protected static final int VALUES_PER_HEIGHTMAP = 16 * 16;

protected static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
protected static final int[] EMPTY_INT_ARRAY = new int[0];
protected static final long[] EMPTY_LONG_ARRAY = new long[0];
protected static final String[] EMPTY_STRING_ARRAY = new String[0];
protected static final BlockState[] EMPTY_BLOCKSTATE_ARRAY = new BlockState[0];

private final World world;
private final Region region;

private final int dataVersion;

private final int xPos;
private final int yPos;
private final int zPos;

private final long inhabitedTime;

protected final BlockData[] data = new BlockData[256];

protected boolean populated;

protected Chunk(World world, Region region) {
this.world = world;
this.region = region;

this.xPos = 0;
this.yPos = 0;
this.zPos = 0;

this.inhabitedTime = 0;
}

protected Chunk(World world, Region region, CompoundTag tag, int index) {
protected Chunk(World world, Region region, Data chunkData, int index) {
this.world = world;
this.region = region;

this.xPos = pos(tag.get("xPos"), () -> (region.getX() << 5) + (index & 31));
this.yPos = pos(tag.get("yPos"), () -> world.getMinBuildHeight() >> 4);
this.zPos = pos(tag.get("zPos"), () -> (region.getZ() << 5) + (index << 5));

this.inhabitedTime = tag.getLong("InhabitedTime");
}
this.dataVersion = chunkData.dataVersion;

private int pos(Tag<?> tag, Supplier<Integer> failsafe) {
if (tag instanceof IntTag intTag) {
return intTag.asInt();
}
if (tag instanceof ByteTag byteTag) {
return byteTag.asInt();
}
return failsafe.get();
this.xPos = (region.getX() << 5) + (index & 31);
this.yPos = world.getMinBuildHeight() >> 4;
this.zPos = (region.getZ() << 5) + (index << 5);
}

public World getWorld() {
Expand All @@ -90,6 +75,10 @@ public Region getRegion() {
return this.region;
}

public int getDataVersion() {
return dataVersion;
}

public int getX() {
return this.xPos;
}
Expand All @@ -102,13 +91,19 @@ public int getZ() {
return this.zPos;
}

public long getInhabitedTime() {
return this.inhabitedTime;
}
public abstract int getMinY();

public abstract int getMaxY();

public abstract long getInhabitedTime();

public abstract boolean isFull();

public abstract boolean noHeightmap();
public abstract boolean hasWorldSurfaceHeights();

public boolean noHeightmap() {
return !hasWorldSurfaceHeights();
}

public abstract int getWorldSurfaceY(int x, int z);

Expand All @@ -132,7 +127,7 @@ public Chunk populate() {
for (int blockZ = startX; blockZ < startX + 16; blockZ++) {
for (int blockX = startZ; blockX < startZ + 16; blockX++) {
BlockData data = new BlockData();
data.blockY = noHeightmap() ? getWorld().getMaxBuildHeight() : getWorldSurfaceY(blockX, blockZ) + 1;
data.blockY = noHeightmap() ? getMaxY() : getWorldSurfaceY(blockX, blockZ) + 1;

// if world has ceiling iterate down until we find air
if (getWorld().hasCeiling()) {
Expand Down Expand Up @@ -198,18 +193,6 @@ public BlockData[] getData() {
return this.data[((z & 0xF) << 4) + (x & 0xF)];
}

public static Chunk create(World world, Region region, CompoundTag tag, int index) {
// https://minecraft.wiki/w/Data_version#List_of_data_versions
int version = tag.getInt("DataVersion");
Chunk chunk;
if (version < 1519) chunk = new EmptyChunk(world, region); // wtf, older than 1.13
else if (version < 2200) chunk = new ChunkAnvil113(world, region, tag, index); // 1.13 - 1.14
else if (version < 2500) chunk = new ChunkAnvil115(world, region, tag, index); // 1.15
else if (version < 2844) chunk = new ChunkAnvil116(world, region, tag, index); // 1.16 - 1.18 (21w42a)
else chunk = new ChunkAnvil118(world, region, tag, index); // 1.18+ (21w43a+)
return chunk.isFull() ? chunk : new EmptyChunk(world, region);
}

@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
Expand Down Expand Up @@ -296,4 +279,17 @@ public List<Integer> getGlassColors() {
return this.glass;
}
}

@SuppressWarnings("FieldMayBeFinal")
public static class Data {

@NBTName("DataVersion")
private int dataVersion = 0;

public int getDataVersion() {
return dataVersion;
}

}

}
Loading
Loading