Port to Hephaistos v2 (#424)

This commit is contained in:
Xavier Niochaut 2021-12-13 16:41:30 +01:00 committed by TheMode
parent f43ffd64cb
commit 9ab4277502
53 changed files with 583 additions and 450 deletions

View File

@ -152,13 +152,13 @@ dependencies {
api "org.jetbrains.kotlin:kotlin-reflect:${project.kotlinVersion}"
// NBT parsing/manipulation/saving
api("com.github.jglrxavpok:Hephaistos:${project.hephaistosVersion}")
api("com.github.jglrxavpok:Hephaistos:${project.hephaistosVersion}:gson")
api("com.github.jglrxavpok:Hephaistos:${project.hephaistosVersion}") {
api("io.github.jglrxavpok.hephaistos:common:${project.hephaistosVersion}")
api("io.github.jglrxavpok.hephaistos:gson:${project.hephaistosVersion}")
/* api("io.github.jglrxavpok.hephaistos:common:${project.hephaistosVersion}") {
capabilities {
requireCapability("org.jglrxavpok.nbt:Hephaistos-gson")
requireCapability("io.github.jglrxavpok.hephaistos:Hephaistos-gson")
}
}
}*/
api "com.github.Minestom:DependencyGetter:v1.0.1"
implementation 'com.github.Minestom:MinestomDataGenerator:801b8007cf'

View File

@ -3,6 +3,6 @@ mcVersion = 1.17
asmVersion=9.2
mixinVersion=0.8.4
hephaistosVersion=v1.1.8
hephaistosVersion=2.3.0
kotlinVersion=1.5.31
adventureVersion=4.9.3
adventureVersion=4.9.3

View File

@ -11,7 +11,7 @@ import java.util.Objects;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.nbt.SNBTParser;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
/**
* Adventure related constants, etc.

View File

@ -16,6 +16,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTException;
import java.io.IOException;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer {
static final NBTLegacyHoverEventSerializer INSTANCE = new NBTLegacyHoverEventSerializer();
@ -66,17 +67,23 @@ final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer
@Override
public @NotNull Component serializeShowItem(HoverEvent.@NotNull ShowItem input) throws IOException {
final NBTCompound tag = new NBTCompound();
tag.setString(ITEM_TYPE, input.item().asString());
tag.setByte(ITEM_COUNT, (byte) input.count());
AtomicReference<NBTException> exception = new AtomicReference<>(null);
final NBTCompound tag = NBT.Compound(t -> {
t.setString(ITEM_TYPE, input.item().asString());
t.setByte(ITEM_COUNT, (byte) input.count());
final BinaryTagHolder nbt = input.nbt();
if (nbt != null) {
try {
tag.set(ITEM_TAG, nbt.get(MinestomAdventure.NBT_CODEC));
} catch (NBTException e) {
throw new IOException(e);
final BinaryTagHolder nbt = input.nbt();
if (nbt != null) {
try {
t.set(ITEM_TAG, nbt.get(MinestomAdventure.NBT_CODEC));
} catch (NBTException e) {
exception.set(e);
}
}
});
if(exception.get() != null) {
throw new IOException(exception.get());
}
return Component.text(MinestomAdventure.NBT_CODEC.encode(tag));
@ -84,14 +91,15 @@ final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer
@Override
public @NotNull Component serializeShowEntity(HoverEvent.@NotNull ShowEntity input, Codec.Encoder<Component, String, ? extends RuntimeException> componentEncoder) throws IOException {
final NBTCompound tag = new NBTCompound();
tag.setString(ENTITY_ID, input.id().toString());
tag.setString(ENTITY_TYPE, input.type().asString());
final NBTCompound tag = NBT.Compound(t -> {
t.setString(ENTITY_ID, input.id().toString());
t.setString(ENTITY_TYPE, input.type().asString());
final Component name = input.name();
if (name != null) {
tag.setString(ENTITY_NAME, componentEncoder.encode(name));
}
final Component name = input.name();
if (name != null) {
t.setString(ENTITY_NAME, componentEncoder.encode(name));
}
});
return Component.text(MinestomAdventure.NBT_CODEC.encode(tag));
}

View File

@ -9,6 +9,7 @@ import net.minestom.server.tag.Tag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -23,7 +24,7 @@ public class ConsoleSender implements CommandSender {
private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleSender.class);
private final Set<Permission> permissions = new CopyOnWriteArraySet<>();
private final NBTCompound nbtCompound = new NBTCompound();
private final MutableNBTCompound nbtCompound = new MutableNBTCompound();
@Override
public void sendMessage(@NotNull String message) {

View File

@ -7,6 +7,7 @@ import net.minestom.server.tag.Tag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.util.Collections;
import java.util.HashSet;
@ -22,7 +23,7 @@ import java.util.Set;
public class ServerSender implements CommandSender {
private final Set<Permission> permissions = Collections.unmodifiableSet(new HashSet<>());
private final NBTCompound nbtCompound = new NBTCompound();
private final MutableNBTCompound nbtCompound = new MutableNBTCompound();
@NotNull
@Override

View File

@ -9,7 +9,7 @@ import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.nbt.SNBTParser;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.io.StringReader;

View File

@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.nbt.SNBTParser;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.io.StringReader;

View File

@ -7,7 +7,7 @@ import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.nbt.SNBTParser;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.io.StringReader;

View File

@ -51,6 +51,7 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.time.Duration;
import java.time.temporal.TemporalUnit;
@ -143,7 +144,7 @@ public class Entity implements Viewable, Tickable, TagHandler, PermissionHandler
this instanceof Player player ? entity -> entity.viewEngine.viewableOption.addition.accept(player) : null,
this instanceof Player player ? entity -> entity.viewEngine.viewableOption.removal.accept(player) : null);
protected final Set<Player> viewers = viewEngine.asSet();
private final NBTCompound nbtCompound = new NBTCompound();
private final MutableNBTCompound nbtCompound = new MutableNBTCompound();
private final Set<Permission> permissions = new CopyOnWriteArraySet<>();
protected UUID uuid;

View File

@ -161,7 +161,7 @@ public class Metadata {
EMPTY_VALUES.set(TYPE_DIRECTION, Direction(Direction.DOWN));
EMPTY_VALUES.set(TYPE_OPTUUID, OptUUID(null));
EMPTY_VALUES.set(TYPE_OPTBLOCKID, OptBlockID(null));
EMPTY_VALUES.set(TYPE_NBT, NBT(new NBTEnd()));
EMPTY_VALUES.set(TYPE_NBT, NBT(NBTEnd.INSTANCE));
//EMPTY_VALUES.set(TYPE_PARTICLE -> throw new UnsupportedOperationException();
EMPTY_VALUES.set(TYPE_VILLAGERDATA, VillagerData(0, 0, 0));
EMPTY_VALUES.set(TYPE_OPTVARINT, OptVarInt(null));

View File

@ -84,6 +84,7 @@ import org.jctools.queues.MpscUnboundedXaddArrayQueue;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.nio.charset.StandardCharsets;
@ -237,11 +238,12 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
public void UNSAFE_init(@NotNull Instance spawnInstance) {
this.dimensionType = spawnInstance.getDimensionType();
NBTCompound nbt = new NBTCompound();
NBTCompound dimensions = MinecraftServer.getDimensionTypeManager().toNBT();
NBTCompound biomes = MinecraftServer.getBiomeManager().toNBT();
nbt.set("minecraft:dimension_type", dimensions);
nbt.set("minecraft:worldgen/biome", biomes);
NBTCompound nbt = NBT.Compound(n -> {
NBTCompound dimensions = MinecraftServer.getDimensionTypeManager().toNBT();
NBTCompound biomes = MinecraftServer.getBiomeManager().toNBT();
n.set("minecraft:dimension_type", dimensions);
n.set("minecraft:worldgen/biome", biomes);
});
final JoinGamePacket joinGamePacket = new JoinGamePacket(getEntityId(), gameMode.isHardcore(), gameMode, null,
List.of("minestom:world"), nbt, dimensionType.toNBT(), dimensionType.getName().asString(),

View File

@ -10,6 +10,7 @@ import net.minestom.server.tag.TagHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
/**
* Represents a type of damage, required when calling {@link LivingEntity#damage(DamageType, float)}
@ -29,7 +30,7 @@ public class DamageType implements TagHandler {
};
private final String identifier;
private final Object nbtLock = new Object();
private final NBTCompound nbt = new NBTCompound();
private final MutableNBTCompound nbt = new MutableNBTCompound();
/**
* Creates a new damage type.

View File

@ -470,7 +470,7 @@ public class ExtensionManager {
// While there are entries with no more elements (no more dependencies)
while (!(
loadableExtensions = dependencyMap.entrySet().stream().filter(entry -> isLoaded(entry.getValue())).collect(Collectors.toList())
loadableExtensions = dependencyMap.entrySet().stream().filter(entry -> isLoaded(entry.getValue())).toList()
).isEmpty()
) {
// Get all "loadable" (not actually being loaded!) extensions and put them in the sorted list.

View File

@ -6,6 +6,7 @@ import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.async.AsyncUtils;
import net.minestom.server.world.biomes.Biome;
import net.minestom.server.world.biomes.BiomeManager;
@ -13,6 +14,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.mca.*;
import org.jglrxavpok.hephaistos.nbt.*;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -22,8 +24,7 @@ import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
@ -87,20 +88,31 @@ public class AnvilLoader implements IChunkLoader {
return CompletableFuture.completedFuture(null);
Chunk chunk = new DynamicChunk(instance, chunkX, chunkZ);
// TODO Biomes
// TODO: Parallelize block, block entities and biome loading
if (fileChunk.getGenerationStatus().compareTo(ChunkColumn.GenerationStatus.Biomes) > 0) {
final int[] fileChunkBiomes = fileChunk.getBiomes();
for (int id : fileChunkBiomes) {
// ((y >> 2) & 63) << 4 | ((z >> 2) & 3) << 2 | ((x >> 2) & 3)
final Biome biome = Objects.requireNonNullElse(BIOME_MANAGER.getById(id), BIOME);
chunk.setBiome(0, 0, 0, biome);
HashMap<String, Biome> biomeCache = new HashMap<>();
for (ChunkSection section : fileChunk.getSections().values()) {
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
int finalX = fileChunk.getX() * Chunk.CHUNK_SIZE_X + x;
int finalZ = fileChunk.getZ() * Chunk.CHUNK_SIZE_Z + z;
int finalY = section.getY() * Chunk.CHUNK_SECTION_SIZE + y;
String biomeName = section.getBiome(x, y, z);
Biome biome = biomeCache.computeIfAbsent(biomeName, n -> Objects.requireNonNullElse(BIOME_MANAGER.getByName(NamespaceID.from(n)), BIOME));
chunk.setBiome(finalX, finalY, finalZ, biome);
}
}
}
}
}
// Blocks
loadBlocks(chunk, fileChunk);
loadTileEntities(chunk, fileChunk);
// Lights
for (var chunkSection : fileChunk.getSections()) {
for (var chunkSection : fileChunk.getSections().values()) {
Section section = chunk.getSection(chunkSection.getY());
section.setSkyLight(chunkSection.getSkyLights());
section.setBlockLight(chunkSection.getBlockLights());
@ -127,7 +139,7 @@ public class AnvilLoader implements IChunkLoader {
}
private void loadBlocks(Chunk chunk, ChunkColumn fileChunk) {
for (var section : fileChunk.getSections()) {
for (var section : fileChunk.getSections().values()) {
if (section.getEmpty()) continue;
final int yOffset = Chunk.CHUNK_SECTION_SIZE * section.getY();
for (int x = 0; x < Chunk.CHUNK_SECTION_SIZE; x++) {
@ -172,12 +184,15 @@ public class AnvilLoader implements IChunkLoader {
block = block.withHandler(handler);
}
// Remove anvil tags
te.removeTag("id")
.removeTag("x").removeTag("y").removeTag("z")
.removeTag("keepPacked");
MutableNBTCompound mutableCopy = te.toMutableCompound();
mutableCopy.remove("id");
mutableCopy.remove("x");
mutableCopy.remove("y");
mutableCopy.remove("z");
mutableCopy.remove("keepPacked");
// Place block
final var finalBlock = te.getSize() > 0 ?
block.withNbt(te) : block;
final var finalBlock = mutableCopy.getSize() > 0 ?
block.withNbt(mutableCopy.toCompound()) : block;
loadedChunk.setBlock(x, y, z, finalBlock);
}
}
@ -247,7 +262,7 @@ public class AnvilLoader implements IChunkLoader {
}
private void save(Chunk chunk, ChunkColumn chunkColumn) {
NBTList<NBTCompound> tileEntities = new NBTList<>(NBTTypes.TAG_Compound);
List<NBTCompound> tileEntities = new ArrayList<>();
chunkColumn.setGenerationStatus(ChunkColumn.GenerationStatus.Full);
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
@ -255,13 +270,15 @@ public class AnvilLoader implements IChunkLoader {
final Block block = chunk.getBlock(x, y, z);
// Block
chunkColumn.setBlockState(x, y, z, new BlockState(block.name(), block.properties()));
chunkColumn.setBiome(x, 0, z, chunk.getBiome(x, y, z).id());
chunkColumn.setBiome(x, 0, z, chunk.getBiome(x, y, z).name().asString());
// Tile entity
var nbt = block.nbt();
final BlockHandler handler = block.handler();
if (nbt != null || handler != null) {
nbt = Objects.requireNonNullElseGet(nbt, NBTCompound::new);
var originalNBT = block.nbt();
if (originalNBT != null || handler != null) {
MutableNBTCompound nbt = originalNBT != null ?
originalNBT.toMutableCompound() : new MutableNBTCompound();
if (handler != null) {
nbt.setString("id", handler.getNamespaceId().asString());
}
@ -269,12 +286,12 @@ public class AnvilLoader implements IChunkLoader {
nbt.setInt("y", y);
nbt.setInt("z", z + Chunk.CHUNK_SIZE_Z * chunk.getChunkZ());
nbt.setByte("keepPacked", (byte) 0);
tileEntities.add(nbt);
tileEntities.add(nbt.toCompound());
}
}
}
}
chunkColumn.setTileEntities(tileEntities);
chunkColumn.setTileEntities(NBT.List(NBTType.TAG_Compound, tileEntities));
}
@Override

View File

@ -17,6 +17,7 @@ import net.minestom.server.world.biomes.Biome;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.util.Set;
import java.util.UUID;
@ -55,7 +56,7 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
protected PFColumnarSpace columnarSpace;
// Data
private final NBTCompound nbt = new NBTCompound();
private final MutableNBTCompound nbt = new MutableNBTCompound();
public Chunk(@NotNull Instance instance, int chunkX, int chunkZ, boolean shouldGenerate) {
this.identifier = UUID.randomUUID();

View File

@ -22,6 +22,7 @@ import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.world.biomes.Biome;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.*;
@ -47,7 +48,7 @@ public class DynamicChunk extends Chunk {
public DynamicChunk(@NotNull Instance instance, int chunkX, int chunkZ) {
super(instance, chunkX, chunkZ, true);
this.minSection = instance.getDimensionType().getMinY() / CHUNK_SECTION_SIZE;
this.maxSection = instance.getDimensionType().getHeight() / CHUNK_SECTION_SIZE;
this.maxSection = (instance.getDimensionType().getMinY() + instance.getDimensionType().getHeight()) / CHUNK_SECTION_SIZE;
this.sections = new Section[maxSection - minSection];
Arrays.setAll(sections, value -> new Section());
}
@ -121,7 +122,7 @@ public class DynamicChunk extends Chunk {
}
}
// Retrieve the block from state id
final Section section = sections[ChunkUtils.getSectionAt(y) + minSection];
final Section section = sections[ChunkUtils.getSectionAt(y) - minSection];
final int blockStateId = section.blockPalette()
.get(toChunkRelativeCoordinate(x), y, toChunkRelativeCoordinate(z));
if (blockStateId == -1) return Block.AIR; // Section is empty
@ -130,7 +131,7 @@ public class DynamicChunk extends Chunk {
@Override
public @NotNull Biome getBiome(int x, int y, int z) {
final Section section = sections[ChunkUtils.getSectionAt(y) + minSection];
final Section section = sections[ChunkUtils.getSectionAt(y) - minSection];
final int id = section.biomePalette()
.get(toChunkRelativeCoordinate(x) / 4, y / 4, toChunkRelativeCoordinate(z) / 4);
return MinecraftServer.getBiomeManager().getById(id);
@ -186,9 +187,9 @@ public class DynamicChunk extends Chunk {
}
}
final int bitsForHeight = MathUtils.bitsToRepresent(dimensionHeight);
heightmapsNBT = new NBTCompound()
.setLongArray("MOTION_BLOCKING", Utils.encodeBlocks(motionBlocking, bitsForHeight))
.setLongArray("WORLD_SURFACE", Utils.encodeBlocks(worldSurface, bitsForHeight));
heightmapsNBT = NBT.Compound(Map.of(
"MOTION_BLOCKING", NBT.LongArray(Utils.encodeBlocks(motionBlocking, bitsForHeight)),
"WORLD_SURFACE", NBT.LongArray(Utils.encodeBlocks(worldSurface, bitsForHeight))));
}
// Data
final BinaryWriter writer = new BinaryWriter();

View File

@ -32,6 +32,7 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.time.Duration;
import java.util.*;
@ -84,7 +85,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, Tickable,
// instance custom data
private final Object nbtLock = new Object();
private final NBTCompound nbt = new NBTCompound();
private final MutableNBTCompound nbt = new MutableNBTCompound();
// the explosion supplier
private ExplosionSupplier explosionSupplier;

View File

@ -9,6 +9,7 @@ import net.minestom.server.utils.block.BlockUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.time.Duration;
import java.util.*;
@ -105,9 +106,9 @@ final class BlockImpl implements Block {
@Override
public @NotNull <T> Block withTag(@NotNull Tag<T> tag, @Nullable T value) {
var temporaryNbt = nbt != null ? nbt.deepClone() : new NBTCompound();
var temporaryNbt = new MutableNBTCompound(Objects.requireNonNullElse(nbt, NBTCompound.EMPTY));
tag.write(temporaryNbt, value);
final var finalNbt = temporaryNbt.getSize() > 0 ? NBT_CACHE.get(temporaryNbt, Function.identity()) : null;
final var finalNbt = temporaryNbt.getSize() > 0 ? NBT_CACHE.get(temporaryNbt.toCompound(), Function.identity()) : null;
return new BlockImpl(registry, propertyEntry, properties, finalNbt, handler);
}

View File

@ -10,6 +10,7 @@ import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.util.ArrayList;
import java.util.Arrays;
@ -32,7 +33,7 @@ public sealed abstract class AbstractInventory implements InventoryClickHandler,
protected final InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
private final Object nbtLock = new Object();
private final NBTCompound nbt = new NBTCompound();
private final MutableNBTCompound nbt = new MutableNBTCompound();
protected AbstractInventory(int size) {
this.size = size;

View File

@ -119,7 +119,7 @@ public class ItemMeta implements TagReadable, Writeable {
}
public @NotNull NBTCompound toNBT() {
return nbt.deepClone();
return nbt;
}
public @NotNull String toSNBT() {

View File

@ -12,6 +12,7 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.*;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import java.util.*;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
@ -75,7 +76,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
final String name = GsonComponentSerializer.gson().serialize(displayName);
nbtCompound.setString("Name", name);
} else {
nbtCompound.removeTag("Name");
nbtCompound.remove("Name");
}
});
return this;
@ -85,10 +86,11 @@ public abstract class ItemMetaBuilder implements TagWritable {
public @NotNull ItemMetaBuilder lore(@NotNull List<@NotNull Component> lore) {
this.lore = new ArrayList<>(lore);
handleCompound("display", nbtCompound -> {
final NBTList<NBTString> loreNBT = new NBTList<>(NBTTypes.TAG_String);
for (Component line : lore) {
loreNBT.add(new NBTString(GsonComponentSerializer.gson().serialize(line)));
}
final NBTList<NBTString> loreNBT = NBT.List(NBTType.TAG_String,
lore.stream()
.map(line -> new NBTString(GsonComponentSerializer.gson().serialize(line)))
.toList()
);
nbtCompound.set("Lore", loreNBT);
});
return this;
@ -104,8 +106,9 @@ public abstract class ItemMetaBuilder implements TagWritable {
public @NotNull ItemMetaBuilder enchantments(@NotNull Map<Enchantment, Short> enchantments) {
this.enchantmentMap = new HashMap<>(enchantments);
handleMap(enchantmentMap, "Enchantments", () -> {
NBTUtils.writeEnchant(nbt, "Enchantments", enchantmentMap);
return nbt.get("Enchantments");
MutableNBTCompound mutableCopy = new MutableNBTCompound(nbt);
NBTUtils.writeEnchant(mutableCopy, "Enchantments", enchantmentMap);
return mutableCopy.get("Enchantments");
});
return this;
}
@ -127,22 +130,19 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder attributes(@NotNull List<@NotNull ItemAttribute> attributes) {
this.attributes = new ArrayList<>(attributes);
handleCollection(attributes, "AttributeModifiers", () -> {
NBTList<NBTCompound> attributesNBT = new NBTList<>(NBTTypes.TAG_Compound);
for (ItemAttribute itemAttribute : attributes) {
final UUID uuid = itemAttribute.getUuid();
attributesNBT.add(
new NBTCompound()
.setIntArray("UUID", Utils.uuidToIntArray(uuid))
.setDouble("Amount", itemAttribute.getValue())
.setString("Slot", itemAttribute.getSlot().name().toLowerCase())
.setString("AttributeName", itemAttribute.getAttribute().getKey())
.setInt("Operation", itemAttribute.getOperation().getId())
.setString("Name", itemAttribute.getInternalName())
);
}
return attributesNBT;
});
handleCollection(attributes, "AttributeModifiers", () -> NBT.List(
NBTType.TAG_Compound,
attributes.stream()
.map(itemAttribute -> NBT.Compound(Map.of(
"UUID", NBT.IntArray(Utils.uuidToIntArray(itemAttribute.getUuid())),
"Amount", NBT.Double(itemAttribute.getValue()),
"Slot", NBT.String(itemAttribute.getSlot().name().toLowerCase()),
"AttributeName", NBT.String(itemAttribute.getAttribute().getKey()),
"Operation", NBT.Int(itemAttribute.getOperation().getId()),
"Name", NBT.String(itemAttribute.getInternalName()))))
.toList()
));
return this;
}
@ -157,11 +157,12 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder canPlaceOn(@NotNull Set<@NotNull Block> blocks) {
this.canPlaceOn = new HashSet<>(blocks);
handleCollection(canPlaceOn, "CanPlaceOn", () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
canPlaceOn.forEach(block -> list.add(new NBTString(block.name())));
return list;
});
handleCollection(canPlaceOn, "CanPlaceOn", () -> NBT.List(
NBTType.TAG_String,
canPlaceOn.stream()
.map(block -> new NBTString(block.name()))
.toList()
));
return this;
}
@ -173,11 +174,12 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract("_ -> this")
public @NotNull ItemMetaBuilder canDestroy(@NotNull Set<@NotNull Block> blocks) {
this.canDestroy = new HashSet<>(blocks);
handleCollection(canDestroy, "CanDestroy", () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
canDestroy.forEach(block -> list.add(new NBTString(block.name())));
return list;
});
handleCollection(canPlaceOn, "CanPlaceOn", () -> NBT.List(
NBTType.TAG_String,
canDestroy.stream()
.map(block -> new NBTString(block.name()))
.toList()
));
return this;
}
@ -203,13 +205,16 @@ public abstract class ItemMetaBuilder implements TagWritable {
protected abstract @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier();
protected synchronized void mutateNbt(Consumer<NBTCompound> consumer) {
protected synchronized void mutateNbt(Consumer<MutableNBTCompound> consumer) {
MutableNBTCompound copy = new MutableNBTCompound(nbt);
consumer.accept(copy);
if (built) {
built = false;
final var currentNbt = nbt;
NBT_UPDATER.compareAndSet(this, currentNbt, currentNbt.deepClone());
NBT_UPDATER.compareAndSet(this, currentNbt, copy.toCompound());
} else {
nbt = copy.toCompound();
}
consumer.accept(nbt);
}
protected synchronized NBTCompound nbt() {
@ -222,28 +227,16 @@ public abstract class ItemMetaBuilder implements TagWritable {
}
protected void handleCompound(@NotNull String key,
@NotNull Consumer<@NotNull NBTCompound> consumer) {
@NotNull Consumer<@NotNull MutableNBTCompound> consumer) {
mutateNbt(nbt -> {
NBTCompound compound = null;
boolean newNbt = false;
if (nbt.containsKey(key)) {
NBT dNbt = nbt.get(key);
if (dNbt instanceof NBTCompound) {
compound = (NBTCompound) dNbt;
}
MutableNBTCompound compoundToModify = nbt.get(key) instanceof NBTCompound compound ?
compound.toMutableCompound() : new MutableNBTCompound();
consumer.accept(compoundToModify);
if (compoundToModify.isEmpty()) {
nbt.remove(key);
} else {
compound = new NBTCompound();
newNbt = true;
}
if (compound != null) {
consumer.accept(compound);
if (newNbt && compound.getSize() > 0) {
this.nbt.set(key, compound);
} else if (!newNbt && compound.getSize() == 0) {
this.nbt.removeTag(key);
}
nbt.set(key, compoundToModify.toCompound());
}
});
}
@ -255,7 +248,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
if (value != null) {
compound.set(key, supplier.get());
} else {
compound.removeTag(key);
compound.remove(key);
}
});
}
@ -267,7 +260,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
if (!objects.isEmpty()) {
compound.set(key, supplier.get());
} else {
compound.removeTag(key);
compound.remove(key);
}
});
}
@ -279,7 +272,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
if (!objects.isEmpty()) {
compound.set(key, supplier.get());
} else {
compound.removeTag(key);
compound.remove(key);
}
});
}
@ -287,7 +280,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
@Contract(value = "_, _ -> new", pure = true)
public static @NotNull ItemMetaBuilder fromNBT(@NotNull ItemMetaBuilder src, @NotNull NBTCompound nbtCompound) {
ItemMetaBuilder dest = src.getSupplier().get();
dest.nbt = nbtCompound.deepClone();
dest.nbt = nbtCompound;
NBTUtils.loadDataIntoMeta(dest, dest.nbt);
return dest;
}

View File

@ -12,9 +12,11 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
@ -254,11 +256,10 @@ public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent
*/
@ApiStatus.Experimental
public @NotNull NBTCompound toItemNBT() {
final NBTCompound nbtCompound = new NBTCompound();
nbtCompound.setString("id", getMaterial().name());
nbtCompound.setByte("Count", (byte) getAmount());
nbtCompound.set("tag", getMeta().toNBT());
return nbtCompound;
return NBT.Compound(Map.of(
"id", NBT.String(getMaterial().name()),
"Count", NBT.Byte(getAmount()),
"tag", getMeta().toNBT()));
}
@Contract(value = "-> new", pure = true)

View File

@ -2,6 +2,8 @@ package net.minestom.server.item.firework;
import net.minestom.server.color.Color;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.collections.ImmutableIntArray;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.ArrayList;
@ -47,14 +49,14 @@ public class FireworkEffect {
List<Color> secondaryColor = new ArrayList<>();
if (compound.containsKey("Colors")) {
final int[] color = compound.getIntArray("Colors");
ImmutableIntArray color = compound.getIntArray("Colors");
for (int j : color) {
primaryColor.add(new Color(j));
}
}
if (compound.containsKey("FadeColors")) {
final int[] fadeColor = compound.getIntArray("FadeColors");
ImmutableIntArray fadeColor = compound.getIntArray("FadeColors");
for (int j : fadeColor) {
secondaryColor.add(new Color(j));
}
@ -137,15 +139,14 @@ public class FireworkEffect {
* @return The firework effect as a nbt compound.
*/
public NBTCompound asCompound() {
NBTCompound explosionCompound = new NBTCompound();
explosionCompound.setByte("Flicker", this.getFlicker());
explosionCompound.setByte("Trail", this.getTrail());
explosionCompound.setByte("Type", this.getType());
return NBT.Compound(explosionCompound -> {
explosionCompound.setByte("Flicker", this.getFlicker());
explosionCompound.setByte("Trail", this.getTrail());
explosionCompound.setByte("Type", this.getType());
explosionCompound.setIntArray("Colors", this.getColors());
explosionCompound.setIntArray("FadeColors", this.getFadeColors());
return explosionCompound;
explosionCompound.setIntArray("Colors", this.getColors());
explosionCompound.setIntArray("FadeColors", this.getFadeColors());
});
}
/**

View File

@ -5,9 +5,7 @@ import net.minestom.server.item.ItemMetaBuilder;
import net.minestom.server.item.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.*;
import java.util.ArrayList;
import java.util.List;
@ -58,11 +56,7 @@ public class BundleMeta extends ItemMeta implements ItemMetaBuilder.Provider<Bun
private void updateItems() {
mutateNbt(compound -> {
NBTList<NBTCompound> itemList = new NBTList<>(NBTTypes.TAG_Compound);
for (ItemStack item : items) {
itemList.add(item.toItemNBT());
}
compound.set("Items", itemList);
compound.set("Items", NBT.List(NBTType.TAG_Compound, items.size(), i -> items.get(i).toItemNBT()));
});
}

View File

@ -6,6 +6,7 @@ import net.minestom.server.item.ItemMeta;
import net.minestom.server.item.ItemMetaBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.function.Supplier;
@ -57,7 +58,7 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
if (lodestoneDimension != null) {
compound.setString("LodestoneDimension", lodestoneDimension);
} else {
compound.removeTag("LodestoneDimension");
compound.remove("LodestoneDimension");
}
});
@ -69,13 +70,13 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider<Co
mutateNbt(compound -> {
if (lodestonePosition != null) {
NBTCompound posCompound = new NBTCompound();
posCompound.setInt("X", lodestonePosition.blockX());
posCompound.setInt("Y", lodestonePosition.blockY());
posCompound.setInt("Z", lodestonePosition.blockZ());
compound.set("LodestonePos", posCompound);
compound.set("LodestonePos", NBT.Compound(posCompound -> {
posCompound.setInt("X", lodestonePosition.blockX());
posCompound.setInt("Y", lodestonePosition.blockY());
posCompound.setInt("Z", lodestonePosition.blockZ());
}));
} else {
compound.removeTag("LodestonePos");
compound.remove("LodestonePos");
}
});

View File

@ -6,9 +6,10 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.ArrayList;
import java.util.List;
@ -94,11 +95,9 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
this.projectile1 = projectile;
this.triple = false;
NBTList<NBTCompound> chargedProjectiles = new NBTList<>(NBTTypes.TAG_Compound);
if (!projectile.isAir()) {
chargedProjectiles.add(getItemCompound(projectile));
}
mutateNbt(compound -> compound.set("ChargedProjectiles", chargedProjectiles));
List<NBTCompound> chargedProjectiles =
projectile.isAir() ? List.of() : List.of(getItemCompound(projectile));
mutateNbt(compound -> compound.set("ChargedProjectiles", NBT.List(NBTType.TAG_Compound, chargedProjectiles)));
return this;
}
@ -120,11 +119,9 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
this.projectile3 = projectile3;
this.triple = true;
NBTList<NBTCompound> chargedProjectiles = new NBTList<>(NBTTypes.TAG_Compound);
chargedProjectiles.add(getItemCompound(projectile1));
chargedProjectiles.add(getItemCompound(projectile2));
chargedProjectiles.add(getItemCompound(projectile3));
mutateNbt(compound -> compound.set("ChargedProjectiles", chargedProjectiles));
List<NBTCompound> chargedProjectiles =
List.of(getItemCompound(projectile1), getItemCompound(projectile2), getItemCompound(projectile3));
mutateNbt(compound -> compound.set("ChargedProjectiles", NBT.List(NBTType.TAG_Compound, chargedProjectiles)));
return this;
}
@ -181,9 +178,10 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider<S
private @NotNull NBTCompound getItemCompound(@NotNull ItemStack itemStack) {
NBTCompound compound = itemStack.getMeta().toNBT();
compound.setByte("Count", (byte) itemStack.getAmount());
compound.setString("id", itemStack.getMaterial().name());
return compound;
return compound.modify(n -> {
n.setByte("Count", (byte) itemStack.getAmount());
n.setString("id", itemStack.getMaterial().name());
});
}
}
}

View File

@ -4,15 +4,17 @@ import net.minestom.server.item.ItemMeta;
import net.minestom.server.item.ItemMetaBuilder;
import net.minestom.server.item.firework.FireworkEffect;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class FireworkMeta extends ItemMeta implements ItemMetaBuilder.Provider<FireworkMeta.Builder> {
@ -42,11 +44,12 @@ public class FireworkMeta extends ItemMeta implements ItemMetaBuilder.Provider<F
public Builder effects(List<FireworkEffect> effects) {
this.effects = effects;
handleCompound("Fireworks", nbtCompound -> {
NBTList<NBTCompound> explosions = new NBTList<>(NBTTypes.TAG_Compound);
for (FireworkEffect effect : this.effects) {
explosions.add(effect.asCompound());
}
nbtCompound.set("Explosions", explosions);
nbtCompound.set("Explosions", NBT.List(
NBTType.TAG_Compound,
effects.stream()
.map(FireworkEffect::asCompound)
.toList()
));
});
return this;
}

View File

@ -32,7 +32,7 @@ public class LeatherArmorMeta extends ItemMeta implements ItemMetaBuilder.Provid
if (color != null) {
nbtCompound.setInt("color", color.asRGB());
} else {
nbtCompound.removeTag("color");
nbtCompound.remove("color");
}
});
return this;

View File

@ -6,12 +6,14 @@ import net.minestom.server.item.ItemMeta;
import net.minestom.server.item.ItemMetaBuilder;
import net.minestom.server.utils.clone.PublicCloneable;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
@ -92,17 +94,17 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
public Builder decorations(List<MapDecoration> value) {
this.decorations = new ArrayList<>(value);
NBTList<NBTCompound> decorationsList = new NBTList<>(NBTTypes.TAG_Compound);
for (MapDecoration decoration : decorations) {
NBTCompound decorationCompound = new NBTCompound();
decorationCompound.setString("id", decoration.getId());
decorationCompound.setByte("type", decoration.getType());
decorationCompound.setByte("x", decoration.getX());
decorationCompound.setByte("z", decoration.getZ());
decorationCompound.setDouble("rot", decoration.getRotation());
decorationsList.add(decorationCompound);
}
NBTList<NBTCompound> decorationsList = NBT.List(
NBTType.TAG_Compound,
decorations.stream()
.map(decoration -> NBT.Compound(Map.of(
"id", NBT.String(decoration.getId()),
"type", NBT.Byte(decoration.getType()),
"x", NBT.Byte(decoration.getX()),
"z", NBT.Byte(decoration.getZ()),
"rot", NBT.Double(decoration.getRotation()))))
.toList()
);
mutateNbt(compound -> compound.set("Decorations", decorationsList));
return this;
@ -111,14 +113,7 @@ public class MapMeta extends ItemMeta implements ItemMetaBuilder.Provider<MapMet
public Builder mapColor(Color value) {
this.mapColor = value;
mutateNbt(nbt -> {
NBTCompound displayCompound;
if (nbt.containsKey("display")) {
displayCompound = nbt.getCompound("display");
} else {
displayCompound = new NBTCompound();
nbt.set("display", displayCompound);
}
handleCompound("display", displayCompound -> {
displayCompound.setInt("MapColor", mapColor.asRGB());
});

View File

@ -6,10 +6,13 @@ import net.minestom.server.item.ItemMetaBuilder;
import net.minestom.server.utils.Utils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Supplier;
@ -50,15 +53,17 @@ public class PlayerHeadMeta extends ItemMeta implements ItemMetaBuilder.Provider
this.playerSkin = playerSkin;
handleCompound("SkullOwner", nbtCompound -> {
if (playerSkin == null) {
nbtCompound.removeTag("Properties");
nbtCompound.remove("Properties");
return;
}
NBTList<NBTCompound> textures = new NBTList<>(NBTTypes.TAG_Compound);
final String value = Objects.requireNonNullElse(this.playerSkin.textures(), "");
final String signature = Objects.requireNonNullElse(this.playerSkin.signature(), "");
textures.add(new NBTCompound().setString("Value", value).setString("Signature", signature));
nbtCompound.set("Properties", new NBTCompound().set("textures", textures));
NBTList<NBTCompound> textures = new NBTList<>(NBTType.TAG_Compound,
List.of(NBT.Compound(Map.of(
"Value", NBT.String(value),
"Signature", NBT.String(signature)))));
nbtCompound.set("Properties", NBT.Compound(Map.of("textures", textures)));
});
return this;
}
@ -74,7 +79,7 @@ public class PlayerHeadMeta extends ItemMeta implements ItemMetaBuilder.Provider
NBTCompound skullOwnerCompound = nbtCompound.getCompound("SkullOwner");
if (skullOwnerCompound.containsKey("Id")) {
skullOwner(Utils.intArrayToUuid(skullOwnerCompound.getIntArray("Id")));
skullOwner(Utils.intArrayToUuid(skullOwnerCompound.getIntArray("Id").copyArray()));
}
if (skullOwnerCompound.containsKey("Properties")) {

View File

@ -7,14 +7,16 @@ import net.minestom.server.potion.CustomPotionEffect;
import net.minestom.server.potion.PotionType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider<PotionMeta.Builder> {
@ -58,18 +60,19 @@ public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider<Pot
public Builder effects(@NotNull List<CustomPotionEffect> customPotionEffects) {
this.customPotionEffects = customPotionEffects;
NBTList<NBTCompound> potionList = new NBTList<>(NBTTypes.TAG_Compound);
for (CustomPotionEffect customPotionEffect : customPotionEffects) {
NBTCompound potionCompound = new NBTCompound();
potionCompound.setByte("Id", customPotionEffect.getId());
potionCompound.setByte("Amplifier", customPotionEffect.getAmplifier());
potionCompound.setInt("Duration", customPotionEffect.getDuration());
potionCompound.setByte("Ambient", (byte) (customPotionEffect.isAmbient() ? 1 : 0));
potionCompound.setByte("ShowParticles", (byte) (customPotionEffect.showParticles() ? 1 : 0));
potionCompound.setByte("ShowIcon", (byte) (customPotionEffect.showIcon() ? 1 : 0));
potionList.add(potionCompound);
}
NBTList<NBTCompound> potionList = NBT.List(
NBTType.TAG_Compound,
customPotionEffects.stream()
.map(customPotionEffect -> NBT.Compound(potionCompound -> {
potionCompound.setByte("Id", customPotionEffect.getId());
potionCompound.setByte("Amplifier", customPotionEffect.getAmplifier());
potionCompound.setInt("Duration", customPotionEffect.getDuration());
potionCompound.setByte("Ambient", (byte) (customPotionEffect.isAmbient() ? 1 : 0));
potionCompound.setByte("ShowParticles", (byte) (customPotionEffect.showParticles() ? 1 : 0));
potionCompound.setByte("ShowIcon", (byte) (customPotionEffect.showIcon() ? 1 : 0));
}))
.toList()
);
mutateNbt(compound -> compound.set("CustomPotionEffects", potionList));
return this;

View File

@ -6,16 +6,14 @@ import net.minestom.server.item.ItemMeta;
import net.minestom.server.item.ItemMetaBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTString;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provider<WritableBookMeta.Builder> {
@ -67,13 +65,12 @@ public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provid
public Builder pages(@NotNull List<@NotNull Component> pages) {
this.pages = new ArrayList<>(pages);
handleCollection(pages, "pages", () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
for (Component page : pages) {
list.add(new NBTString(LegacyComponentSerializer.legacySection().serialize(page)));
}
return list;
});
handleCollection(pages, "pages", () -> NBT.List(
NBTType.TAG_String,
pages.stream()
.map(page -> new NBTString(LegacyComponentSerializer.legacySection().serialize(page)))
.toList()
));
return this;
}

View File

@ -14,6 +14,7 @@ import org.jglrxavpok.hephaistos.nbt.*;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provider<WrittenBookMeta.Builder> {
@ -115,13 +116,12 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide
public Builder pages(@NotNull List<@NotNull Component> pages) {
this.pages = new ArrayList<>(pages);
handleCollection(pages, "pages", () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
for (Component page : pages) {
list.add(new NBTString(GsonComponentSerializer.gson().serialize(page)));
}
return list;
});
handleCollection(pages, "pages", () -> NBT.List(
NBTType.TAG_String,
pages.stream()
.map(page -> new NBTString(GsonComponentSerializer.gson().serialize(page)))
.toList()
));
return this;
}

View File

@ -6,6 +6,7 @@ import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.List;

View File

@ -9,6 +9,7 @@ import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.Writeable;
import net.minestom.server.utils.chunk.ChunkUtils;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.HashMap;
@ -18,7 +19,6 @@ import java.util.Objects;
public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data,
@NotNull Map<Integer, Block> blockEntities) implements Writeable {
public ChunkData {
heightmaps = heightmaps.deepClone();
data = data.clone();
blockEntities = Map.copyOf(blockEntities);
}
@ -56,15 +56,16 @@ public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data,
// Append handler tags
final BlockHandler handler = block.handler();
if (handler != null) {
resultNbt = new NBTCompound();
final NBTCompound blockNbt = Objects.requireNonNullElseGet(block.nbt(), NBTCompound::new);
for (Tag<?> tag : handler.getBlockEntityTags()) {
final var value = tag.read(blockNbt);
if (value != null) {
// Tag is present and valid
tag.writeUnsafe(resultNbt, value);
resultNbt = NBT.Compound(nbt -> {
final NBTCompound blockNbt = Objects.requireNonNullElseGet(block.nbt(), NBTCompound::new);
for (Tag<?> tag : handler.getBlockEntityTags()) {
final var value = tag.read(blockNbt);
if (value != null) {
// Tag is present and valid
tag.writeUnsafe(nbt, value);
}
}
}
});
} else {
// Complete nbt shall be sent if the block has no handler
// Necessary to support all vanilla blocks

View File

@ -3,7 +3,7 @@ package net.minestom.server.permission;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.SNBTParser;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.util.Set;

View File

@ -1,13 +1,16 @@
package net.minestom.server.tag;
import net.minestom.server.MinecraftServer;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTCompoundLike;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.nbt.SNBTParser;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import org.jglrxavpok.hephaistos.parser.SNBTParser;
import java.io.StringReader;
import java.util.Objects;
@ -31,16 +34,15 @@ public class Tag<T> {
* Writing will override all tags. Proceed with caution.
*/
@ApiStatus.Experimental
public static final Tag<String> SNBT = new Tag<>(null, NBTCompound::toSNBT, (original, snbt) -> {
public static final Tag<String> SNBT = new Tag<>(null, n -> n.toCompound().toSNBT(), (original, snbt) -> {
try {
final var updated = new SNBTParser(new StringReader(snbt)).parse();
if (!(updated instanceof NBTCompound updatedCompound))
throw new IllegalArgumentException("'" + snbt + "' is not a compound!");
original.clear();
updatedCompound.getKeys().forEach(s ->
original.set(s, Objects.requireNonNull(updatedCompound.get(s))));
updatedCompound.forEach(original::set);
} catch (NBTException e) {
e.printStackTrace();
MinecraftServer.getExceptionManager().handleException(e);
}
}, null);
@ -50,20 +52,20 @@ public class Tag<T> {
* Writing will override all tags. Proceed with caution.
*/
@ApiStatus.Experimental
public static final Tag<NBTCompound> NBT = new Tag<>(null, NBTCompound::deepClone, (original, updated) -> {
public static final Tag<NBTCompound> NBT = new Tag<>(null, NBTCompoundLike::toCompound, (original, updated) -> {
original.clear();
updated.getKeys().forEach(s -> original.set(s, Objects.requireNonNull(updated.get(s))));
updated.forEach(original::set);
}, null);
private final String key;
private final Function<NBTCompound, T> readFunction;
private final BiConsumer<NBTCompound, T> writeConsumer;
private final Function<NBTCompoundLike, T> readFunction;
private final BiConsumer<MutableNBTCompound, T> writeConsumer;
private final Supplier<T> defaultValue;
protected Tag(@Nullable String key,
@NotNull Function<NBTCompound, T> readFunction,
@Nullable BiConsumer<NBTCompound, T> writeConsumer,
@NotNull Function<NBTCompoundLike, T> readFunction,
@Nullable BiConsumer<MutableNBTCompound, T> writeConsumer,
@Nullable Supplier<T> defaultValue) {
this.key = key;
this.readFunction = readFunction;
@ -73,8 +75,8 @@ public class Tag<T> {
}
protected Tag(@Nullable String key,
@NotNull Function<NBTCompound, T> readFunction,
@Nullable BiConsumer<NBTCompound, T> writeConsumer) {
@NotNull Function<NBTCompoundLike, T> readFunction,
@Nullable BiConsumer<MutableNBTCompound, T> writeConsumer) {
this(key, readFunction, writeConsumer, null);
}
@ -126,7 +128,7 @@ public class Tag<T> {
});
}
public @Nullable T read(@NotNull NBTCompound nbtCompound) {
public @Nullable T read(@NotNull NBTCompoundLike nbtCompound) {
T result = readFunction.apply(nbtCompound);
if (result == null) {
final var supplier = defaultValue;
@ -135,15 +137,15 @@ public class Tag<T> {
return result;
}
public void write(@NotNull NBTCompound nbtCompound, @Nullable T value) {
public void write(@NotNull MutableNBTCompound nbtCompound, @Nullable T value) {
if (key == null || value != null) {
this.writeConsumer.accept(nbtCompound, value);
} else {
nbtCompound.removeTag(key);
nbtCompound.remove(key);
}
}
public void writeUnsafe(@NotNull NBTCompound nbtCompound, @Nullable Object value) {
public void writeUnsafe(@NotNull MutableNBTCompound nbtCompound, @Nullable Object value) {
write(nbtCompound, (T) value);
}
@ -185,7 +187,7 @@ public class Tag<T> {
public static @NotNull Tag<byte[]> ByteArray(@NotNull String key) {
return new Tag<>(key,
nbtCompound -> nbtCompound.getByteArray(key),
nbtCompound -> nbtCompound.getByteArray(key).copyArray(),
(nbtCompound, value) -> nbtCompound.setByteArray(key, value));
}
@ -199,24 +201,20 @@ public class Tag<T> {
return new Tag<>(key,
nbt -> {
final var currentNBT = nbt.get(key);
// Avoid a NPE when cloning a null variable.
if (currentNBT == null) {
return null;
}
return (T) currentNBT.deepClone();
return (T) currentNBT;
},
((nbt, value) -> nbt.set(key, value.deepClone())));
((nbt, value) -> nbt.set(key, value)));
}
public static @NotNull Tag<int[]> IntArray(@NotNull String key) {
return new Tag<>(key,
nbtCompound -> nbtCompound.getIntArray(key),
nbtCompound -> nbtCompound.getIntArray(key).copyArray(),
(nbtCompound, value) -> nbtCompound.setIntArray(key, value));
}
public static @NotNull Tag<long[]> LongArray(@NotNull String key) {
return new Tag<>(key,
nbtCompound -> nbtCompound.getLongArray(key),
nbtCompound -> nbtCompound.getLongArray(key).copyArray(),
(nbtCompound, value) -> nbtCompound.setLongArray(key, value));
}
@ -231,19 +229,15 @@ public class Tag<T> {
public static <T> @NotNull Tag<T> Structure(@NotNull String key, @NotNull TagSerializer<T> serializer) {
return new Tag<>(key,
nbtCompound -> {
final var compound = nbtCompound.getCompound(key);
if (compound == null) {
return null;
}
final NBTCompound compound = nbtCompound.getCompound(key);
if (compound == null) return null;
return serializer.read(TagReadable.fromCompound(compound));
},
(nbtCompound, value) -> {
var compound = nbtCompound.getCompound(key);
if (compound == null) {
compound = new NBTCompound();
nbtCompound.set(key, compound);
}
serializer.write(TagWritable.fromCompound(compound), value);
MutableNBTCompound mutableCopy = nbtCompound.get(key) instanceof NBTCompound c ?
c.toMutableCompound() : new MutableNBTCompound();
serializer.write(TagWritable.fromCompound(mutableCopy), value);
nbtCompound.set(key, mutableCopy.toCompound());
});
}

View File

@ -3,6 +3,8 @@ package net.minestom.server.tag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTCompoundGetters;
import org.jglrxavpok.hephaistos.nbt.NBTCompoundLike;
/**
* Represents an element which can read {@link Tag tags}.
@ -34,7 +36,7 @@ public interface TagReadable {
* @param compound the compound to convert
* @return a {@link TagReadable} capable of reading {@code compound}
*/
static @NotNull TagReadable fromCompound(@NotNull NBTCompound compound) {
static @NotNull TagReadable fromCompound(@NotNull NBTCompoundLike compound) {
return new TagReadable() {
@Override
public <T> @Nullable T getTag(@NotNull Tag<T> tag) {

View File

@ -3,6 +3,7 @@ package net.minestom.server.tag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
/**
* Represents an element which can write {@link Tag tags}.
@ -28,7 +29,7 @@ public interface TagWritable {
* @param compound the compound to convert
* @return a {@link TagWritable} capable of writing {@code compound}
*/
static @NotNull TagWritable fromCompound(@NotNull NBTCompound compound) {
static @NotNull TagWritable fromCompound(@NotNull MutableNBTCompound compound) {
return new TagWritable() {
@Override
public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {

View File

@ -20,10 +20,12 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.*;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
// for lack of a better name
public final class NBTUtils {
@ -79,34 +81,35 @@ public final class NBTUtils {
}
}
public static void saveAllItems(@NotNull NBTList<NBTCompound> list, @NotNull Inventory inventory) {
public static void saveAllItems(@NotNull List<NBTCompound> list, @NotNull Inventory inventory) {
for (int i = 0; i < inventory.getSize(); i++) {
final ItemStack stack = inventory.getItemStack(i);
NBTCompound nbt = new NBTCompound();
NBTCompound tag = stack.getMeta().toNBT();
nbt.set("tag", tag);
nbt.setByte("Slot", (byte) i);
nbt.setByte("Count", (byte) stack.getAmount());
nbt.setString("id", stack.getMaterial().name());
list.add(nbt);
final int slotIndex = i;
list.add(NBT.Compound(nbt -> {
nbt.set("tag", tag);
nbt.setByte("Slot", (byte) slotIndex);
nbt.setByte("Count", (byte) stack.getAmount());
nbt.setString("id", stack.getMaterial().name());
}));
}
}
public static void writeEnchant(@NotNull NBTCompound nbt, @NotNull String listName,
public static void writeEnchant(@NotNull MutableNBTCompound nbt, @NotNull String listName,
@NotNull Map<Enchantment, Short> enchantmentMap) {
NBTList<NBTCompound> enchantList = new NBTList<>(NBTTypes.TAG_Compound);
for (var entry : enchantmentMap.entrySet()) {
final Enchantment enchantment = entry.getKey();
final short level = entry.getValue();
enchantList.add(new NBTCompound()
.setShort("lvl", level)
.setString("id", enchantment.name())
);
}
nbt.set(listName, enchantList);
nbt.set(listName, NBT.List(
NBTType.TAG_Compound,
enchantmentMap.entrySet().stream()
.map(entry ->
NBT.Compound(n -> {
n.setShort("lvl", entry.getValue());
n.setString("id", entry.getKey().name());
})
)
.toList()
));
}
public static @NotNull ItemStack readItemStack(@NotNull BinaryReader reader) {
@ -134,7 +137,7 @@ public final class NBTUtils {
if (nbt.containsKey("display")) {
final NBTCompound display = nbt.getCompound("display");
if (display.containsKey("Name")) {
final String rawName = StringUtils.unescapeJavaString(display.getString("Name"));
final String rawName = display.getString("Name");
final Component displayName = GsonComponentSerializer.gson().deserialize(rawName);
metaBuilder.displayName(displayName);
}
@ -142,7 +145,7 @@ public final class NBTUtils {
NBTList<NBTString> loreList = display.getList("Lore");
List<Component> lore = new ArrayList<>();
for (NBTString s : loreList) {
final String rawLore = StringUtils.unescapeJavaString(s.getValue());
final String rawLore = s.getValue();
lore.add(GsonComponentSerializer.gson().deserialize(rawLore));
}
metaBuilder.lore(lore);
@ -161,7 +164,7 @@ public final class NBTUtils {
for (NBTCompound attributeNBT : nbtAttributes) {
final UUID uuid;
{
final int[] uuidArray = attributeNBT.getIntArray("UUID");
final int[] uuidArray = attributeNBT.getIntArray("UUID").copyArray();
uuid = Utils.intArrayToUuid(uuidArray);
}

View File

@ -15,7 +15,7 @@ public final class SerializerUtils {
public static Point longToBlockPosition(long value) {
final int x = (int) (value >> 38);
final int y = (int) (value & 0xFFF);
final int y = (int) (value << 52 >> 52);
final int z = (int) (value << 26 >> 38);
return new Vec(x, y, z);
}

View File

@ -10,6 +10,7 @@ import net.minestom.server.utils.SerializerUtils;
import net.minestom.server.utils.Utils;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.CompressedProcesser;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.nbt.NBTReader;
@ -32,7 +33,7 @@ import java.util.function.Supplier;
*/
public class BinaryReader extends InputStream {
private final ByteBuffer buffer;
private NBTReader nbtReader;
private NBTReader nbtReader = null;
public BinaryReader(@NotNull ByteBuffer buffer) {
this.buffer = buffer;
@ -257,7 +258,7 @@ public class BinaryReader extends InputStream {
public NBT readTag() {
NBTReader reader = this.nbtReader;
if (reader == null) {
reader = new NBTReader(this, false);
reader = new NBTReader(this, CompressedProcesser.NONE);
this.nbtReader = reader;
}
try {

View File

@ -9,6 +9,7 @@ import net.minestom.server.utils.SerializerUtils;
import net.minestom.server.utils.Utils;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.CompressedProcesser;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTWriter;
@ -303,7 +304,7 @@ public class BinaryWriter extends OutputStream {
public void writeNBT(@NotNull String name, @NotNull NBT tag) {
if (nbtWriter == null) {
this.nbtWriter = new NBTWriter(this, false);
this.nbtWriter = new NBTWriter(this, CompressedProcesser.NONE);
}
try {
nbtWriter.writeNamed(name, tag);

View File

@ -3,8 +3,10 @@ package net.minestom.server.world;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
@ -26,8 +28,9 @@ public class DimensionType {
.ceilingEnabled(false)
.fixedTime(null)
.ambientLight(0.0f)
.height(256)
.logicalHeight(256)
.height(384)
.minY(-64)
.logicalHeight(384)
.infiniburn(NamespaceID.from("minecraft:infiniburn_overworld"))
.build();
@ -107,35 +110,33 @@ public class DimensionType {
@NotNull
public NBTCompound toIndexedNBT() {
NBTCompound nbt = new NBTCompound();
NBTCompound element = toNBT();
nbt.setString("name", name.toString());
nbt.setInt("id", id);
nbt.set("element", element);
return nbt;
return NBT.Compound(Map.of(
"name", NBT.String(name.toString()),
"id", NBT.Int(id),
"element", toNBT()));
}
@NotNull
public NBTCompound toNBT() {
NBTCompound nbt = new NBTCompound()
.setFloat("ambient_light", ambientLight)
.setString("infiniburn", infiniburn.toString())
.setByte("natural", (byte) (natural ? 0x01 : 0x00))
.setByte("has_ceiling", (byte) (ceilingEnabled ? 0x01 : 0x00))
.setByte("has_skylight", (byte) (skylightEnabled ? 0x01 : 0x00))
.setByte("ultrawarm", (byte) (ultrawarm ? 0x01 : 0x00))
.setByte("has_raids", (byte) (raidCapable ? 0x01 : 0x00))
.setByte("respawn_anchor_works", (byte) (respawnAnchorSafe ? 0x01 : 0x00))
.setByte("bed_works", (byte) (bedSafe ? 0x01 : 0x00))
.setString("effects", effects)
.setByte("piglin_safe", (byte) (piglinSafe ? 0x01 : 0x00))
.setInt("min_y", minY)
.setInt("height", height)
.setInt("logical_height", logicalHeight)
.setInt("coordinate_scale", coordinateScale)
.setString("name", name.toString());
if (fixedTime != null) nbt.setLong("fixed_time", fixedTime);
return nbt;
return NBT.Compound(nbt -> {
nbt.setFloat("ambient_light", ambientLight);
nbt.setString("infiniburn", infiniburn.toString());
nbt.setByte("natural", (byte) (natural ? 0x01 : 0x00));
nbt.setByte("has_ceiling", (byte) (ceilingEnabled ? 0x01 : 0x00));
nbt.setByte("has_skylight", (byte) (skylightEnabled ? 0x01 : 0x00));
nbt.setByte("ultrawarm", (byte) (ultrawarm ? 0x01 : 0x00));
nbt.setByte("has_raids", (byte) (raidCapable ? 0x01 : 0x00));
nbt.setByte("respawn_anchor_works", (byte) (respawnAnchorSafe ? 0x01 : 0x00));
nbt.setByte("bed_works", (byte) (bedSafe ? 0x01 : 0x00));
nbt.setString("effects", effects);
nbt.setByte("piglin_safe", (byte) (piglinSafe ? 0x01 : 0x00));
nbt.setInt("min_y", minY);
nbt.setInt("height", height);
nbt.setInt("logical_height", logicalHeight);
nbt.setInt("coordinate_scale", coordinateScale);
nbt.setString("name", name.toString());
if (fixedTime != null) nbt.setLong("fixed_time", fixedTime);
});
}
@Override

View File

@ -3,13 +3,15 @@ package net.minestom.server.world;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
/**
* Allows servers to register custom dimensions. Also used during player login to send the list of all existing dimensions.
@ -88,13 +90,14 @@ public final class DimensionTypeManager {
* @return an nbt compound containing the registered dimensions
*/
public @NotNull NBTCompound toNBT() {
NBTCompound dimensions = new NBTCompound();
dimensions.setString("type", "minecraft:dimension_type");
NBTList<NBTCompound> dimensionList = new NBTList<>(NBTTypes.TAG_Compound);
for (DimensionType dimensionType : dimensionTypes) {
dimensionList.add(dimensionType.toIndexedNBT());
}
dimensions.set("value", dimensionList);
return dimensions;
return NBT.Compound(dimensions -> {
dimensions.setString("type", "minecraft:dimension_type");
dimensions.set("value", NBT.List(
NBTType.TAG_Compound,
dimensionTypes.stream()
.map(DimensionType::toIndexedNBT)
.toList()
));
});
}
}

View File

@ -4,6 +4,7 @@ import net.minestom.server.coordinate.Point;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Locale;
@ -61,22 +62,22 @@ public final class Biome {
Check.notNull(name, "The biome namespace cannot be null");
Check.notNull(effects, "The biome effects cannot be null");
NBTCompound nbt = new NBTCompound();
nbt.setString("name", name.toString());
nbt.setInt("id", id());
return NBT.Compound(nbt -> {
nbt.setString("name", name.toString());
nbt.setInt("id", id());
NBTCompound element = new NBTCompound();
element.setFloat("depth", depth);
element.setFloat("temperature", temperature);
element.setFloat("scale", scale);
element.setFloat("downfall", downfall);
element.setString("category", category.name().toLowerCase(Locale.ROOT));
element.setString("precipitation", precipitation.name().toLowerCase(Locale.ROOT));
if (temperatureModifier != TemperatureModifier.NONE)
element.setString("temperature_modifier", temperatureModifier.name().toLowerCase(Locale.ROOT));
element.set("effects", effects.toNbt());
nbt.set("element", element);
return nbt;
nbt.set("element", NBT.Compound(element -> {
element.setFloat("depth", depth);
element.setFloat("temperature", temperature);
element.setFloat("scale", scale);
element.setFloat("downfall", downfall);
element.setString("category", category.name().toLowerCase(Locale.ROOT));
element.setString("precipitation", precipitation.name().toLowerCase(Locale.ROOT));
if (temperatureModifier != TemperatureModifier.NONE)
element.setString("temperature_modifier", temperatureModifier.name().toLowerCase(Locale.ROOT));
element.set("effects", effects.toNbt());
}));
});
}
public int id() {

View File

@ -2,9 +2,11 @@ package net.minestom.server.world.biomes;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Locale;
import java.util.Map;
public record BiomeEffects(int fogColor, int skyColor, int waterColor, int waterFogColor, int foliageColor,
int grassColor,
@ -17,26 +19,28 @@ public record BiomeEffects(int fogColor, int skyColor, int waterColor, int water
}
public NBTCompound toNbt() {
NBTCompound nbt = new NBTCompound();
nbt.setInt("fog_color", fogColor);
if (foliageColor != -1) nbt.setInt("foliage_color", foliageColor);
if (grassColor != -1) nbt.setInt("grass_color", grassColor);
nbt.setInt("sky_color", skyColor);
nbt.setInt("water_color", waterColor);
nbt.setInt("water_fog_color", waterFogColor);
if (grassColorModifier != null)
nbt.setString("grass_color_modifier", grassColorModifier.name().toLowerCase(Locale.ROOT));
if (biomeParticle != null)
nbt.set("particle", biomeParticle.toNbt());
if (ambientSound != null)
nbt.setString("ambient_sound", ambientSound.toString());
if (moodSound != null)
nbt.set("mood_sound", moodSound.toNbt());
if (additionsSound != null)
nbt.set("additions_sound", additionsSound.toNbt());
if (music != null)
nbt.set("music", music.toNbt());
return nbt;
return NBT.Compound(nbt -> {
nbt.setInt("fog_color", fogColor);
if (foliageColor != -1)
nbt.setInt("foliage_color", foliageColor);
if (grassColor != -1)
nbt.setInt("grass_color", grassColor);
nbt.setInt("sky_color", skyColor);
nbt.setInt("water_color", waterColor);
nbt.setInt("water_fog_color", waterFogColor);
if (grassColorModifier != null)
nbt.setString("grass_color_modifier", grassColorModifier.name().toLowerCase(Locale.ROOT));
if (biomeParticle != null)
nbt.set("particle", biomeParticle.toNbt());
if (ambientSound != null)
nbt.setString("ambient_sound", ambientSound.toString());
if (moodSound != null)
nbt.set("mood_sound", moodSound.toNbt());
if (additionsSound != null)
nbt.set("additions_sound", additionsSound.toNbt());
if (music != null)
nbt.set("music", music.toNbt());
});
}
public enum GrassColorModifier {
@ -45,32 +49,29 @@ public record BiomeEffects(int fogColor, int skyColor, int waterColor, int water
public record MoodSound(NamespaceID sound, int tickDelay, int blockSearchExtent, double offset) {
public @NotNull NBTCompound toNbt() {
NBTCompound nbt = new NBTCompound();
nbt.setString("sound", sound.toString());
nbt.setInt("tick_delay", tickDelay);
nbt.setInt("block_search_extent", blockSearchExtent);
nbt.setDouble("offset", offset);
return nbt;
return NBT.Compound(Map.of(
"sound", NBT.String(sound.toString()),
"tick_delay", NBT.Int(tickDelay),
"block_search_extent", NBT.Int(blockSearchExtent),
"offset", NBT.Double(offset)));
}
}
public record AdditionsSound(NamespaceID sound, double tickChance) {
public @NotNull NBTCompound toNbt() {
NBTCompound nbt = new NBTCompound();
nbt.setString("sound", sound.toString());
nbt.setDouble("tick_chance", tickChance);
return nbt;
return NBT.Compound(Map.of(
"sound", NBT.String(sound.toString()),
"tick_chance", NBT.Double(tickChance)));
}
}
public record Music(NamespaceID sound, int minDelay, int maxDelay, boolean replaceCurrentMusic) {
public @NotNull NBTCompound toNbt() {
NBTCompound nbt = new NBTCompound();
nbt.setString("sound", sound.toString());
nbt.setInt("min_delay", minDelay);
nbt.setInt("max_delay", maxDelay);
nbt.setByte("replace_current_music", replaceCurrentMusic ? (byte) 1 : (byte) 0);
return nbt;
return NBT.Compound(Map.of(
"sound", NBT.String(sound.toString()),
"min_delay", NBT.Int(minDelay),
"max_delay", NBT.Int(maxDelay),
"replace_current_music", NBT.Boolean(replaceCurrentMusic)));
}
}

View File

@ -3,12 +3,14 @@ package net.minestom.server.world.biomes;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minestom.server.utils.NamespaceID;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
/**
* Allows servers to register custom dimensions. Also used during player joining to send the list of all existing dimensions.
@ -71,13 +73,8 @@ public final class BiomeManager {
}
public synchronized NBTCompound toNBT() {
NBTCompound biomes = new NBTCompound();
biomes.setString("type", "minecraft:worldgen/biome");
NBTList<NBTCompound> biomesList = new NBTList<>(NBTTypes.TAG_Compound);
for (Biome biome : this.biomes.values()) {
biomesList.add(biome.toNbt());
}
biomes.set("value", biomesList);
return biomes;
return NBT.Compound(Map.of(
"type", NBT.String("minecraft:worldgen/biome"),
"value", NBT.List(NBTType.TAG_Compound, biomes.values().stream().map(Biome::toNbt).toList())));
}
}

View File

@ -3,16 +3,16 @@ package net.minestom.server.world.biomes;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.NamespaceID;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.Map;
public record BiomeParticle(float probability, Option option) {
public NBTCompound toNbt() {
NBTCompound nbt = new NBTCompound();
nbt.setFloat("probability", probability);
nbt.set("options", option.toNbt());
return nbt;
return NBT.Compound(Map.of(
"probability", NBT.Float(probability),
"options", option.toNbt()));
}
public interface Option {
@ -25,16 +25,16 @@ public record BiomeParticle(float probability, Option option) {
@Override
public NBTCompound toNbt() {
NBTCompound nbtCompound = new NBTCompound();
nbtCompound.setString("type", type);
nbtCompound.setString("Name", block.name());
Map<String, String> propertiesMap = block.properties();
if (propertiesMap.size() != 0) {
NBTCompound properties = new NBTCompound();
propertiesMap.forEach(properties::setString);
nbtCompound.set("Properties", properties);
}
return nbtCompound;
return NBT.Compound(nbtCompound -> {
nbtCompound.setString("type", type);
nbtCompound.setString("Name", block.name());
Map<String, String> propertiesMap = block.properties();
if (propertiesMap.size() != 0) {
nbtCompound.set("Properties", NBT.Compound(p -> {
propertiesMap.forEach(p::setString);
}));
}
});
}
}
@ -43,13 +43,12 @@ public record BiomeParticle(float probability, Option option) {
@Override
public NBTCompound toNbt() {
NBTCompound nbtCompound = new NBTCompound();
nbtCompound.setString("type", type);
nbtCompound.setFloat("r", red);
nbtCompound.setFloat("g", green);
nbtCompound.setFloat("b", blue);
nbtCompound.setFloat("scale", scale);
return nbtCompound;
return NBT.Compound(Map.of(
"type", NBT.String(type),
"r", NBT.Float(red),
"g", NBT.Float(green),
"b", NBT.Float(blue),
"scale", NBT.Float(scale)));
}
}
@ -60,17 +59,16 @@ public record BiomeParticle(float probability, Option option) {
public NBTCompound toNbt() {
//todo test count might be wrong type
NBTCompound nbtCompound = item.getMeta().toNBT();
nbtCompound.setString("type", type);
return nbtCompound;
return nbtCompound.modify(n -> {
n.setString("type", type);
});
}
}
public record NormalOption(NamespaceID type) implements Option {
@Override
public NBTCompound toNbt() {
NBTCompound nbtCompound = new NBTCompound();
nbtCompound.setString("type", type.toString());
return nbtCompound;
return NBT.Compound(Map.of("type", NBT.String(type.toString())));
}
}
}

View File

@ -10,13 +10,15 @@ import net.minestom.server.tag.TagWritable;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTList;
import org.jglrxavpok.hephaistos.nbt.NBTTypes;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class CampfireHandler implements BlockHandler {
@ -44,15 +46,16 @@ public class CampfireHandler implements BlockHandler {
writer.removeTag(internal);
return;
}
NBTList<NBTCompound> items = new NBTList<>(NBTTypes.TAG_Compound);
for (var item : value) {
NBTCompound compound = new NBTCompound()
.setByte("Count", (byte) item.getAmount())
.setByte("Slot", (byte) 1)
.setString("id", item.getMaterial().name());
items.add(compound);
}
writer.setTag(internal, items);
writer.setTag(internal, NBT.List(
NBTType.TAG_Compound,
value.stream()
.map(item -> NBT.Compound(nbt -> {
nbt.setByte("Count", (byte) item.getAmount());
nbt.setByte("Slot", (byte) 1);
nbt.setString("id", item.getMaterial().name());
}))
.toList()
));
}
});

View File

@ -3,6 +3,7 @@ package permissions;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.permission.Permission;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@ -36,9 +37,11 @@ public class TestPermissions {
};
permission1 = new Permission("perm.name",
new NBTCompound()
.setString("name", "Minestom")
.setInt("amount", 5));
NBT.Compound(nbt -> {
nbt.setString("name", "Minestom");
nbt.setInt("amount", 5);
})
);
permission2 = new Permission("perm.name2");
}

View File

@ -0,0 +1,95 @@
package regressions;
import net.minestom.server.item.ItemMeta;
import net.minestom.server.item.ItemMetaBuilder;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTShort;
import org.jglrxavpok.hephaistos.nbt.NBTString;
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
import org.junit.jupiter.api.Test;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static org.junit.jupiter.api.Assertions.*;
public class ItemMetaBuilderRegressions {
private static class BasicMetaBuilder extends ItemMetaBuilder {
@Override
public @NotNull ItemMeta build() {
return new ItemMeta(this) {};
}
@Override
public void read(@NotNull NBTCompound nbtCompound) {
// don't care
}
@Override
protected @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier() {
// don't care
return () -> this;
}
@Override
public void handleCompound(@NotNull String key, @NotNull Consumer<@NotNull MutableNBTCompound> consumer) {
super.handleCompound(key, consumer);
}
}
@Test
public void handleCompoundShouldUsePreviousValue() {
BasicMetaBuilder builder = new BasicMetaBuilder();
builder.handleCompound("test", nbt -> {
nbt.setString("my_key", "AAA");
});
NBTCompound nbt = builder.build().toNBT().getCompound("test");
assertTrue(nbt.contains("my_key"));
assertEquals(1, nbt.getSize());
assertTrue(nbt.get("my_key") instanceof NBTString);
assertEquals("AAA", nbt.getString("my_key"));
builder.handleCompound("test", n -> {
n.setString("my_other_key", "BBB");
});
nbt = builder.build().toNBT().getCompound("test");
assertTrue(nbt.contains("my_key"));
assertTrue(nbt.contains("my_other_key"));
assertEquals(2, nbt.getSize());
assertTrue(nbt.get("my_key") instanceof NBTString);
assertTrue(nbt.get("my_other_key") instanceof NBTString);
assertEquals("AAA", nbt.getString("my_key"));
assertEquals("BBB", nbt.getString("my_other_key"));
}
@Test
public void clearingShouldRemoveData() {
BasicMetaBuilder builder = new BasicMetaBuilder();
builder.handleCompound("test", nbt -> {
nbt.setString("my_key", "AAA");
});
NBTCompound nbt = builder.build().toNBT().getCompound("test");
assertTrue(nbt.contains("my_key"));
assertEquals(1, nbt.getSize());
assertTrue(nbt.get("my_key") instanceof NBTString);
assertEquals("AAA", nbt.getString("my_key"));
builder.handleCompound("test", n -> {
n.clear();
});
NBTCompound rootNBT = builder.build().toNBT();
assertFalse(rootNBT.contains("test"));
assertEquals(0, rootNBT.getSize());
}
}