Archived
0

обработка NBT в чанках

This commit is contained in:
2018-12-23 21:14:48 +03:00
parent d783317b5d
commit bd0d762df5
14 changed files with 209 additions and 17 deletions

View File

@@ -1,5 +1,6 @@
package mc.world.anvil;
import com.flowpowered.nbt.CompoundTag;
import lombok.extern.slf4j.Slf4j;
import mc.core.world.block.Block;
import mc.core.world.block.BlockLocation;
@@ -49,6 +50,20 @@ public class AnvilBlock implements Block {
return globalLocation;
}
@Override
public CompoundTag getNBTData() {
CompoundTag compoundTag = chunkSection.getParent().getNbtByGlobalXYZ(
(chunkSection.getX() << 4) + location.getX(),
(chunkSection.getY() << 4) + location.getY(),
(chunkSection.getZ() << 4) + location.getZ()
);
compoundTag.getValue().remove("Items");
compoundTag.getValue().remove("Lock");
return compoundTag;
}
@Override
public String toString() {
return "AnvilBlock{" +

View File

@@ -20,6 +20,7 @@ public class AnvilChunk implements Chunk {
private int z;
private TByteList biomes = new TByteArrayList(256);
private List<ChunkSection> sections;
private ListTag<CompoundTag> tileEntities;
@SuppressWarnings("unchecked")
AnvilChunk(CompoundTag chunkTag) {
@@ -29,6 +30,7 @@ public class AnvilChunk implements Chunk {
this.z = ((IntTag) levelTagMap.get("zPos")).getValue();
biomes.add(((ByteArrayTag) levelTagMap.get("Biomes")).getValue());
tileEntities = (ListTag<CompoundTag>) levelTagMap.get("TileEntities");
List<CompoundTag> sections = ((ListTag<CompoundTag>) levelTagMap.get("Sections")).getValue();
this.sections = new ArrayList<>(sections.size());
@@ -49,6 +51,18 @@ public class AnvilChunk implements Chunk {
}
}
CompoundTag getNbtByGlobalXYZ(int x, int y, int z) {
for (CompoundTag compoundTag : tileEntities.getValue()) {
CompoundMap compoundMap = compoundTag.getValue();
if (((IntTag)compoundMap.get("x")).getValue() == x
&& ((IntTag)compoundMap.get("y")).getValue() == y
&& ((IntTag)compoundMap.get("z")).getValue() == z) {
return compoundTag;
}
}
return null;
}
@Override
public ChunkSection getChunkSection(int height) {
if (height > sections.size()-1) return null;

View File

@@ -1,5 +1,9 @@
package mc.world.anvil;
import com.flowpowered.nbt.CompoundMap;
import com.flowpowered.nbt.CompoundTag;
import com.flowpowered.nbt.IntTag;
import com.flowpowered.nbt.StringTag;
import lombok.SneakyThrows;
import mc.core.world.block.Block;
import mc.core.world.block.BlockType;
@@ -60,6 +64,16 @@ class RegionTest {
}
}
private CompoundTag createExceptedNBT(Block block) {
CompoundMap compoundMap = new CompoundMap();
compoundMap.put(new IntTag("x", block.getLocation().getX()));
compoundMap.put(new IntTag("y", block.getLocation().getY()));
compoundMap.put(new IntTag("z", block.getLocation().getZ()));
compoundMap.put(new StringTag("id", block.getBlockType().getNamedId()));
return new CompoundTag("", compoundMap);
}
private void checkSection2(ChunkSection chunkSection) {
for (int y = 0; y < 16; y++) {
for (int x = 0; x < 16; x++) {
@@ -70,6 +84,23 @@ class RegionTest {
// @formatter:off
if (y == 0) assertEquals(BlockType.DIRT, block.getBlockType(), msg);
else if (y == 1) assertEquals(BlockType.GRASS, block.getBlockType(), msg);
else if (y == 2) {
if ((x == 2 || x == 4 || x == 5) && z == 1) {
assertEquals(BlockType.CHEST_NORTH, block.getBlockType(), msg);
assertEquals(createExceptedNBT(block), block.getNBTData());
} else if ((x == 2 || x == 3 || x == 5) && z == 6) {
assertEquals(BlockType.CHEST_SOUTH, block.getBlockType(), msg);
assertEquals(createExceptedNBT(block), block.getNBTData());
} else if (x == 1 && (z == 2 || z == 3 || z == 5)) {
assertEquals(BlockType.CHEST_WEST, block.getBlockType(), msg);
assertEquals(createExceptedNBT(block), block.getNBTData());
} else if (x == 6 && (z == 2 || z == 4 || z == 5)) {
assertEquals(BlockType.CHEST_EAST, block.getBlockType(), msg);
assertEquals(createExceptedNBT(block), block.getNBTData());
} else {
assertEquals(BlockType.AIR, block.getBlockType(), msg);
}
}
else assertEquals(BlockType.AIR, block.getBlockType(), msg);
// @formatter:on
}

View File

@@ -1,5 +1,6 @@
package mc.core.network;
import com.flowpowered.nbt.Tag;
import lombok.Getter;
import lombok.Setter;
@@ -29,6 +30,7 @@ public abstract class NetInputStream extends InputStream {
public abstract double readDouble();
public abstract String readString();
public abstract UUID readUUID();
public abstract Tag<?> readNBT();
public abstract void skipBytes(int count);

View File

@@ -1,5 +1,7 @@
package mc.core.network;
import com.flowpowered.nbt.Tag;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;
@@ -20,6 +22,7 @@ public abstract class NetOutputStream extends OutputStream {
public abstract void writeDouble(double value);
public abstract void writeString(String value);
public abstract void writeUUID(UUID uuid);
public abstract void writeNBT(Tag<?> tag);
@Override
public void write(int b) throws IOException {

View File

@@ -1,8 +1,17 @@
package mc.core.world.block;
import com.flowpowered.nbt.CompoundTag;
public interface Block {
int getLight();
void setLight(int light);
BlockType getBlockType();
BlockLocation getLocation();
default CompoundTag getNBTData() {
return null;
}
default void setNBTData(CompoundTag nbtData) {
}
}

View File

@@ -96,11 +96,10 @@ public enum BlockType {
MOSS_STONE(48, 0),
OBSIDIAN(49, 0),
MONSTER_SPAWNER(52, 0),
//BAG CHUNK
// CHEST_NORTH(54, 2),
// CHEST_SOUTH(54, 3),
// CHEST_WEST (54, 4),
// CHEST_EAST (54, 5),
CHEST_NORTH(54, 2, "minecraft:chest"),
CHEST_SOUTH(54, 3, "minecraft:chest"),
CHEST_WEST (54, 4, "minecraft:chest"),
CHEST_EAST (54, 5, "minecraft:chest"),
ORE_DIAMOND(56, 0),
ORE_REDSTONE(73, 0),
ORE_GLOWING_REDSTONE(74, 0),
@@ -118,6 +117,12 @@ public enum BlockType {
PEONY(175, 5),
ROSE_BUSH_10(175, 10);
BlockType(int id, int meta) {
this.id = id;
this.meta = meta;
this.namedId = null;
}
public static BlockType getByIdMeta(int id, int meta) {
if (id < 0) {
log.warn("Incorrect id \"{}\"", id);
@@ -137,4 +142,6 @@ public enum BlockType {
private final int id;
@Getter
private final int meta;
@Getter
private final String namedId;
}

View File

@@ -1,13 +1,18 @@
package mc.core.network.proto_1_12_2;
import com.flowpowered.nbt.Tag;
import com.flowpowered.nbt.stream.NBTInputStream;
import lombok.extern.slf4j.Slf4j;
import mc.core.network.NetInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
@Slf4j
public abstract class NetInputStream_p340 extends NetInputStream {
private NBTInputStream nbtInputStream;
@Override
public int readVarInt(int[] countReadBytes) {
int numRead = 0;
@@ -51,4 +56,23 @@ public abstract class NetInputStream_p340 extends NetInputStream {
public UUID readUUID() {
return new UUID(readLong(), readLong());
}
@Override
public Tag<?> readNBT() {
if (nbtInputStream == null) {
try {
nbtInputStream = new NBTInputStream(this, false);
} catch (IOException e) {
log.error("Create NBT stream", e);
return null;
}
}
try {
return nbtInputStream.readTag();
} catch (IOException e) {
log.error("Read NBT", e);
return null;
}
}
}

View File

@@ -1,13 +1,18 @@
package mc.core.network.proto_1_12_2;
import com.flowpowered.nbt.Tag;
import com.flowpowered.nbt.stream.NBTOutputStream;
import lombok.extern.slf4j.Slf4j;
import mc.core.network.NetOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
@Slf4j
public abstract class NetOutputStream_p340 extends NetOutputStream {
private NBTOutputStream nbtOutputStream;
@Override
public void writeVarInt(int value) {
while ((value & -128) != 0) {
@@ -37,4 +42,22 @@ public abstract class NetOutputStream_p340 extends NetOutputStream {
writeLong(uuid.getMostSignificantBits());
writeLong(uuid.getLeastSignificantBits());
}
@Override
public void writeNBT(Tag<?> tag) {
if (nbtOutputStream == null) {
try {
nbtOutputStream = new NBTOutputStream(this, false);
} catch (IOException e) {
log.error("Create NBT stream", e);
return;
}
}
try {
nbtOutputStream.writeTag(tag);
} catch (IOException e) {
log.error("Write NBT", e);
}
}
}

View File

@@ -1,5 +1,6 @@
package mc.core.network.proto_1_12_2.packets;
import com.flowpowered.nbt.CompoundTag;
import gnu.trove.list.TIntList;
import gnu.trove.list.array.TIntArrayList;
import lombok.NoArgsConstructor;
@@ -15,6 +16,7 @@ import mc.core.world.block.BlockType;
import mc.core.world.chunk.Chunk;
import mc.core.world.chunk.ChunkSection;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -133,6 +135,8 @@ public class ChunkDataPacket implements SCPacket {
final ByteArrayOutputNetStream biomes = new ByteArrayOutputNetStream();
boolean biomeWrite = true;
List<CompoundTag> nbtList = new ArrayList<>();
for (int h = 0; h < maxH; h++) {
ChunkSection chunkSection = null;
@@ -151,11 +155,18 @@ public class ChunkDataPacket implements SCPacket {
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
Block block = chunkSection.getBlockLocal(x, y, z);
palettedChunkSection.addBlock(
chunkSection.getBlockLocal(x, y, z),
block,
chunkSection.getSkyLightLocal(x, y, z)
);
CompoundTag nbt = block.getNBTData();
if (nbt != null) {
nbtList.add(nbt);
}
if (biomeWrite) {
biomes.writeByte(chunk.getBiomeLocal(x, z).getId());
if (x == 15 && z == 15) {
@@ -176,8 +187,12 @@ public class ChunkDataPacket implements SCPacket {
netStream.writeVarInt(data.size()); // Size of Data
netStream.writeBytes(data.toByteArray()); // Data
netStream.writeVarInt(0); // Number of block entities
/* writeNBT */
netStream.writeVarInt(nbtList.size()); // Number of block entities
// <NBT>
for (CompoundTag compoundTag : nbtList) {
netStream.writeNBT(compoundTag);
}
// </NBT>
}
@Override

View File

@@ -1,10 +1,10 @@
package mc.core.network.proto_1_12_2.packets;
import com.flowpowered.nbt.*;
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
import mc.core.network.proto_1_12_2.packets.DumbChunkData.DumbChunkSection;
import mc.core.world.Biome;
import mc.core.world.block.BlockFactory;
import mc.core.world.block.BlockType;
import mc.core.world.block.*;
import mc.core.world.chunk.Chunk;
import mc.core.world.chunk.ChunkSection;
import org.apache.commons.io.IOUtils;
@@ -72,6 +72,29 @@ class ChunkDataPacketTest {
setupActualData();
}
private static Block createChestBlock(BlockType type, int x, int y, int z, int height) {
final BlockLocation location = new BlockLocation(x, y, z);
final CompoundMap compoundMap = new CompoundMap();
compoundMap.put(new IntTag("x", x));
compoundMap.put(new IntTag("y", (height << 4) + y));
compoundMap.put(new IntTag("z", z));
compoundMap.put(new StringTag("id", type.getNamedId()));
final CompoundTag compoundTag = new CompoundTag("", compoundMap);
return new AbstractBlock(type) {
@Override
public BlockLocation getLocation() {
return location;
}
@Override
public CompoundTag getNBTData() {
return compoundTag;
}
};
}
private static ChunkSection createChunkSection(int height) {
final ChunkSection chunkSection = mock(ChunkSection.class);
when(chunkSection.getSkyLightLocal(anyInt(), anyInt(), anyInt())).thenReturn(0);
@@ -107,13 +130,23 @@ class ChunkDataPacketTest {
BlockFactory blockFactory = new BlockFactory();
if (y == 0) {
return blockFactory.create(BlockType.DIRT, x, y, z);
} else if (y == 1) {
return blockFactory.create(BlockType.GRASS, x, y, z);
} else {
// @formatter:off
if (y == 0) return blockFactory.create(BlockType.DIRT, x, y, z);
else if (y == 1) return blockFactory.create(BlockType.GRASS, x, y, z);
else if (y == 2) {
if ((x == 2 || x == 4 || x == 5) && z == 1)
return createChestBlock(BlockType.CHEST_NORTH, x, y, z, height);
else if ((x == 2 || x == 3 || x == 5) && z == 6)
return createChestBlock(BlockType.CHEST_SOUTH, x, y, z, height);
else if (x == 1 && (z == 2 || z == 3 || z == 5))
return createChestBlock(BlockType.CHEST_WEST, x, y, z, height);
else if (x == 6 && (z == 2 || z == 4 || z == 5))
return createChestBlock(BlockType.CHEST_EAST, x, y, z, height);
else
return blockFactory.create(BlockType.AIR, x, y, z);
}
else return blockFactory.create(BlockType.AIR, x, y, z);
// @formatter:on
});
}
@@ -132,6 +165,11 @@ class ChunkDataPacketTest {
@Test
void testNBT() {
assertEquals(expectedDumbChunkData.getNumberNBT(), actualDumbChunkData.getNumberNBT());
assertEquals(expectedDumbChunkData.getNbt().size(), actualDumbChunkData.getNbt().size());
for (Tag<?> tag : actualDumbChunkData.getNbt()) {
assertTrue(expectedDumbChunkData.getNbt().contains(tag));
}
}
@Test

View File

@@ -1,5 +1,6 @@
package mc.core.network.proto_1_12_2.packets;
import com.flowpowered.nbt.Tag;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
@@ -8,6 +9,7 @@ import mc.core.world.block.BlockType;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@@ -23,9 +25,10 @@ class DumbChunkData {
private byte[] biomes;
private int numberNBT;
private List<Tag<?>> nbt;
private static BlockType deserializeBlockState(int blockState) {
return BlockType.getByIdMeta((blockState & 0xF0) >> 4, blockState & 0x0F);
return BlockType.getByIdMeta(blockState >> 4, blockState & 0x0F);
}
static DumbChunkData ReadFromNetInputStream(byte[] bytes) {
@@ -95,6 +98,14 @@ class DumbChunkData {
netStream.readBytes(dumbChunkData.biomes);
dumbChunkData.numberNBT = netStream.readVarInt();
if (dumbChunkData.numberNBT > 0) {
dumbChunkData.nbt = new ArrayList<>(dumbChunkData.numberNBT);
for (int i = 0; i < dumbChunkData.numberNBT; i++) {
dumbChunkData.nbt.add(netStream.readNBT());
}
} else {
dumbChunkData.nbt = Collections.emptyList();
}
return dumbChunkData;
}