mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-10 01:11:25 +01:00
feat: initial conversion to adventure nbt. no tests, no anvil
This commit is contained in:
parent
19bb74e942
commit
e61dc8188f
@ -72,10 +72,7 @@ dependencies {
|
||||
api(libs.jetbrainsAnnotations)
|
||||
api(libs.bundles.adventure)
|
||||
api(libs.hydrazine)
|
||||
api(libs.bundles.kotlin)
|
||||
api(libs.bundles.hephaistos)
|
||||
implementation(libs.minestomData)
|
||||
implementation(libs.dependencyGetter)
|
||||
|
||||
// Performance/data structures
|
||||
implementation(libs.caffeine)
|
||||
|
@ -1,5 +1,9 @@
|
||||
package net.minestom.demo.block;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.minestom.server.instance.block.BlockHandler;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
@ -10,10 +14,6 @@ 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.NBTType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -22,16 +22,17 @@ import java.util.List;
|
||||
public class CampfireHandler implements BlockHandler {
|
||||
|
||||
public static final Tag<List<ItemStack>> ITEMS = Tag.View(new TagSerializer<>() {
|
||||
private final Tag<NBT> internal = Tag.NBT("Items");
|
||||
private final Tag<BinaryTag> internal = Tag.NBT("Items");
|
||||
|
||||
@Override
|
||||
public @Nullable List<ItemStack> read(@NotNull TagReadable reader) {
|
||||
NBTList<NBTCompound> item = (NBTList<NBTCompound>) reader.getTag(internal);
|
||||
ListBinaryTag item = (ListBinaryTag) reader.getTag(internal);
|
||||
if (item == null)
|
||||
return null;
|
||||
List<ItemStack> result = new ArrayList<>();
|
||||
item.forEach(nbtCompound -> {
|
||||
int amount = nbtCompound.getAsByte("Count");
|
||||
item.forEach(childTag -> {
|
||||
CompoundBinaryTag nbtCompound = (CompoundBinaryTag) childTag;
|
||||
int amount = nbtCompound.getByte("Count");
|
||||
String id = nbtCompound.getString("id");
|
||||
Material material = Material.fromNamespaceId(id);
|
||||
result.add(ItemStack.of(material, amount));
|
||||
@ -45,14 +46,14 @@ public class CampfireHandler implements BlockHandler {
|
||||
writer.removeTag(internal);
|
||||
return;
|
||||
}
|
||||
writer.setTag(internal, NBT.List(
|
||||
NBTType.TAG_Compound,
|
||||
writer.setTag(internal, ListBinaryTag.listBinaryTag(
|
||||
BinaryTagTypes.COMPOUND,
|
||||
value.stream()
|
||||
.map(item -> NBT.Compound(nbt -> {
|
||||
nbt.setByte("Count", (byte) item.amount());
|
||||
nbt.setByte("Slot", (byte) 1);
|
||||
nbt.setString("id", item.material().name());
|
||||
}))
|
||||
.map(item -> (BinaryTag) CompoundBinaryTag.builder()
|
||||
.putByte("Count", (byte) item.amount())
|
||||
.putByte("Slot", (byte) 1)
|
||||
.putString("id", item.material().name())
|
||||
.build())
|
||||
.toList()
|
||||
));
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ metadata.format.version = "1.1"
|
||||
|
||||
# Important dependencies
|
||||
data = "1.20.4-rv4"
|
||||
adventure = "4.15.0"
|
||||
adventure = "4.16.0"
|
||||
kotlin = "1.7.22"
|
||||
dependencyGetter = "v1.0.1"
|
||||
hydrazine = "1.7.2"
|
||||
@ -41,22 +41,16 @@ nexuspublish = "1.3.0"
|
||||
# Important Dependencies
|
||||
# Adventure
|
||||
adventure-api = { group = "net.kyori", name = "adventure-api", version.ref = "adventure" }
|
||||
adventure-nbt = { group = "net.kyori", name = "adventure-nbt", version.ref = "adventure" }
|
||||
adventure-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" }
|
||||
adventure-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" }
|
||||
adventure-serializer-plain = { group = "net.kyori", name = "adventure-text-serializer-plain", version.ref = "adventure" }
|
||||
adventure-text-logger-slf4j = { group = "net.kyori", name = "adventure-text-logger-slf4j", version.ref = "adventure" }
|
||||
|
||||
# Kotlin
|
||||
kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }
|
||||
kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" }
|
||||
|
||||
# Miscellaneous
|
||||
hydrazine = { group = "com.github.MadMartian", name = "hydrazine-path-finding", version.ref = "hydrazine" }
|
||||
minestomData = { group = "net.minestom", name = "data", version.ref = "data" }
|
||||
dependencyGetter = { group = "com.github.Minestom", name = "DependencyGetter", version.ref = "dependencyGetter" }
|
||||
jetbrainsAnnotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrainsAnnotations" }
|
||||
hephaistos-common = { group = "io.github.jglrxavpok.hephaistos", name = "common", version.ref = "hephaistos" }
|
||||
hephaistos-gson = { group = "io.github.jglrxavpok.hephaistos", name = "gson", version.ref = "hephaistos" }
|
||||
slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j"}
|
||||
|
||||
# Performance / Data Structures
|
||||
@ -86,11 +80,9 @@ logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.
|
||||
|
||||
[bundles]
|
||||
|
||||
kotlin = ["kotlin-stdlib-jdk8", "kotlin-reflect"]
|
||||
flare = ["flare", "flare-fastutil"]
|
||||
adventure = ["adventure-api", "adventure-serializer-gson", "adventure-serializer-legacy", "adventure-serializer-plain", "adventure-text-logger-slf4j"]
|
||||
adventure = ["adventure-api", "adventure-nbt", "adventure-serializer-gson", "adventure-serializer-legacy", "adventure-serializer-plain", "adventure-text-logger-slf4j"]
|
||||
junit = ["junit-api", "junit-engine", "junit-params", "junit-suite-api", "junit-suite-engine"]
|
||||
hephaistos = ["hephaistos-common", "hephaistos-gson"]
|
||||
logback = ["logback-core", "logback-classic"]
|
||||
|
||||
[plugins]
|
||||
|
@ -1,21 +1,18 @@
|
||||
package net.minestom.server.adventure;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
import net.kyori.adventure.util.Codec;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTException;
|
||||
import org.jglrxavpok.hephaistos.parser.SNBTParser;
|
||||
|
||||
/**
|
||||
* Adventure related constants, etc.
|
||||
*/
|
||||
@ -23,8 +20,8 @@ public final class MinestomAdventure {
|
||||
/**
|
||||
* A codec to convert between strings and NBT.
|
||||
*/
|
||||
public static final Codec<NBT, String, NBTException, RuntimeException> NBT_CODEC
|
||||
= Codec.codec(encoded -> new SNBTParser(new StringReader(encoded)).parse(), NBT::toSNBT);
|
||||
public static final Codec<CompoundBinaryTag, String, IOException, IOException> NBT_CODEC
|
||||
= Codec.codec(TagStringIO.get()::asCompound, TagStringIO.get()::asString);
|
||||
|
||||
/**
|
||||
* If components should be automatically translated in outgoing packets.
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.adventure.provider;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
@ -9,14 +10,10 @@ import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import net.kyori.adventure.util.Codec;
|
||||
import net.minestom.server.adventure.MinestomAdventure;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
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();
|
||||
@ -30,76 +27,46 @@ final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer
|
||||
@Override
|
||||
public HoverEvent.@NotNull ShowItem deserializeShowItem(@NotNull Component input) throws IOException {
|
||||
final String raw = PlainTextComponentSerializer.plainText().serialize(input);
|
||||
try {
|
||||
// attempt the parse
|
||||
final NBT nbt = MinestomAdventure.NBT_CODEC.decode(raw);
|
||||
if (!(nbt instanceof NBTCompound contents)) throw new IOException("contents were not a compound");
|
||||
final NBTCompound tag = contents.getCompound(ITEM_TAG);
|
||||
// attempt the parse
|
||||
final CompoundBinaryTag contents = MinestomAdventure.NBT_CODEC.decode(raw);
|
||||
final CompoundBinaryTag tag = contents.getCompound(ITEM_TAG);
|
||||
|
||||
// create the event
|
||||
return HoverEvent.ShowItem.showItem(
|
||||
Key.key(Objects.requireNonNullElse(contents.getString(ITEM_TYPE), "")),
|
||||
Objects.requireNonNullElse(contents.getByte(ITEM_COUNT), (byte) 1),
|
||||
tag == null ? null : BinaryTagHolder.encode(tag, MinestomAdventure.NBT_CODEC)
|
||||
);
|
||||
} catch (final NBTException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
// create the event
|
||||
return HoverEvent.ShowItem.showItem(
|
||||
Key.key(contents.getString(ITEM_TYPE, "")),
|
||||
contents.getByte(ITEM_COUNT, (byte) 1),
|
||||
tag.size() == 0 ? null : BinaryTagHolder.encode(tag, MinestomAdventure.NBT_CODEC)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HoverEvent.@NotNull ShowEntity deserializeShowEntity(@NotNull Component input, Codec.Decoder<Component, String, ? extends RuntimeException> componentDecoder) throws IOException {
|
||||
final String raw = PlainTextComponentSerializer.plainText().serialize(input);
|
||||
try {
|
||||
final NBT nbt = MinestomAdventure.NBT_CODEC.decode(raw);
|
||||
if (!(nbt instanceof NBTCompound contents)) throw new IOException("contents were not a compound");
|
||||
|
||||
return HoverEvent.ShowEntity.showEntity(
|
||||
Key.key(Objects.requireNonNullElse(contents.getString(ENTITY_TYPE), "")),
|
||||
UUID.fromString(Objects.requireNonNullElse(contents.getString(ENTITY_ID), "")),
|
||||
componentDecoder.decode(Objects.requireNonNullElse(contents.getString(ENTITY_NAME), ""))
|
||||
);
|
||||
} catch (NBTException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
final CompoundBinaryTag contents = MinestomAdventure.NBT_CODEC.decode(raw);
|
||||
return HoverEvent.ShowEntity.showEntity(
|
||||
Key.key(contents.getString(ENTITY_TYPE, "")),
|
||||
UUID.fromString(Objects.requireNonNullElse(contents.getString(ENTITY_ID), "")),
|
||||
componentDecoder.decode(Objects.requireNonNullElse(contents.getString(ENTITY_NAME), ""))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component serializeShowItem(HoverEvent.@NotNull ShowItem input) throws IOException {
|
||||
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 {
|
||||
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));
|
||||
CompoundBinaryTag.Builder tag = CompoundBinaryTag.builder();
|
||||
tag.putString(ITEM_TYPE, input.item().asString());
|
||||
tag.putByte(ITEM_COUNT, (byte) input.count());
|
||||
final BinaryTagHolder nbt = input.nbt();
|
||||
if (nbt != null) tag.put(ITEM_TAG, nbt.get(MinestomAdventure.NBT_CODEC));
|
||||
return Component.text(MinestomAdventure.NBT_CODEC.encode(tag.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component serializeShowEntity(HoverEvent.@NotNull ShowEntity input, Codec.Encoder<Component, String, ? extends RuntimeException> componentEncoder) {
|
||||
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) {
|
||||
t.setString(ENTITY_NAME, componentEncoder.encode(name));
|
||||
}
|
||||
});
|
||||
|
||||
return Component.text(MinestomAdventure.NBT_CODEC.encode(tag));
|
||||
public @NotNull Component serializeShowEntity(HoverEvent.@NotNull ShowEntity input, Codec.Encoder<Component, String, ? extends RuntimeException> componentEncoder) throws IOException {
|
||||
CompoundBinaryTag.Builder tag = CompoundBinaryTag.builder();
|
||||
tag.putString(ENTITY_ID, input.id().toString());
|
||||
tag.putString(ENTITY_TYPE, input.type().asString());
|
||||
final Component name = input.name();
|
||||
if (name != null) tag.putString(ENTITY_NAME, componentEncoder.encode(name));
|
||||
return Component.text(MinestomAdventure.NBT_CODEC.encode(tag.build()));
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package net.minestom.server.adventure.serializer.nbt;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.ComponentSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
|
||||
public interface NbtComponentSerializer extends ComponentSerializer<Component, Component, NBT> {
|
||||
public interface NbtComponentSerializer extends ComponentSerializer<Component, Component, BinaryTag> {
|
||||
static @NotNull NbtComponentSerializer nbt() {
|
||||
return NbtComponentSerializerImpl.INSTANCE;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.adventure.serializer.nbt;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.*;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.kyori.adventure.text.*;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
@ -12,14 +13,10 @@ import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.intellij.lang.annotations.Subst;
|
||||
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.NBTType;
|
||||
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
//todo write tests for me!!
|
||||
@ -27,19 +24,19 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
static final NbtComponentSerializer INSTANCE = new NbtComponentSerializerImpl();
|
||||
|
||||
@Override
|
||||
public @NotNull Component deserialize(@NotNull NBT input) {
|
||||
public @NotNull Component deserialize(@NotNull BinaryTag input) {
|
||||
return deserializeAnyComponent(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull NBT serialize(@NotNull Component component) {
|
||||
public @NotNull BinaryTag serialize(@NotNull Component component) {
|
||||
return serializeComponent(component);
|
||||
}
|
||||
|
||||
// DESERIALIZATION
|
||||
|
||||
private @NotNull Component deserializeAnyComponent(@NotNull NBT nbt) {
|
||||
if (nbt instanceof NBTCompound compound) {
|
||||
private @NotNull Component deserializeAnyComponent(@NotNull BinaryTag nbt) {
|
||||
if (nbt instanceof CompoundBinaryTag compound) {
|
||||
return deserializeComponent(compound);
|
||||
} else {
|
||||
//todo raw string + list
|
||||
@ -47,12 +44,12 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
private @NotNull Component deserializeComponent(@NotNull NBTCompound compound) {
|
||||
private @NotNull Component deserializeComponent(@NotNull CompoundBinaryTag compound) {
|
||||
ComponentBuilder<?, ?> builder;
|
||||
var type = compound.getString("type");
|
||||
if (type != null) {
|
||||
var type = compound.get("type");
|
||||
if (type instanceof StringBinaryTag sType) {
|
||||
// If type is specified, use that
|
||||
builder = switch (type) {
|
||||
builder = switch (sType.value()) {
|
||||
case "text" -> deserializeTextComponent(compound);
|
||||
case "translatable" -> deserializeTranslatableComponent(compound);
|
||||
case "score" -> deserializeScoreComponent(compound);
|
||||
@ -63,26 +60,25 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
};
|
||||
} else {
|
||||
// Try to infer the type from the fields present.
|
||||
if (compound.containsKey("text")) {
|
||||
Set<String> keys = compound.keySet();
|
||||
if (keys.contains("text")) {
|
||||
builder = deserializeTextComponent(compound);
|
||||
} else if (compound.containsKey("translate")) {
|
||||
} else if (keys.contains("translate")) {
|
||||
builder = deserializeTranslatableComponent(compound);
|
||||
} else if (compound.containsKey("score")) {
|
||||
} else if (keys.contains("score")) {
|
||||
builder = deserializeScoreComponent(compound);
|
||||
} else if (compound.containsKey("selector")) {
|
||||
} else if (keys.contains("selector")) {
|
||||
builder = deserializeSelectorComponent(compound);
|
||||
} else if (compound.containsKey("keybind")) {
|
||||
} else if (keys.contains("keybind")) {
|
||||
builder = deserializeKeybindComponent(compound);
|
||||
} else if (compound.containsKey("nbt")) {
|
||||
} else if (keys.contains("nbt")) {
|
||||
builder = deserializeNbtComponent(compound);
|
||||
} else throw new UnsupportedOperationException("Unable to infer component type");
|
||||
}
|
||||
|
||||
// Children
|
||||
var extra = compound.getList("extra");
|
||||
Check.argCondition(extra != null && !extra.getSubtagType().equals(NBTType.TAG_Compound),
|
||||
"Extra field must be a list of compounds");
|
||||
if (extra != null) {
|
||||
var extra = compound.getList("extra", BinaryTagTypes.COMPOUND);
|
||||
if (extra.size() > 0) {
|
||||
var list = new ArrayList<ComponentLike>();
|
||||
for (var child : extra) list.add(deserializeAnyComponent(child));
|
||||
builder.append(list);
|
||||
@ -91,7 +87,7 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
// Formatting
|
||||
var style = Style.style();
|
||||
var color = compound.getString("color");
|
||||
if (color != null) {
|
||||
if (!color.isEmpty()) {
|
||||
var hexColor = TextColor.fromHexString(color);
|
||||
if (hexColor != null) {
|
||||
style.color(hexColor);
|
||||
@ -105,57 +101,60 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
}
|
||||
}
|
||||
@Subst("minecraft:default") var font = compound.getString("font");
|
||||
if (font != null) style.font(Key.key(font));
|
||||
var bold = compound.getByte("bold");
|
||||
if (bold != null) style.decoration(TextDecoration.BOLD, bold == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
var italic = compound.getByte("italic");
|
||||
if (italic != null) style.decoration(TextDecoration.ITALIC, italic == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
var underlined = compound.getByte("underlined");
|
||||
if (underlined != null) style.decoration(TextDecoration.UNDERLINED, underlined == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
var strikethrough = compound.getByte("strikethrough");
|
||||
if (strikethrough != null) style.decoration(TextDecoration.STRIKETHROUGH, strikethrough == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
var obfuscated = compound.getByte("obfuscated");
|
||||
if (obfuscated != null) style.decoration(TextDecoration.OBFUSCATED, obfuscated == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
if (!font.isEmpty()) style.font(Key.key(font));
|
||||
BinaryTag bold = compound.get("bold");
|
||||
if (bold instanceof ByteBinaryTag b)
|
||||
style.decoration(TextDecoration.BOLD, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
BinaryTag italic = compound.get("italic");
|
||||
if (italic instanceof ByteBinaryTag b)
|
||||
style.decoration(TextDecoration.ITALIC, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
BinaryTag underlined = compound.get("underlined");
|
||||
if (underlined instanceof ByteBinaryTag b)
|
||||
style.decoration(TextDecoration.UNDERLINED, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
BinaryTag strikethrough = compound.get("strikethrough");
|
||||
if (strikethrough instanceof ByteBinaryTag b)
|
||||
style.decoration(TextDecoration.STRIKETHROUGH, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
BinaryTag obfuscated = compound.get("obfuscated");
|
||||
if (obfuscated instanceof ByteBinaryTag b)
|
||||
style.decoration(TextDecoration.OBFUSCATED, b.value() == 1 ? TextDecoration.State.TRUE : TextDecoration.State.FALSE);
|
||||
builder.style(style.build());
|
||||
|
||||
// Interactivity
|
||||
var insertion = compound.getString("insertion");
|
||||
if (insertion != null) builder.insertion(insertion);
|
||||
if (!insertion.isEmpty()) builder.insertion(insertion);
|
||||
var clickEvent = compound.getCompound("clickEvent");
|
||||
if (clickEvent != null) builder.clickEvent(deserializeClickEvent(clickEvent));
|
||||
if (clickEvent.size() > 0) builder.clickEvent(deserializeClickEvent(clickEvent));
|
||||
var hoverEvent = compound.getCompound("hoverEvent");
|
||||
if (hoverEvent != null) builder.hoverEvent(deserializeHoverEvent(hoverEvent));
|
||||
if (hoverEvent.size() > 0) builder.hoverEvent(deserializeHoverEvent(hoverEvent));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeTextComponent(@NotNull NBTCompound compound) {
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeTextComponent(@NotNull CompoundBinaryTag compound) {
|
||||
var text = compound.getString("text");
|
||||
Check.notNull(text, "Text component must have a text field");
|
||||
return Component.text().content(text);
|
||||
}
|
||||
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeTranslatableComponent(@NotNull NBTCompound compound) {
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeTranslatableComponent(@NotNull CompoundBinaryTag compound) {
|
||||
var key = compound.getString("translate");
|
||||
Check.notNull(key, "Translatable component must have a translate field");
|
||||
var builder = Component.translatable().key(key);
|
||||
|
||||
var fallback = compound.getString("fallback");
|
||||
if (fallback != null) builder.fallback(fallback);
|
||||
var fallback = compound.get("fallback");
|
||||
if (fallback instanceof StringBinaryTag s) builder.fallback(s.value());
|
||||
|
||||
NBTList<NBTCompound> args = compound.getList("with");
|
||||
Check.argCondition(args != null && !args.getSubtagType().equals(NBTType.TAG_Compound),
|
||||
"Translatable component with field must be a list of compounds");
|
||||
if (args != null) {
|
||||
ListBinaryTag args = compound.getList("with", BinaryTagTypes.COMPOUND);
|
||||
if (args.size() > 0) {
|
||||
var list = new ArrayList<ComponentLike>();
|
||||
for (var arg : args) list.add(deserializeComponent(arg));
|
||||
for (var arg : args) list.add(deserializeComponent((CompoundBinaryTag) arg));
|
||||
builder.arguments(list);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeScoreComponent(@NotNull NBTCompound compound) {
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeScoreComponent(@NotNull CompoundBinaryTag compound) {
|
||||
var scoreCompound = compound.getCompound("score");
|
||||
Check.notNull(scoreCompound, "Score component must have a score field");
|
||||
var name = scoreCompound.getString("name");
|
||||
@ -165,14 +164,14 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
var builder = Component.score().name(name).objective(objective);
|
||||
|
||||
var value = scoreCompound.getString("value");
|
||||
if (value != null)
|
||||
if (!value.isEmpty())
|
||||
//noinspection deprecation
|
||||
builder.value(value);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeSelectorComponent(@NotNull NBTCompound compound) {
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeSelectorComponent(@NotNull CompoundBinaryTag compound) {
|
||||
var selector = compound.getString("selector");
|
||||
Check.notNull(selector, "Selector component must have a selector field");
|
||||
var builder = Component.selector().pattern(selector);
|
||||
@ -183,17 +182,17 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
return builder;
|
||||
}
|
||||
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeKeybindComponent(@NotNull NBTCompound compound) {
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeKeybindComponent(@NotNull CompoundBinaryTag compound) {
|
||||
var keybind = compound.getString("keybind");
|
||||
Check.notNull(keybind, "Keybind component must have a keybind field");
|
||||
return Component.keybind().keybind(keybind);
|
||||
}
|
||||
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeNbtComponent(@NotNull NBTCompound compound) {
|
||||
private @NotNull ComponentBuilder<?, ?> deserializeNbtComponent(@NotNull CompoundBinaryTag compound) {
|
||||
throw new UnsupportedOperationException("NBTComponent is not implemented yet");
|
||||
}
|
||||
|
||||
private @NotNull ClickEvent deserializeClickEvent(@NotNull NBTCompound compound) {
|
||||
private @NotNull ClickEvent deserializeClickEvent(@NotNull CompoundBinaryTag compound) {
|
||||
var actionName = compound.getString("action");
|
||||
Check.notNull(actionName, "Click event must have an action field");
|
||||
var action = ClickEvent.Action.NAMES.value(actionName);
|
||||
@ -203,7 +202,7 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
return ClickEvent.clickEvent(action, value);
|
||||
}
|
||||
|
||||
private @NotNull HoverEvent<?> deserializeHoverEvent(@NotNull NBTCompound compound) {
|
||||
private @NotNull HoverEvent<?> deserializeHoverEvent(@NotNull CompoundBinaryTag compound) {
|
||||
var actionName = compound.getString("action");
|
||||
Check.notNull(actionName, "Hover event must have an action field");
|
||||
var contents = compound.getCompound("contents");
|
||||
@ -216,13 +215,12 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
@Subst("minecraft:stick") var id = contents.getString("id");
|
||||
Check.notNull(id, "Show item hover event must have an id field");
|
||||
var count = contents.getInt("count");
|
||||
var countInt = count == null ? 1 : count;
|
||||
var tag = contents.getString("tag");
|
||||
var binaryTag = tag == null ? null : BinaryTagHolder.binaryTagHolder(tag);
|
||||
return HoverEvent.showItem(Key.key(id), countInt, binaryTag);
|
||||
var binaryTag = tag.isEmpty() ? null : BinaryTagHolder.binaryTagHolder(tag);
|
||||
return HoverEvent.showItem(Key.key(id), count, binaryTag);
|
||||
} else if (action == HoverEvent.Action.SHOW_ENTITY) {
|
||||
var name = contents.getCompound("name");
|
||||
var nameComponent = name == null ? null : deserializeComponent(name);
|
||||
var nameComponent = name.size() == 0 ? null : deserializeComponent(name);
|
||||
@Subst("minecraft:pig") var type = contents.getString("type");
|
||||
Check.notNull(type, "Show entity hover event must have a type field");
|
||||
var id = contents.getString("id");
|
||||
@ -235,36 +233,36 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
|
||||
// SERIALIZATION
|
||||
|
||||
private @NotNull NBT serializeComponent(@NotNull Component component) {
|
||||
MutableNBTCompound compound = new MutableNBTCompound();
|
||||
private @NotNull CompoundBinaryTag serializeComponent(@NotNull Component component) {
|
||||
CompoundBinaryTag.Builder compound = CompoundBinaryTag.builder();
|
||||
|
||||
// Base component types
|
||||
if (component instanceof TextComponent text) {
|
||||
compound.setString("type", "text");
|
||||
compound.setString("text", text.content());
|
||||
compound.putString("type", "text");
|
||||
compound.putString("text", text.content());
|
||||
} else if (component instanceof TranslatableComponent translatable) {
|
||||
compound.setString("type", "translatable");
|
||||
compound.setString("translate", translatable.key());
|
||||
compound.putString("type", "translatable");
|
||||
compound.putString("translate", translatable.key());
|
||||
var fallback = translatable.fallback();
|
||||
if (fallback != null) compound.setString("fallback", fallback);
|
||||
if (fallback != null) compound.putString("fallback", fallback);
|
||||
var args = translatable.arguments();
|
||||
if (!args.isEmpty()) compound.set("with", serializeTranslationArgs(args));
|
||||
if (!args.isEmpty()) compound.put("with", serializeTranslationArgs(args));
|
||||
} else if (component instanceof ScoreComponent score) {
|
||||
compound.setString("type", "score");
|
||||
var scoreCompound = new MutableNBTCompound();
|
||||
scoreCompound.setString("name", score.name());
|
||||
scoreCompound.setString("objective", score.objective());
|
||||
compound.putString("type", "score");
|
||||
CompoundBinaryTag.Builder scoreCompound = CompoundBinaryTag.builder();
|
||||
scoreCompound.putString("name", score.name());
|
||||
scoreCompound.putString("objective", score.objective());
|
||||
@SuppressWarnings("deprecation") var value = score.value();
|
||||
if (value != null) scoreCompound.setString("value", value);
|
||||
compound.set("score", scoreCompound.toCompound());
|
||||
if (value != null) scoreCompound.putString("value", value);
|
||||
compound.put("score", scoreCompound.build());
|
||||
} else if (component instanceof SelectorComponent selector) {
|
||||
compound.setString("type", "selector");
|
||||
compound.setString("selector", selector.pattern());
|
||||
compound.putString("type", "selector");
|
||||
compound.putString("selector", selector.pattern());
|
||||
var separator = selector.separator();
|
||||
if (separator != null) compound.set("separator", serializeComponent(separator));
|
||||
if (separator != null) compound.put("separator", serializeComponent(separator));
|
||||
} else if (component instanceof KeybindComponent keybind) {
|
||||
compound.setString("type", "keybind");
|
||||
compound.setString("keybind", keybind.keybind());
|
||||
compound.putString("type", "keybind");
|
||||
compound.putString("keybind", keybind.keybind());
|
||||
} else if (component instanceof NBTComponent<?, ?> nbt) {
|
||||
//todo
|
||||
throw new UnsupportedOperationException("NBTComponent is not implemented yet");
|
||||
@ -274,10 +272,10 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
|
||||
// Children
|
||||
if (!component.children().isEmpty()) {
|
||||
var children = new ArrayList<NBT>();
|
||||
ListBinaryTag.Builder<CompoundBinaryTag> children = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
|
||||
for (var child : component.children())
|
||||
children.add(serializeComponent(child));
|
||||
compound.set("extra", new NBTList<>(NBTType.TAG_Compound, children));
|
||||
compound.put("extra", children.build());
|
||||
}
|
||||
|
||||
// Formatting
|
||||
@ -285,94 +283,89 @@ final class NbtComponentSerializerImpl implements NbtComponentSerializer {
|
||||
var color = style.color();
|
||||
if (color != null) {
|
||||
if (color instanceof NamedTextColor named) {
|
||||
compound.setString("color", named.toString());
|
||||
compound.putString("color", named.toString());
|
||||
} else {
|
||||
compound.setString("color", color.asHexString());
|
||||
compound.putString("color", color.asHexString());
|
||||
}
|
||||
}
|
||||
var font = style.font();
|
||||
if (font != null)
|
||||
compound.setString("font", font.toString());
|
||||
compound.putString("font", font.toString());
|
||||
var bold = style.decoration(TextDecoration.BOLD);
|
||||
if (bold != TextDecoration.State.NOT_SET)
|
||||
setBool(compound, "bold", bold == TextDecoration.State.TRUE);
|
||||
compound.putBoolean("bold", bold == TextDecoration.State.TRUE);
|
||||
var italic = style.decoration(TextDecoration.ITALIC);
|
||||
if (italic != TextDecoration.State.NOT_SET)
|
||||
setBool(compound, "italic", italic == TextDecoration.State.TRUE);
|
||||
compound.putBoolean("italic", italic == TextDecoration.State.TRUE);
|
||||
var underlined = style.decoration(TextDecoration.UNDERLINED);
|
||||
if (underlined != TextDecoration.State.NOT_SET)
|
||||
setBool(compound, "underlined", underlined == TextDecoration.State.TRUE);
|
||||
compound.putBoolean("underlined", underlined == TextDecoration.State.TRUE);
|
||||
var strikethrough = style.decoration(TextDecoration.STRIKETHROUGH);
|
||||
if (strikethrough != TextDecoration.State.NOT_SET)
|
||||
setBool(compound, "strikethrough", strikethrough == TextDecoration.State.TRUE);
|
||||
compound.putBoolean("strikethrough", strikethrough == TextDecoration.State.TRUE);
|
||||
var obfuscated = style.decoration(TextDecoration.OBFUSCATED);
|
||||
if (obfuscated != TextDecoration.State.NOT_SET)
|
||||
setBool(compound, "obfuscated", obfuscated == TextDecoration.State.TRUE);
|
||||
compound.putBoolean("obfuscated", obfuscated == TextDecoration.State.TRUE);
|
||||
|
||||
// Interactivity
|
||||
var insertion = component.insertion();
|
||||
if (insertion != null) compound.setString("insertion", insertion);
|
||||
if (insertion != null) compound.putString("insertion", insertion);
|
||||
var clickEvent = component.clickEvent();
|
||||
if (clickEvent != null) compound.set("clickEvent", serializeClickEvent(clickEvent));
|
||||
if (clickEvent != null) compound.put("clickEvent", serializeClickEvent(clickEvent));
|
||||
var hoverEvent = component.hoverEvent();
|
||||
if (hoverEvent != null) compound.set("hoverEvent", serializeHoverEvent(hoverEvent));
|
||||
if (hoverEvent != null) compound.put("hoverEvent", serializeHoverEvent(hoverEvent));
|
||||
|
||||
return compound.toCompound();
|
||||
return compound.build();
|
||||
}
|
||||
|
||||
private @NotNull NBT serializeTranslationArgs(@NotNull Collection<TranslationArgument> args) {
|
||||
var list = new ArrayList<NBT>();
|
||||
private @NotNull BinaryTag serializeTranslationArgs(@NotNull Collection<TranslationArgument> args) {
|
||||
ListBinaryTag.Builder<CompoundBinaryTag> argList = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
|
||||
for (var arg : args)
|
||||
list.add(serializeComponent(arg.asComponent()));
|
||||
return new NBTList<>(NBTType.TAG_Compound, list);
|
||||
argList.add(serializeComponent(arg.asComponent()));
|
||||
return argList.build();
|
||||
}
|
||||
|
||||
private @NotNull NBT serializeClickEvent(@NotNull ClickEvent event) {
|
||||
var compound = new MutableNBTCompound();
|
||||
compound.setString("action", event.action().toString());
|
||||
compound.setString("value", event.value());
|
||||
return compound.toCompound();
|
||||
private @NotNull BinaryTag serializeClickEvent(@NotNull ClickEvent event) {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("action", event.action().toString())
|
||||
.putString("value", event.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private @NotNull NBT serializeHoverEvent(@NotNull HoverEvent<?> event) {
|
||||
var compound = new MutableNBTCompound();
|
||||
private @NotNull BinaryTag serializeHoverEvent(@NotNull HoverEvent<?> event) {
|
||||
CompoundBinaryTag.Builder compound = CompoundBinaryTag.builder();
|
||||
|
||||
//todo surely there is a better way to do this?
|
||||
compound.setString("action", event.action().toString());
|
||||
compound.putString("action", event.action().toString());
|
||||
if (event.action() == HoverEvent.Action.SHOW_TEXT) {
|
||||
var value = ((HoverEvent<Component>) event).value();
|
||||
compound.set("contents", serializeComponent(value));
|
||||
compound.put("contents", serializeComponent(value));
|
||||
} else if (event.action() == HoverEvent.Action.SHOW_ITEM) {
|
||||
var value = ((HoverEvent<HoverEvent.ShowItem>) event).value();
|
||||
|
||||
var itemCompound = new MutableNBTCompound();
|
||||
itemCompound.setString("id", value.item().asString());
|
||||
if (value.count() != 1) itemCompound.setInt("count", value.count());
|
||||
CompoundBinaryTag.Builder itemCompound = CompoundBinaryTag.builder();
|
||||
itemCompound.putString("id", value.item().asString());
|
||||
if (value.count() != 1) itemCompound.putInt("count", value.count());
|
||||
var tag = value.nbt();
|
||||
if (tag != null) itemCompound.setString("tag", tag.string());
|
||||
if (tag != null) itemCompound.putString("tag", tag.string());
|
||||
|
||||
compound.set("contents", itemCompound.toCompound());
|
||||
compound.put("contents", itemCompound.build());
|
||||
} else if (event.action() == HoverEvent.Action.SHOW_ENTITY) {
|
||||
var value = ((HoverEvent<HoverEvent.ShowEntity>) event).value();
|
||||
|
||||
var entityCompound = new MutableNBTCompound();
|
||||
CompoundBinaryTag.Builder entityCompound = CompoundBinaryTag.builder();
|
||||
var name = value.name();
|
||||
if (name != null) entityCompound.set("name", serializeComponent(name));
|
||||
entityCompound.setString("type", value.type().asString());
|
||||
entityCompound.setString("id", value.id().toString());
|
||||
if (name != null) entityCompound.put("name", serializeComponent(name));
|
||||
entityCompound.putString("type", value.type().asString());
|
||||
entityCompound.putString("id", value.id().toString());
|
||||
|
||||
compound.set("contents", entityCompound.toCompound());
|
||||
compound.put("contents", entityCompound.build());
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unknown hover event action: " + event.action());
|
||||
}
|
||||
|
||||
return compound.toCompound();
|
||||
return compound.build();
|
||||
}
|
||||
|
||||
private void setBool(@NotNull MutableNBTCompound compound, @NotNull String key, boolean value) {
|
||||
compound.setByte(key, value ? (byte) 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
package net.minestom.server.command.builder.arguments.minecraft;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTException;
|
||||
import org.jglrxavpok.hephaistos.parser.SNBTParser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Argument which can be used to retrieve an {@link ItemStack} from its material and with NBT data.
|
||||
@ -65,10 +64,10 @@ public class ArgumentItemStack extends Argument<ItemStack> {
|
||||
|
||||
final String sNBT = input.substring(nbtIndex).replace("\\\"", "\"");
|
||||
|
||||
NBTCompound compound;
|
||||
CompoundBinaryTag compound;
|
||||
try {
|
||||
compound = (NBTCompound) new SNBTParser(new StringReader(sNBT)).parse();
|
||||
} catch (NBTException e) {
|
||||
compound = TagStringIO.get().asCompound(sNBT);
|
||||
} catch (IOException e) {
|
||||
throw new ArgumentSyntaxException("Item NBT is invalid", input, INVALID_NBT);
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,21 @@
|
||||
package net.minestom.server.command.builder.arguments.minecraft;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
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.parser.SNBTParser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Argument used to retrieve a {@link NBTCompound} if you need key-value data.
|
||||
* Argument used to retrieve a {@link CompoundBinaryTag} if you need key-value data.
|
||||
* <p>
|
||||
* Example: {display:{Name:"{\"text\":\"Sword of Power\"}"}}
|
||||
*/
|
||||
public class ArgumentNbtCompoundTag extends Argument<NBTCompound> {
|
||||
public class ArgumentNbtCompoundTag extends Argument<CompoundBinaryTag> {
|
||||
|
||||
public static final int INVALID_NBT = 1;
|
||||
|
||||
@ -26,15 +25,15 @@ public class ArgumentNbtCompoundTag extends Argument<NBTCompound> {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public NBTCompound parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
|
||||
public CompoundBinaryTag parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
|
||||
try {
|
||||
NBT nbt = new SNBTParser(new StringReader(input)).parse();
|
||||
BinaryTag nbt = TagStringIO.get().asCompound(input);
|
||||
|
||||
if (!(nbt instanceof NBTCompound))
|
||||
if (!(nbt instanceof CompoundBinaryTag compound))
|
||||
throw new ArgumentSyntaxException("NBTCompound is invalid", input, INVALID_NBT);
|
||||
|
||||
return (NBTCompound) nbt;
|
||||
} catch (NBTException e) {
|
||||
return compound;
|
||||
} catch (IOException e) {
|
||||
throw new ArgumentSyntaxException("NBTCompound is invalid", input, INVALID_NBT);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,22 @@
|
||||
package net.minestom.server.command.builder.arguments.minecraft;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTException;
|
||||
import org.jglrxavpok.hephaistos.parser.SNBTParser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Argument used to retrieve a {@link NBT} based object, can be any kind of tag like
|
||||
* {@link org.jglrxavpok.hephaistos.nbt.NBTCompound}, {@link org.jglrxavpok.hephaistos.nbt.NBTList},
|
||||
* {@link org.jglrxavpok.hephaistos.nbt.NBTInt}, etc...
|
||||
* Argument used to retrieve a {@link BinaryTag} based object, can be any kind of tag like
|
||||
* {@link net.kyori.adventure.nbt.CompoundBinaryTag}, {@link net.kyori.adventure.nbt.ListBinaryTag},
|
||||
* {@link net.kyori.adventure.nbt.IntBinaryTag}, etc...
|
||||
* <p>
|
||||
* Example: {display:{Name:"{\"text\":\"Sword of Power\"}"}} or [{display:{Name:"{\"text\":\"Sword of Power\"}"}}]
|
||||
*/
|
||||
public class ArgumentNbtTag extends Argument<NBT> {
|
||||
public class ArgumentNbtTag extends Argument<BinaryTag> {
|
||||
|
||||
public static final int INVALID_NBT = 1;
|
||||
|
||||
@ -27,10 +26,10 @@ public class ArgumentNbtTag extends Argument<NBT> {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public NBT parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
|
||||
public BinaryTag parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
|
||||
try {
|
||||
return new SNBTParser(new StringReader(input)).parse();
|
||||
} catch (NBTException e) {
|
||||
return TagStringIO.get().asCompound(input);
|
||||
} catch (IOException e) {
|
||||
throw new ArgumentSyntaxException("Invalid NBT", input, INVALID_NBT);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.entity;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.entity.metadata.animal.FrogMeta;
|
||||
@ -15,7 +16,6 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
@ -100,7 +100,7 @@ public final class Metadata {
|
||||
});
|
||||
}
|
||||
|
||||
public static Entry<NBT> NBT(@NotNull NBT nbt) {
|
||||
public static Entry<BinaryTag> NBT(@NotNull BinaryTag nbt) {
|
||||
return new MetadataImpl.EntryImpl<>(TYPE_NBT, nbt, NetworkBuffer.NBT);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.entity;
|
||||
|
||||
import net.kyori.adventure.nbt.EndBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.metadata.animal.FrogMeta;
|
||||
@ -13,7 +14,6 @@ import net.minestom.server.utils.Direction;
|
||||
import net.minestom.server.utils.collection.ObjectArray;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTEnd;
|
||||
|
||||
import static net.minestom.server.entity.Metadata.*;
|
||||
import static net.minestom.server.network.NetworkBuffer.VAR_INT;
|
||||
@ -38,7 +38,7 @@ final class MetadataImpl {
|
||||
EMPTY_VALUES.set(TYPE_OPTUUID, OptUUID(null));
|
||||
EMPTY_VALUES.set(TYPE_BLOCKSTATE, BlockState(Block.AIR.id()));
|
||||
EMPTY_VALUES.set(TYPE_OPTBLOCKSTATE, OptBlockState(null));
|
||||
EMPTY_VALUES.set(TYPE_NBT, NBT(NBTEnd.INSTANCE));
|
||||
EMPTY_VALUES.set(TYPE_NBT, NBT(EndBinaryTag.endBinaryTag()));
|
||||
//EMPTY_VALUES.set(TYPE_PARTICLE -> throw new UnsupportedOperationException();
|
||||
EMPTY_VALUES.set(TYPE_VILLAGERDATA, VillagerData(0, 0, 0));
|
||||
EMPTY_VALUES.set(TYPE_OPTVARINT, OptVarInt(null));
|
||||
|
@ -1,12 +1,12 @@
|
||||
package net.minestom.server.entity.damage;
|
||||
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@ -36,7 +36,7 @@ public sealed interface DamageType extends StaticProtocolObject, DamageTypes per
|
||||
return registry().scaling();
|
||||
}
|
||||
|
||||
NBTCompound asNBT();
|
||||
CompoundBinaryTag asNBT();
|
||||
|
||||
static @NotNull Collection<@NotNull DamageType> values() {
|
||||
return DamageTypeImpl.values();
|
||||
@ -54,7 +54,7 @@ public sealed interface DamageType extends StaticProtocolObject, DamageTypes per
|
||||
return DamageTypeImpl.getId(id);
|
||||
}
|
||||
|
||||
static NBTCompound getNBT() {
|
||||
static CompoundBinaryTag getNBT() {
|
||||
return DamageTypeImpl.getNBT();
|
||||
}
|
||||
}
|
@ -1,14 +1,12 @@
|
||||
package net.minestom.server.entity.damage;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements DamageType {
|
||||
@ -33,12 +31,12 @@ record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements Dama
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTCompound asNBT() {
|
||||
var elem = new HashMap<String, NBT>();
|
||||
elem.put("exhaustion", NBT.Float(registry.exhaustion()));
|
||||
elem.put("message_id", NBT.String(registry.messageId()));
|
||||
elem.put("scaling", NBT.String(registry.scaling()));
|
||||
return NBT.Compound(elem);
|
||||
public CompoundBinaryTag asNBT() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putFloat("exhaustion", registry.exhaustion())
|
||||
.putString("message_id", registry.messageId())
|
||||
.putString("scaling", registry.scaling())
|
||||
.build();
|
||||
}
|
||||
|
||||
static Collection<DamageType> values() {
|
||||
@ -55,22 +53,23 @@ record DamageTypeImpl(Registry.DamageTypeEntry registry, int id) implements Dama
|
||||
return id;
|
||||
}
|
||||
|
||||
private static NBTCompound lazyNbt = null;
|
||||
private static CompoundBinaryTag lazyNbt = null;
|
||||
|
||||
static NBTCompound getNBT() {
|
||||
static CompoundBinaryTag getNBT() {
|
||||
if (lazyNbt == null) {
|
||||
var damageTypes = values().stream()
|
||||
.map((damageType) -> NBT.Compound(Map.of(
|
||||
"id", NBT.Int(damageType.id()),
|
||||
"name", NBT.String(damageType.name()),
|
||||
"element", damageType.asNBT()
|
||||
)))
|
||||
.toList();
|
||||
var entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
|
||||
for (var damageType : values()) {
|
||||
entries.add(CompoundBinaryTag.builder()
|
||||
.putInt("id", damageType.id())
|
||||
.putString("name", damageType.name())
|
||||
.put("element", damageType.asNBT())
|
||||
.build());
|
||||
}
|
||||
|
||||
lazyNbt = NBT.Compound(Map.of(
|
||||
"type", NBT.String("minecraft:damage_type"),
|
||||
"value", NBT.List(NBTType.TAG_Compound, damageTypes)
|
||||
));
|
||||
lazyNbt = CompoundBinaryTag.builder()
|
||||
.putString("type", "minecraft:damage_type")
|
||||
.put("value", entries.build())
|
||||
.build();
|
||||
}
|
||||
return lazyNbt;
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
package net.minestom.server.entity.metadata;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Metadata;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PlayerMeta extends LivingEntityMeta {
|
||||
public static final byte OFFSET = LivingEntityMeta.MAX_OFFSET;
|
||||
@ -109,23 +108,23 @@ public class PlayerMeta extends LivingEntityMeta {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public NBT getLeftShoulderEntityData() {
|
||||
public BinaryTag getLeftShoulderEntityData() {
|
||||
return super.metadata.getIndex(OFFSET + 4, null);
|
||||
}
|
||||
|
||||
public void setLeftShoulderEntityData(@Nullable NBT value) {
|
||||
if (value == null) value = NBT.Compound(Map.of());
|
||||
public void setLeftShoulderEntityData(@Nullable BinaryTag value) {
|
||||
if (value == null) value = CompoundBinaryTag.empty();
|
||||
|
||||
super.metadata.setIndex(OFFSET + 4, Metadata.NBT(value));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public NBT getRightShoulderEntityData() {
|
||||
public BinaryTag getRightShoulderEntityData() {
|
||||
return super.metadata.getIndex(OFFSET + 5, null);
|
||||
}
|
||||
|
||||
public void setRightShoulderEntityData(@Nullable NBT value) {
|
||||
if (value == null) value = NBT.Compound(Map.of());
|
||||
public void setRightShoulderEntityData(@Nullable BinaryTag value) {
|
||||
if (value == null) value = CompoundBinaryTag.empty();
|
||||
|
||||
super.metadata.setIndex(OFFSET + 5, Metadata.NBT(value));
|
||||
}
|
||||
|
@ -1,35 +1,17 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntIntImmutablePair;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockHandler;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.utils.async.AsyncUtils;
|
||||
import net.minestom.server.world.biomes.Biome;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.mca.*;
|
||||
import org.jglrxavpok.hephaistos.mca.readers.ChunkReader;
|
||||
import org.jglrxavpok.hephaistos.mca.readers.ChunkSectionReader;
|
||||
import org.jglrxavpok.hephaistos.mca.readers.SectionBiomeInformation;
|
||||
import org.jglrxavpok.hephaistos.mca.writer.ChunkSectionWriter;
|
||||
import org.jglrxavpok.hephaistos.mca.writer.ChunkWriter;
|
||||
import org.jglrxavpok.hephaistos.nbt.*;
|
||||
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@ -37,7 +19,7 @@ public class AnvilLoader implements IChunkLoader {
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(AnvilLoader.class);
|
||||
private final static Biome PLAINS = MinecraftServer.getBiomeManager().getByName(NamespaceID.from("minecraft:plains"));
|
||||
|
||||
private final Map<String, RegionFile> alreadyLoaded = new ConcurrentHashMap<>();
|
||||
// private final Map<String, RegionFile> alreadyLoaded = new ConcurrentHashMap<>();
|
||||
private final Path path;
|
||||
private final Path levelPath;
|
||||
private final Path regionPath;
|
||||
@ -51,7 +33,7 @@ public class AnvilLoader implements IChunkLoader {
|
||||
private final RegionCache perRegionLoadedChunks = new RegionCache();
|
||||
|
||||
// thread local to avoid contention issues with locks
|
||||
private final ThreadLocal<Int2ObjectMap<BlockState>> blockStateId2ObjectCacheTLS = ThreadLocal.withInitial(Int2ObjectArrayMap::new);
|
||||
// private final ThreadLocal<Int2ObjectMap<BlockState>> blockStateId2ObjectCacheTLS = ThreadLocal.withInitial(Int2ObjectArrayMap::new);
|
||||
|
||||
public AnvilLoader(@NotNull Path path) {
|
||||
this.path = path;
|
||||
@ -65,415 +47,409 @@ public class AnvilLoader implements IChunkLoader {
|
||||
|
||||
@Override
|
||||
public void loadInstance(@NotNull Instance instance) {
|
||||
if (!Files.exists(levelPath)) {
|
||||
return;
|
||||
}
|
||||
try (var reader = new NBTReader(Files.newInputStream(levelPath))) {
|
||||
final NBTCompound tag = (NBTCompound) reader.read();
|
||||
Files.copy(levelPath, path.resolve("level.dat_old"), StandardCopyOption.REPLACE_EXISTING);
|
||||
instance.tagHandler().updateContent(tag);
|
||||
} catch (IOException | NBTException e) {
|
||||
MinecraftServer.getExceptionManager().handleException(e);
|
||||
}
|
||||
// if (!Files.exists(levelPath)) {
|
||||
// return;
|
||||
// }
|
||||
// try (var reader = new NBTReader(Files.newInputStream(levelPath))) {
|
||||
// final NBTCompound tag = (NBTCompound) reader.read();
|
||||
// Files.copy(levelPath, path.resolve("level.dat_old"), StandardCopyOption.REPLACE_EXISTING);
|
||||
// instance.tagHandler().updateContent(tag);
|
||||
// } catch (IOException | NBTException e) {
|
||||
// MinecraftServer.getExceptionManager().handleException(e);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) {
|
||||
if (!Files.exists(path)) {
|
||||
// No world folder
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
try {
|
||||
return loadMCA(instance, chunkX, chunkZ);
|
||||
} catch (Exception e) {
|
||||
MinecraftServer.getExceptionManager().handleException(e);
|
||||
}
|
||||
// if (!Files.exists(path)) {
|
||||
// // No world folder
|
||||
// return CompletableFuture.completedFuture(null);
|
||||
// }
|
||||
// try {
|
||||
// return loadMCA(instance, chunkX, chunkZ);
|
||||
// } catch (Exception e) {
|
||||
// MinecraftServer.getExceptionManager().handleException(e);
|
||||
// }
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
private @NotNull CompletableFuture<@Nullable Chunk> loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException, AnvilException {
|
||||
final RegionFile mcaFile = getMCAFile(instance, chunkX, chunkZ);
|
||||
if (mcaFile == null)
|
||||
return CompletableFuture.completedFuture(null);
|
||||
final NBTCompound chunkData = mcaFile.getChunkData(chunkX, chunkZ);
|
||||
if (chunkData == null)
|
||||
return CompletableFuture.completedFuture(null);
|
||||
|
||||
final ChunkReader chunkReader = new ChunkReader(chunkData);
|
||||
|
||||
Chunk chunk = instance.getChunkSupplier().createChunk(instance, chunkX, chunkZ);
|
||||
synchronized (chunk) {
|
||||
var yRange = chunkReader.getYRange();
|
||||
if (yRange.getStart() < instance.getDimensionType().getMinY()) {
|
||||
throw new AnvilException(
|
||||
String.format("Trying to load chunk with minY = %d, but instance dimension type (%s) has a minY of %d",
|
||||
yRange.getStart(),
|
||||
instance.getDimensionType().getName().asString(),
|
||||
instance.getDimensionType().getMinY()
|
||||
));
|
||||
}
|
||||
if (yRange.getEndInclusive() > instance.getDimensionType().getMaxY()) {
|
||||
throw new AnvilException(
|
||||
String.format("Trying to load chunk with maxY = %d, but instance dimension type (%s) has a maxY of %d",
|
||||
yRange.getEndInclusive(),
|
||||
instance.getDimensionType().getName().asString(),
|
||||
instance.getDimensionType().getMaxY()
|
||||
));
|
||||
}
|
||||
|
||||
// TODO: Parallelize block, block entities and biome loading
|
||||
// Blocks + Biomes
|
||||
loadSections(chunk, chunkReader);
|
||||
|
||||
// Block entities
|
||||
loadBlockEntities(chunk, chunkReader);
|
||||
|
||||
chunk.loadHeightmapsFromNBT(chunkReader.getHeightmaps());
|
||||
}
|
||||
synchronized (perRegionLoadedChunks) {
|
||||
int regionX = CoordinatesKt.chunkToRegion(chunkX);
|
||||
int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
|
||||
var chunks = perRegionLoadedChunks.computeIfAbsent(new IntIntImmutablePair(regionX, regionZ), r -> new HashSet<>()); // region cache may have been removed on another thread due to unloadChunk
|
||||
chunks.add(new IntIntImmutablePair(chunkX, chunkZ));
|
||||
}
|
||||
return CompletableFuture.completedFuture(chunk);
|
||||
}
|
||||
|
||||
private @Nullable RegionFile getMCAFile(Instance instance, int chunkX, int chunkZ) {
|
||||
final int regionX = CoordinatesKt.chunkToRegion(chunkX);
|
||||
final int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
|
||||
return alreadyLoaded.computeIfAbsent(RegionFile.Companion.createFileName(regionX, regionZ), n -> {
|
||||
try {
|
||||
final Path regionPath = this.regionPath.resolve(n);
|
||||
if (!Files.exists(regionPath)) {
|
||||
return null;
|
||||
}
|
||||
synchronized (perRegionLoadedChunks) {
|
||||
Set<IntIntImmutablePair> previousVersion = perRegionLoadedChunks.put(new IntIntImmutablePair(regionX, regionZ), new HashSet<>());
|
||||
assert previousVersion == null : "The AnvilLoader cache should not already have data for this region.";
|
||||
}
|
||||
return new RegionFile(new RandomAccessFile(regionPath.toFile(), "rw"), regionX, regionZ, instance.getDimensionType().getMinY(), instance.getDimensionType().getMaxY() - 1);
|
||||
} catch (IOException | AnvilException e) {
|
||||
MinecraftServer.getExceptionManager().handleException(e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadSections(Chunk chunk, ChunkReader chunkReader) {
|
||||
final HashMap<String, Biome> biomeCache = new HashMap<>();
|
||||
for (NBTCompound sectionNBT : chunkReader.getSections()) {
|
||||
ChunkSectionReader sectionReader = new ChunkSectionReader(chunkReader.getMinecraftVersion(), sectionNBT);
|
||||
|
||||
if (sectionReader.isSectionEmpty()) continue;
|
||||
final int sectionY = sectionReader.getY();
|
||||
final int yOffset = Chunk.CHUNK_SECTION_SIZE * sectionY;
|
||||
|
||||
Section section = chunk.getSection(sectionY);
|
||||
|
||||
if (sectionReader.getSkyLight() != null) {
|
||||
section.setSkyLight(sectionReader.getSkyLight().copyArray());
|
||||
}
|
||||
if (sectionReader.getBlockLight() != null) {
|
||||
section.setBlockLight(sectionReader.getBlockLight().copyArray());
|
||||
}
|
||||
|
||||
// Biomes
|
||||
if (chunkReader.getGenerationStatus().compareTo(ChunkColumn.GenerationStatus.Biomes) > 0) {
|
||||
SectionBiomeInformation sectionBiomeInformation = chunkReader.readSectionBiomes(sectionReader);
|
||||
|
||||
if (sectionBiomeInformation != null && sectionBiomeInformation.hasBiomeInformation()) {
|
||||
if (sectionBiomeInformation.isFilledWithSingleBiome()) {
|
||||
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 = chunk.chunkX * Chunk.CHUNK_SIZE_X + x;
|
||||
int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z;
|
||||
int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y;
|
||||
String biomeName = sectionBiomeInformation.getBaseBiome();
|
||||
Biome biome = biomeCache.computeIfAbsent(biomeName, n ->
|
||||
Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS));
|
||||
chunk.setBiome(finalX, finalY, finalZ, biome);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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 = chunk.chunkX * Chunk.CHUNK_SIZE_X + x;
|
||||
int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z;
|
||||
int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y;
|
||||
|
||||
int index = x / 4 + (z / 4) * 4 + (y / 4) * 16;
|
||||
String biomeName = sectionBiomeInformation.getBiomes()[index];
|
||||
Biome biome = biomeCache.computeIfAbsent(biomeName, n ->
|
||||
Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS));
|
||||
chunk.setBiome(finalX, finalY, finalZ, biome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Blocks
|
||||
final NBTList<NBTCompound> blockPalette = sectionReader.getBlockPalette();
|
||||
if (blockPalette != null) {
|
||||
final int[] blockStateIndices = sectionReader.getUncompressedBlockStateIDs();
|
||||
Block[] convertedPalette = new Block[blockPalette.getSize()];
|
||||
for (int i = 0; i < convertedPalette.length; i++) {
|
||||
final NBTCompound paletteEntry = blockPalette.get(i);
|
||||
String blockName = Objects.requireNonNull(paletteEntry.getString("Name"));
|
||||
if (blockName.equals("minecraft:air")) {
|
||||
convertedPalette[i] = Block.AIR;
|
||||
} else {
|
||||
if (blockName.equals("minecraft:grass")) {
|
||||
blockName = "minecraft:short_grass";
|
||||
}
|
||||
Block block = Objects.requireNonNull(Block.fromNamespaceId(blockName));
|
||||
// Properties
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
NBTCompound propertiesNBT = paletteEntry.getCompound("Properties");
|
||||
if (propertiesNBT != null) {
|
||||
for (var property : propertiesNBT) {
|
||||
if (property.getValue().getID() != NBTType.TAG_String) {
|
||||
LOGGER.warn("Fail to parse block state properties {}, expected a TAG_String for {}, but contents were {}",
|
||||
propertiesNBT,
|
||||
property.getKey(),
|
||||
property.getValue().toSNBT());
|
||||
} else {
|
||||
properties.put(property.getKey(), ((NBTString) property.getValue()).getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!properties.isEmpty()) block = block.withProperties(properties);
|
||||
// Handler
|
||||
final BlockHandler handler = MinecraftServer.getBlockManager().getHandler(block.name());
|
||||
if (handler != null) block = block.withHandler(handler);
|
||||
|
||||
convertedPalette[i] = block;
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
|
||||
for (int z = 0; z < Chunk.CHUNK_SECTION_SIZE; z++) {
|
||||
for (int x = 0; x < Chunk.CHUNK_SECTION_SIZE; x++) {
|
||||
try {
|
||||
final int blockIndex = y * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SECTION_SIZE + z * Chunk.CHUNK_SECTION_SIZE + x;
|
||||
final int paletteIndex = blockStateIndices[blockIndex];
|
||||
final Block block = convertedPalette[paletteIndex];
|
||||
|
||||
chunk.setBlock(x, y + yOffset, z, block);
|
||||
} catch (Exception e) {
|
||||
MinecraftServer.getExceptionManager().handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadBlockEntities(Chunk loadedChunk, ChunkReader chunkReader) {
|
||||
for (NBTCompound te : chunkReader.getBlockEntities()) {
|
||||
final var x = te.getInt("x");
|
||||
final var y = te.getInt("y");
|
||||
final var z = te.getInt("z");
|
||||
if (x == null || y == null || z == null) {
|
||||
LOGGER.warn("Tile entity has failed to load due to invalid coordinate");
|
||||
continue;
|
||||
}
|
||||
Block block = loadedChunk.getBlock(x, y, z);
|
||||
|
||||
final String tileEntityID = te.getString("id");
|
||||
if (tileEntityID != null) {
|
||||
final BlockHandler handler = MinecraftServer.getBlockManager().getHandlerOrDummy(tileEntityID);
|
||||
block = block.withHandler(handler);
|
||||
}
|
||||
// Remove anvil tags
|
||||
MutableNBTCompound mutableCopy = te.toMutableCompound();
|
||||
mutableCopy.remove("id");
|
||||
mutableCopy.remove("x");
|
||||
mutableCopy.remove("y");
|
||||
mutableCopy.remove("z");
|
||||
mutableCopy.remove("keepPacked");
|
||||
// Place block
|
||||
final var finalBlock = mutableCopy.getSize() > 0 ?
|
||||
block.withNbt(mutableCopy.toCompound()) : block;
|
||||
loadedChunk.setBlock(x, y, z, finalBlock);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// private @NotNull CompletableFuture<@Nullable Chunk> loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException, AnvilException {
|
||||
// final RegionFile mcaFile = getMCAFile(instance, chunkX, chunkZ);
|
||||
// if (mcaFile == null)
|
||||
// return CompletableFuture.completedFuture(null);
|
||||
// final NBTCompound chunkData = mcaFile.getChunkData(chunkX, chunkZ);
|
||||
// if (chunkData == null)
|
||||
// return CompletableFuture.completedFuture(null);
|
||||
//
|
||||
// final ChunkReader chunkReader = new ChunkReader(chunkData);
|
||||
//
|
||||
// Chunk chunk = instance.getChunkSupplier().createChunk(instance, chunkX, chunkZ);
|
||||
// synchronized (chunk) {
|
||||
// var yRange = chunkReader.getYRange();
|
||||
// if (yRange.getStart() < instance.getDimensionType().getMinY()) {
|
||||
// throw new AnvilException(
|
||||
// String.format("Trying to load chunk with minY = %d, but instance dimension type (%s) has a minY of %d",
|
||||
// yRange.getStart(),
|
||||
// instance.getDimensionType().getName().asString(),
|
||||
// instance.getDimensionType().getMinY()
|
||||
// ));
|
||||
// }
|
||||
// if (yRange.getEndInclusive() > instance.getDimensionType().getMaxY()) {
|
||||
// throw new AnvilException(
|
||||
// String.format("Trying to load chunk with maxY = %d, but instance dimension type (%s) has a maxY of %d",
|
||||
// yRange.getEndInclusive(),
|
||||
// instance.getDimensionType().getName().asString(),
|
||||
// instance.getDimensionType().getMaxY()
|
||||
// ));
|
||||
// }
|
||||
//
|
||||
// // TODO: Parallelize block, block entities and biome loading
|
||||
// // Blocks + Biomes
|
||||
// loadSections(chunk, chunkReader);
|
||||
//
|
||||
// // Block entities
|
||||
// loadBlockEntities(chunk, chunkReader);
|
||||
// }
|
||||
// synchronized (perRegionLoadedChunks) {
|
||||
// int regionX = CoordinatesKt.chunkToRegion(chunkX);
|
||||
// int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
|
||||
// var chunks = perRegionLoadedChunks.computeIfAbsent(new IntIntImmutablePair(regionX, regionZ), r -> new HashSet<>()); // region cache may have been removed on another thread due to unloadChunk
|
||||
// chunks.add(new IntIntImmutablePair(chunkX, chunkZ));
|
||||
// }
|
||||
// return CompletableFuture.completedFuture(chunk);
|
||||
// }
|
||||
//
|
||||
// private @Nullable RegionFile getMCAFile(Instance instance, int chunkX, int chunkZ) {
|
||||
// final int regionX = CoordinatesKt.chunkToRegion(chunkX);
|
||||
// final int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
|
||||
// return alreadyLoaded.computeIfAbsent(RegionFile.Companion.createFileName(regionX, regionZ), n -> {
|
||||
// try {
|
||||
// final Path regionPath = this.regionPath.resolve(n);
|
||||
// if (!Files.exists(regionPath)) {
|
||||
// return null;
|
||||
// }
|
||||
// synchronized (perRegionLoadedChunks) {
|
||||
// Set<IntIntImmutablePair> previousVersion = perRegionLoadedChunks.put(new IntIntImmutablePair(regionX, regionZ), new HashSet<>());
|
||||
// assert previousVersion == null : "The AnvilLoader cache should not already have data for this region.";
|
||||
// }
|
||||
// return new RegionFile(new RandomAccessFile(regionPath.toFile(), "rw"), regionX, regionZ, instance.getDimensionType().getMinY(), instance.getDimensionType().getMaxY() - 1);
|
||||
// } catch (IOException | AnvilException e) {
|
||||
// MinecraftServer.getExceptionManager().handleException(e);
|
||||
// return null;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// private void loadSections(Chunk chunk, ChunkReader chunkReader) {
|
||||
// final HashMap<String, Biome> biomeCache = new HashMap<>();
|
||||
// for (NBTCompound sectionNBT : chunkReader.getSections()) {
|
||||
// ChunkSectionReader sectionReader = new ChunkSectionReader(chunkReader.getMinecraftVersion(), sectionNBT);
|
||||
//
|
||||
// if (sectionReader.isSectionEmpty()) continue;
|
||||
// final int sectionY = sectionReader.getY();
|
||||
// final int yOffset = Chunk.CHUNK_SECTION_SIZE * sectionY;
|
||||
//
|
||||
// Section section = chunk.getSection(sectionY);
|
||||
//
|
||||
// if (sectionReader.getSkyLight() != null) {
|
||||
// section.setSkyLight(sectionReader.getSkyLight().copyArray());
|
||||
// }
|
||||
// if (sectionReader.getBlockLight() != null) {
|
||||
// section.setBlockLight(sectionReader.getBlockLight().copyArray());
|
||||
// }
|
||||
//
|
||||
// // Biomes
|
||||
// if (chunkReader.getGenerationStatus().compareTo(ChunkColumn.GenerationStatus.Biomes) > 0) {
|
||||
// SectionBiomeInformation sectionBiomeInformation = chunkReader.readSectionBiomes(sectionReader);
|
||||
//
|
||||
// if (sectionBiomeInformation != null && sectionBiomeInformation.hasBiomeInformation()) {
|
||||
// if (sectionBiomeInformation.isFilledWithSingleBiome()) {
|
||||
// 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 = chunk.chunkX * Chunk.CHUNK_SIZE_X + x;
|
||||
// int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z;
|
||||
// int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y;
|
||||
// String biomeName = sectionBiomeInformation.getBaseBiome();
|
||||
// Biome biome = biomeCache.computeIfAbsent(biomeName, n ->
|
||||
// Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS));
|
||||
// chunk.setBiome(finalX, finalY, finalZ, biome);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// 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 = chunk.chunkX * Chunk.CHUNK_SIZE_X + x;
|
||||
// int finalZ = chunk.chunkZ * Chunk.CHUNK_SIZE_Z + z;
|
||||
// int finalY = sectionY * Chunk.CHUNK_SECTION_SIZE + y;
|
||||
//
|
||||
// int index = x / 4 + (z / 4) * 4 + (y / 4) * 16;
|
||||
// String biomeName = sectionBiomeInformation.getBiomes()[index];
|
||||
// Biome biome = biomeCache.computeIfAbsent(biomeName, n ->
|
||||
// Objects.requireNonNullElse(MinecraftServer.getBiomeManager().getByName(NamespaceID.from(n)), PLAINS));
|
||||
// chunk.setBiome(finalX, finalY, finalZ, biome);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Blocks
|
||||
// final NBTList<NBTCompound> blockPalette = sectionReader.getBlockPalette();
|
||||
// if (blockPalette != null) {
|
||||
// final int[] blockStateIndices = sectionReader.getUncompressedBlockStateIDs();
|
||||
// Block[] convertedPalette = new Block[blockPalette.getSize()];
|
||||
// for (int i = 0; i < convertedPalette.length; i++) {
|
||||
// final NBTCompound paletteEntry = blockPalette.get(i);
|
||||
// String blockName = Objects.requireNonNull(paletteEntry.getString("Name"));
|
||||
// if (blockName.equals("minecraft:air")) {
|
||||
// convertedPalette[i] = Block.AIR;
|
||||
// } else {
|
||||
// if (blockName.equals("minecraft:grass")) {
|
||||
// blockName = "minecraft:short_grass";
|
||||
// }
|
||||
// Block block = Objects.requireNonNull(Block.fromNamespaceId(blockName));
|
||||
// // Properties
|
||||
// final Map<String, String> properties = new HashMap<>();
|
||||
// NBTCompound propertiesNBT = paletteEntry.getCompound("Properties");
|
||||
// if (propertiesNBT != null) {
|
||||
// for (var property : propertiesNBT) {
|
||||
// if (property.getValue().getID() != NBTType.TAG_String) {
|
||||
// LOGGER.warn("Fail to parse block state properties {}, expected a TAG_String for {}, but contents were {}",
|
||||
// propertiesNBT,
|
||||
// property.getKey(),
|
||||
// property.getValue().toSNBT());
|
||||
// } else {
|
||||
// properties.put(property.getKey(), ((NBTString) property.getValue()).getValue());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!properties.isEmpty()) block = block.withProperties(properties);
|
||||
// // Handler
|
||||
// final BlockHandler handler = MinecraftServer.getBlockManager().getHandler(block.name());
|
||||
// if (handler != null) block = block.withHandler(handler);
|
||||
//
|
||||
// convertedPalette[i] = block;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
|
||||
// for (int z = 0; z < Chunk.CHUNK_SECTION_SIZE; z++) {
|
||||
// for (int x = 0; x < Chunk.CHUNK_SECTION_SIZE; x++) {
|
||||
// try {
|
||||
// final int blockIndex = y * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SECTION_SIZE + z * Chunk.CHUNK_SECTION_SIZE + x;
|
||||
// final int paletteIndex = blockStateIndices[blockIndex];
|
||||
// final Block block = convertedPalette[paletteIndex];
|
||||
//
|
||||
// chunk.setBlock(x, y + yOffset, z, block);
|
||||
// } catch (Exception e) {
|
||||
// MinecraftServer.getExceptionManager().handleException(e);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void loadBlockEntities(Chunk loadedChunk, ChunkReader chunkReader) {
|
||||
// for (NBTCompound te : chunkReader.getBlockEntities()) {
|
||||
// final var x = te.getInt("x");
|
||||
// final var y = te.getInt("y");
|
||||
// final var z = te.getInt("z");
|
||||
// if (x == null || y == null || z == null) {
|
||||
// LOGGER.warn("Tile entity has failed to load due to invalid coordinate");
|
||||
// continue;
|
||||
// }
|
||||
// Block block = loadedChunk.getBlock(x, y, z);
|
||||
//
|
||||
// final String tileEntityID = te.getString("id");
|
||||
// if (tileEntityID != null) {
|
||||
// final BlockHandler handler = MinecraftServer.getBlockManager().getHandlerOrDummy(tileEntityID);
|
||||
// block = block.withHandler(handler);
|
||||
// }
|
||||
// // Remove anvil tags
|
||||
// MutableNBTCompound mutableCopy = te.toMutableCompound();
|
||||
// mutableCopy.remove("id");
|
||||
// mutableCopy.remove("x");
|
||||
// mutableCopy.remove("y");
|
||||
// mutableCopy.remove("z");
|
||||
// mutableCopy.remove("keepPacked");
|
||||
// // Place block
|
||||
// final var finalBlock = mutableCopy.getSize() > 0 ?
|
||||
// block.withNbt(mutableCopy.toCompound()) : block;
|
||||
// loadedChunk.setBlock(x, y, z, finalBlock);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
@Override
|
||||
public @NotNull CompletableFuture<Void> saveInstance(@NotNull Instance instance) {
|
||||
final NBTCompound nbt = instance.tagHandler().asCompound();
|
||||
if (nbt.isEmpty()) {
|
||||
// Instance has no data
|
||||
return AsyncUtils.VOID_FUTURE;
|
||||
}
|
||||
try (NBTWriter writer = new NBTWriter(Files.newOutputStream(levelPath))) {
|
||||
writer.writeNamed("", nbt);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// final NBTCompound nbt = instance.tagHandler().asCompound();
|
||||
// if (nbt.isEmpty()) {
|
||||
// // Instance has no data
|
||||
// return AsyncUtils.VOID_FUTURE;
|
||||
// }
|
||||
// try (NBTWriter writer = new NBTWriter(Files.newOutputStream(levelPath))) {
|
||||
// writer.writeNamed("", nbt);
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
return AsyncUtils.VOID_FUTURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<Void> saveChunk(@NotNull Chunk chunk) {
|
||||
final int chunkX = chunk.getChunkX();
|
||||
final int chunkZ = chunk.getChunkZ();
|
||||
RegionFile mcaFile;
|
||||
synchronized (alreadyLoaded) {
|
||||
mcaFile = getMCAFile(chunk.instance, chunkX, chunkZ);
|
||||
if (mcaFile == null) {
|
||||
final int regionX = CoordinatesKt.chunkToRegion(chunkX);
|
||||
final int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
|
||||
final String n = RegionFile.Companion.createFileName(regionX, regionZ);
|
||||
File regionFile = new File(regionPath.toFile(), n);
|
||||
try {
|
||||
if (!regionFile.exists()) {
|
||||
if (!regionFile.getParentFile().exists()) {
|
||||
regionFile.getParentFile().mkdirs();
|
||||
}
|
||||
regionFile.createNewFile();
|
||||
}
|
||||
mcaFile = new RegionFile(new RandomAccessFile(regionFile, "rw"), regionX, regionZ);
|
||||
alreadyLoaded.put(n, mcaFile);
|
||||
} catch (AnvilException | IOException e) {
|
||||
LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e);
|
||||
MinecraftServer.getExceptionManager().handleException(e);
|
||||
return AsyncUtils.VOID_FUTURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
ChunkWriter writer = new ChunkWriter(SupportedVersion.Companion.getLatest());
|
||||
save(chunk, writer);
|
||||
try {
|
||||
LOGGER.debug("Attempt saving at {} {}", chunk.getChunkX(), chunk.getChunkZ());
|
||||
mcaFile.writeColumnData(writer.toNBT(), chunk.getChunkX(), chunk.getChunkZ());
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e);
|
||||
MinecraftServer.getExceptionManager().handleException(e);
|
||||
return AsyncUtils.VOID_FUTURE;
|
||||
}
|
||||
// final int chunkX = chunk.getChunkX();
|
||||
// final int chunkZ = chunk.getChunkZ();
|
||||
// RegionFile mcaFile;
|
||||
// synchronized (alreadyLoaded) {
|
||||
// mcaFile = getMCAFile(chunk.instance, chunkX, chunkZ);
|
||||
// if (mcaFile == null) {
|
||||
// final int regionX = CoordinatesKt.chunkToRegion(chunkX);
|
||||
// final int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
|
||||
// final String n = RegionFile.Companion.createFileName(regionX, regionZ);
|
||||
// File regionFile = new File(regionPath.toFile(), n);
|
||||
// try {
|
||||
// if (!regionFile.exists()) {
|
||||
// if (!regionFile.getParentFile().exists()) {
|
||||
// regionFile.getParentFile().mkdirs();
|
||||
// }
|
||||
// regionFile.createNewFile();
|
||||
// }
|
||||
// mcaFile = new RegionFile(new RandomAccessFile(regionFile, "rw"), regionX, regionZ);
|
||||
// alreadyLoaded.put(n, mcaFile);
|
||||
// } catch (AnvilException | IOException e) {
|
||||
// LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e);
|
||||
// MinecraftServer.getExceptionManager().handleException(e);
|
||||
// return AsyncUtils.VOID_FUTURE;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ChunkWriter writer = new ChunkWriter(SupportedVersion.Companion.getLatest());
|
||||
// save(chunk, writer);
|
||||
// try {
|
||||
// LOGGER.debug("Attempt saving at {} {}", chunk.getChunkX(), chunk.getChunkZ());
|
||||
// mcaFile.writeColumnData(writer.toNBT(), chunk.getChunkX(), chunk.getChunkZ());
|
||||
// } catch (IOException e) {
|
||||
// LOGGER.error("Failed to save chunk " + chunkX + ", " + chunkZ, e);
|
||||
// MinecraftServer.getExceptionManager().handleException(e);
|
||||
// return AsyncUtils.VOID_FUTURE;
|
||||
// }
|
||||
return AsyncUtils.VOID_FUTURE;
|
||||
}
|
||||
|
||||
private BlockState getBlockState(final Block block) {
|
||||
return blockStateId2ObjectCacheTLS.get().computeIfAbsent(block.stateId(), _unused -> new BlockState(block.name(), block.properties()));
|
||||
}
|
||||
|
||||
private void save(Chunk chunk, ChunkWriter chunkWriter) {
|
||||
final int minY = chunk.getMinSection() * Chunk.CHUNK_SECTION_SIZE;
|
||||
final int maxY = chunk.getMaxSection() * Chunk.CHUNK_SECTION_SIZE - 1;
|
||||
chunkWriter.setYPos(minY);
|
||||
List<NBTCompound> blockEntities = new ArrayList<>();
|
||||
chunkWriter.setStatus(ChunkColumn.GenerationStatus.Full);
|
||||
|
||||
List<NBTCompound> sectionData = new ArrayList<>((maxY - minY + 1) / Chunk.CHUNK_SECTION_SIZE);
|
||||
int[] palettedBiomes = new int[ChunkSection.Companion.getBiomeArraySize()];
|
||||
int[] palettedBlockStates = new int[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SIZE_Z];
|
||||
for (int sectionY = chunk.getMinSection(); sectionY < chunk.getMaxSection(); sectionY++) {
|
||||
ChunkSectionWriter sectionWriter = new ChunkSectionWriter(SupportedVersion.Companion.getLatest(), (byte) sectionY);
|
||||
|
||||
Section section = chunk.getSection(sectionY);
|
||||
sectionWriter.setSkyLights(section.skyLight().array());
|
||||
sectionWriter.setBlockLights(section.blockLight().array());
|
||||
|
||||
BiomePalette biomePalette = new BiomePalette();
|
||||
BlockPalette blockPalette = new BlockPalette();
|
||||
for (int sectionLocalY = 0; sectionLocalY < Chunk.CHUNK_SECTION_SIZE; sectionLocalY++) {
|
||||
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
|
||||
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
|
||||
final int y = sectionLocalY + sectionY * Chunk.CHUNK_SECTION_SIZE;
|
||||
|
||||
final int blockIndex = x + sectionLocalY * 16 * 16 + z * 16;
|
||||
|
||||
final Block block = chunk.getBlock(x, y, z);
|
||||
|
||||
final BlockState hephaistosBlockState = getBlockState(block);
|
||||
blockPalette.increaseReference(hephaistosBlockState);
|
||||
|
||||
palettedBlockStates[blockIndex] = blockPalette.getPaletteIndex(hephaistosBlockState);
|
||||
|
||||
// biome are stored for 4x4x4 volumes, avoid unnecessary work
|
||||
if (x % 4 == 0 && sectionLocalY % 4 == 0 && z % 4 == 0) {
|
||||
int biomeIndex = (x / 4) + (sectionLocalY / 4) * 4 * 4 + (z / 4) * 4;
|
||||
final Biome biome = chunk.getBiome(x, y, z);
|
||||
final String biomeName = biome.name();
|
||||
|
||||
biomePalette.increaseReference(biomeName);
|
||||
palettedBiomes[biomeIndex] = biomePalette.getPaletteIndex(biomeName);
|
||||
}
|
||||
|
||||
// Block entities
|
||||
final BlockHandler handler = block.handler();
|
||||
final NBTCompound 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());
|
||||
}
|
||||
nbt.setInt("x", x + Chunk.CHUNK_SIZE_X * chunk.getChunkX());
|
||||
nbt.setInt("y", y);
|
||||
nbt.setInt("z", z + Chunk.CHUNK_SIZE_Z * chunk.getChunkZ());
|
||||
nbt.setByte("keepPacked", (byte) 0);
|
||||
blockEntities.add(nbt.toCompound());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sectionWriter.setPalettedBiomes(biomePalette, palettedBiomes);
|
||||
sectionWriter.setPalettedBlockStates(blockPalette, palettedBlockStates);
|
||||
|
||||
sectionData.add(sectionWriter.toNBT());
|
||||
}
|
||||
|
||||
chunkWriter.setSectionsData(NBT.List(NBTType.TAG_Compound, sectionData));
|
||||
chunkWriter.setBlockEntityData(NBT.List(NBTType.TAG_Compound, blockEntities));
|
||||
|
||||
// Save heightmaps
|
||||
chunkWriter.setMotionBlockingHeightMap(chunk.motionBlockingHeightmap().getNBT());
|
||||
chunkWriter.setWorldSurfaceHeightMap(chunk.worldSurfaceHeightmap().getNBT());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unload a given chunk. Also unloads a region when no chunk from that region is loaded.
|
||||
*
|
||||
* @param chunk the chunk to unload
|
||||
*/
|
||||
@Override
|
||||
public void unloadChunk(Chunk chunk) {
|
||||
final int regionX = CoordinatesKt.chunkToRegion(chunk.chunkX);
|
||||
final int regionZ = CoordinatesKt.chunkToRegion(chunk.chunkZ);
|
||||
|
||||
final IntIntImmutablePair regionKey = new IntIntImmutablePair(regionX, regionZ);
|
||||
synchronized (perRegionLoadedChunks) {
|
||||
Set<IntIntImmutablePair> chunks = perRegionLoadedChunks.get(regionKey);
|
||||
if (chunks != null) { // if null, trying to unload a chunk from a region that was not created by the AnvilLoader
|
||||
// don't check return value, trying to unload a chunk not created by the AnvilLoader is valid
|
||||
chunks.remove(new IntIntImmutablePair(chunk.chunkX, chunk.chunkZ));
|
||||
|
||||
if (chunks.isEmpty()) {
|
||||
perRegionLoadedChunks.remove(regionKey);
|
||||
RegionFile regionFile = alreadyLoaded.remove(RegionFile.Companion.createFileName(regionX, regionZ));
|
||||
if (regionFile != null) {
|
||||
try {
|
||||
regionFile.close();
|
||||
} catch (IOException e) {
|
||||
MinecraftServer.getExceptionManager().handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// private BlockState getBlockState(final Block block) {
|
||||
// return blockStateId2ObjectCacheTLS.get().computeIfAbsent(block.stateId(), _unused -> new BlockState(block.name(), block.properties()));
|
||||
// }
|
||||
//
|
||||
// private void save(Chunk chunk, ChunkWriter chunkWriter) {
|
||||
// final int minY = chunk.getMinSection() * Chunk.CHUNK_SECTION_SIZE;
|
||||
// final int maxY = chunk.getMaxSection() * Chunk.CHUNK_SECTION_SIZE - 1;
|
||||
// chunkWriter.setYPos(minY);
|
||||
// List<NBTCompound> blockEntities = new ArrayList<>();
|
||||
// chunkWriter.setStatus(ChunkColumn.GenerationStatus.Full);
|
||||
//
|
||||
// List<NBTCompound> sectionData = new ArrayList<>((maxY - minY + 1) / Chunk.CHUNK_SECTION_SIZE);
|
||||
// int[] palettedBiomes = new int[ChunkSection.Companion.getBiomeArraySize()];
|
||||
// int[] palettedBlockStates = new int[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SIZE_Z];
|
||||
// for (int sectionY = chunk.getMinSection(); sectionY < chunk.getMaxSection(); sectionY++) {
|
||||
// ChunkSectionWriter sectionWriter = new ChunkSectionWriter(SupportedVersion.Companion.getLatest(), (byte) sectionY);
|
||||
//
|
||||
// Section section = chunk.getSection(sectionY);
|
||||
// sectionWriter.setSkyLights(section.skyLight().array());
|
||||
// sectionWriter.setBlockLights(section.blockLight().array());
|
||||
//
|
||||
// BiomePalette biomePalette = new BiomePalette();
|
||||
// BlockPalette blockPalette = new BlockPalette();
|
||||
// for (int sectionLocalY = 0; sectionLocalY < Chunk.CHUNK_SECTION_SIZE; sectionLocalY++) {
|
||||
// for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
|
||||
// for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
|
||||
// final int y = sectionLocalY + sectionY * Chunk.CHUNK_SECTION_SIZE;
|
||||
//
|
||||
// final int blockIndex = x + sectionLocalY * 16 * 16 + z * 16;
|
||||
//
|
||||
// final Block block = chunk.getBlock(x, y, z);
|
||||
//
|
||||
// final BlockState hephaistosBlockState = getBlockState(block);
|
||||
// blockPalette.increaseReference(hephaistosBlockState);
|
||||
//
|
||||
// palettedBlockStates[blockIndex] = blockPalette.getPaletteIndex(hephaistosBlockState);
|
||||
//
|
||||
// // biome are stored for 4x4x4 volumes, avoid unnecessary work
|
||||
// if (x % 4 == 0 && sectionLocalY % 4 == 0 && z % 4 == 0) {
|
||||
// int biomeIndex = (x / 4) + (sectionLocalY / 4) * 4 * 4 + (z / 4) * 4;
|
||||
// final Biome biome = chunk.getBiome(x, y, z);
|
||||
// final String biomeName = biome.name();
|
||||
//
|
||||
// biomePalette.increaseReference(biomeName);
|
||||
// palettedBiomes[biomeIndex] = biomePalette.getPaletteIndex(biomeName);
|
||||
// }
|
||||
//
|
||||
// // Block entities
|
||||
// final BlockHandler handler = block.handler();
|
||||
// final NBTCompound 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());
|
||||
// }
|
||||
// nbt.setInt("x", x + Chunk.CHUNK_SIZE_X * chunk.getChunkX());
|
||||
// nbt.setInt("y", y);
|
||||
// nbt.setInt("z", z + Chunk.CHUNK_SIZE_Z * chunk.getChunkZ());
|
||||
// nbt.setByte("keepPacked", (byte) 0);
|
||||
// blockEntities.add(nbt.toCompound());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// sectionWriter.setPalettedBiomes(biomePalette, palettedBiomes);
|
||||
// sectionWriter.setPalettedBlockStates(blockPalette, palettedBlockStates);
|
||||
//
|
||||
// sectionData.add(sectionWriter.toNBT());
|
||||
// }
|
||||
//
|
||||
// chunkWriter.setSectionsData(NBT.List(NBTType.TAG_Compound, sectionData));
|
||||
// chunkWriter.setBlockEntityData(NBT.List(NBTType.TAG_Compound, blockEntities));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Unload a given chunk. Also unloads a region when no chunk from that region is loaded.
|
||||
// *
|
||||
// * @param chunk the chunk to unload
|
||||
// */
|
||||
// @Override
|
||||
// public void unloadChunk(Chunk chunk) {
|
||||
// final int regionX = CoordinatesKt.chunkToRegion(chunk.chunkX);
|
||||
// final int regionZ = CoordinatesKt.chunkToRegion(chunk.chunkZ);
|
||||
//
|
||||
// final IntIntImmutablePair regionKey = new IntIntImmutablePair(regionX, regionZ);
|
||||
// synchronized (perRegionLoadedChunks) {
|
||||
// Set<IntIntImmutablePair> chunks = perRegionLoadedChunks.get(regionKey);
|
||||
// if (chunks != null) { // if null, trying to unload a chunk from a region that was not created by the AnvilLoader
|
||||
// // don't check return value, trying to unload a chunk not created by the AnvilLoader is valid
|
||||
// chunks.remove(new IntIntImmutablePair(chunk.chunkX, chunk.chunkZ));
|
||||
//
|
||||
// if (chunks.isEmpty()) {
|
||||
// perRegionLoadedChunks.remove(regionKey);
|
||||
// RegionFile regionFile = alreadyLoaded.remove(RegionFile.Companion.createFileName(regionX, regionZ));
|
||||
// if (regionFile != null) {
|
||||
// try {
|
||||
// regionFile.close();
|
||||
// } catch (IOException e) {
|
||||
// MinecraftServer.getExceptionManager().handleException(e);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean supportsParallelLoading() {
|
||||
|
@ -2,6 +2,7 @@ package net.minestom.server.instance;
|
||||
|
||||
import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
@ -26,8 +27,6 @@ import net.minestom.server.world.biomes.Biome;
|
||||
import net.minestom.server.world.biomes.BiomeManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ExplosionSupplier {
|
||||
@ -12,9 +12,9 @@ public interface ExplosionSupplier {
|
||||
* @param centerY center Y of the explosion
|
||||
* @param centerZ center Z of the explosion
|
||||
* @param strength strength of the explosion
|
||||
* @param additionalData data passed via {@link Instance#explode(float, float, float, float, NBTCompound)} )}. Can be null
|
||||
* @param additionalData data passed via {@link Instance#explode(float, float, float, float, CompoundBinaryTag)} )}. Can be null
|
||||
* @return Explosion object representing the algorithm to use
|
||||
*/
|
||||
Explosion createExplosion(float centerX, float centerY, float centerZ, float strength, NBTCompound additionalData);
|
||||
Explosion createExplosion(float centerX, float centerY, float centerZ, float strength, CompoundBinaryTag additionalData);
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package net.minestom.server.instance;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.pointer.Pointers;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.ServerProcess;
|
||||
@ -45,7 +46,6 @@ import net.minestom.server.world.DimensionType;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
@ -792,7 +792,7 @@ public abstract class Instance implements Block.Getter, Block.Setter,
|
||||
* @param additionalData data to pass to the explosion supplier
|
||||
* @throws IllegalStateException If no {@link ExplosionSupplier} was supplied
|
||||
*/
|
||||
public void explode(float centerX, float centerY, float centerZ, float strength, @Nullable NBTCompound additionalData) {
|
||||
public void explode(float centerX, float centerY, float centerZ, float strength, @Nullable CompoundBinaryTag additionalData) {
|
||||
final ExplosionSupplier explosionSupplier = getExplosionSupplier();
|
||||
Check.stateCondition(explosionSupplier == null, "Tried to create an explosion with no explosion supplier");
|
||||
final Explosion explosion = explosionSupplier.createExplosion(centerX, centerY, centerZ, strength, additionalData);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.coordinate.BlockVec;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
@ -33,7 +34,6 @@ import net.minestom.server.world.DimensionType;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import space.vectrix.flare.fastutil.Long2ObjectSyncMap;
|
||||
@ -187,7 +187,7 @@ public class InstanceContainer extends Instance {
|
||||
chunk.sendPacketToViewers(new BlockChangePacket(blockPosition, block.stateId()));
|
||||
var registry = block.registry();
|
||||
if (registry.isBlockEntity()) {
|
||||
final NBTCompound data = BlockUtils.extractClientNbt(block);
|
||||
final CompoundBinaryTag data = BlockUtils.extractClientNbt(block);
|
||||
chunk.sendPacketToViewers(new BlockEntityDataPacket(blockPosition, registry.blockEntityId(), data));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package net.minestom.server.instance;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.LongArrayBinaryTag;
|
||||
import net.minestom.server.ServerFlag;
|
||||
import net.minestom.server.collision.Shape;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
|
@ -1,15 +1,15 @@
|
||||
package net.minestom.server.instance.block;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.batch.Batch;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.*;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@ -67,7 +67,7 @@ public sealed interface Block extends StaticProtocolObject, TagReadable, Blocks
|
||||
* @return a new block with different nbt
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
@NotNull Block withNbt(@Nullable NBTCompound compound);
|
||||
@NotNull Block withNbt(@Nullable CompoundBinaryTag compound);
|
||||
|
||||
/**
|
||||
* Creates a new block with the specified {@link BlockHandler handler}.
|
||||
@ -86,7 +86,7 @@ public sealed interface Block extends StaticProtocolObject, TagReadable, Blocks
|
||||
* @return the block nbt, null if not present
|
||||
*/
|
||||
@Contract(pure = true)
|
||||
@Nullable NBTCompound nbt();
|
||||
@Nullable CompoundBinaryTag nbt();
|
||||
|
||||
@Contract(pure = true)
|
||||
default boolean hasNbt() {
|
||||
|
@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.utils.ArrayUtils;
|
||||
@ -14,8 +15,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
@ -23,7 +22,7 @@ import java.util.function.Function;
|
||||
|
||||
record BlockImpl(@NotNull Registry.BlockEntry registry,
|
||||
byte @NotNull [] propertiesArray,
|
||||
@Nullable NBTCompound nbt,
|
||||
@Nullable CompoundBinaryTag nbt,
|
||||
@Nullable BlockHandler handler) implements Block {
|
||||
// Block state -> block object
|
||||
private static final ObjectArray<Block> BLOCK_STATE_MAP = ObjectArray.singleThread();
|
||||
@ -86,7 +85,7 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
|
||||
final int defaultState = properties.getInt("defaultStateId");
|
||||
return getState(defaultState);
|
||||
});
|
||||
private static final Cache<NBTCompound, NBTCompound> NBT_CACHE = Caffeine.newBuilder()
|
||||
private static final Cache<CompoundBinaryTag, CompoundBinaryTag> NBT_CACHE = Caffeine.newBuilder()
|
||||
.expireAfterWrite(Duration.ofMinutes(5))
|
||||
.weakValues()
|
||||
.build();
|
||||
@ -144,14 +143,16 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
|
||||
|
||||
@Override
|
||||
public @NotNull <T> Block withTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||
var temporaryNbt = new MutableNBTCompound(Objects.requireNonNullElse(nbt, NBTCompound.EMPTY));
|
||||
tag.write(temporaryNbt, value);
|
||||
final var finalNbt = temporaryNbt.getSize() > 0 ? NBT_CACHE.get(temporaryNbt.toCompound(), Function.identity()) : null;
|
||||
var builder = CompoundBinaryTag.builder();
|
||||
if (nbt != null) builder.put(nbt);
|
||||
tag.write(builder, value);
|
||||
var temporaryNbt = builder.build();
|
||||
final var finalNbt = temporaryNbt.size() > 0 ? NBT_CACHE.get(temporaryNbt, Function.identity()) : null;
|
||||
return new BlockImpl(registry, propertiesArray, finalNbt, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Block withNbt(@Nullable NBTCompound compound) {
|
||||
public @NotNull Block withNbt(@Nullable CompoundBinaryTag compound) {
|
||||
return new BlockImpl(registry, propertiesArray, compound, handler);
|
||||
}
|
||||
|
||||
@ -183,7 +184,7 @@ record BlockImpl(@NotNull Registry.BlockEntry registry,
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
|
||||
return tag.read(Objects.requireNonNullElse(nbt, NBTCompound.EMPTY));
|
||||
return tag.read(Objects.requireNonNullElse(nbt, CompoundBinaryTag.empty()));
|
||||
}
|
||||
|
||||
private Map<PropertiesHolder, BlockImpl> possibleProperties() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.item.attribute.ItemAttribute;
|
||||
@ -12,7 +13,6 @@ import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
@ -26,7 +26,7 @@ public sealed interface ItemMeta extends TagReadable, NetworkBuffer.Writer
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
@NotNull ItemMeta with(@NotNull Consumer<@NotNull Builder> builderConsumer);
|
||||
|
||||
@NotNull NBTCompound toNBT();
|
||||
@NotNull CompoundBinaryTag toNBT();
|
||||
|
||||
@NotNull String toSNBT();
|
||||
|
||||
|
@ -1,16 +1,17 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.tag.TagHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.BYTE;
|
||||
import static net.minestom.server.network.NetworkBuffer.NBT;
|
||||
|
||||
record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta {
|
||||
@ -29,23 +30,22 @@ record ItemMetaImpl(TagHandler tagHandler) implements ItemMeta {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull NBTCompound toNBT() {
|
||||
public @NotNull CompoundBinaryTag toNBT() {
|
||||
return tagHandler.asCompound();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String toSNBT() {
|
||||
return toNBT().toSNBT();
|
||||
try {
|
||||
return TagStringIO.get().asString(toNBT());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to convert to SNBT", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
final NBTCompound nbt = toNBT();
|
||||
if (nbt.isEmpty()) {
|
||||
writer.write(BYTE, (byte) 0);
|
||||
return;
|
||||
}
|
||||
writer.write(NBT, nbt);
|
||||
writer.write(NBT, toNBT());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.api.BinaryTagHolder;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
@ -11,8 +12,8 @@ import net.minestom.server.tag.TagReadable;
|
||||
import net.minestom.server.tag.TagWritable;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.*;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntUnaryOperator;
|
||||
@ -47,13 +48,13 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
}
|
||||
|
||||
@Contract(value = "_, _, _ -> new", pure = true)
|
||||
static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable NBTCompound nbtCompound, int amount) {
|
||||
static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable CompoundBinaryTag nbtCompound, int amount) {
|
||||
if (nbtCompound == null) return of(material, amount);
|
||||
return builder(material).amount(amount).meta(nbtCompound).build();
|
||||
}
|
||||
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable NBTCompound nbtCompound) {
|
||||
static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable CompoundBinaryTag nbtCompound) {
|
||||
return fromNBT(material, nbtCompound, 1);
|
||||
}
|
||||
|
||||
@ -63,7 +64,7 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
* @param nbtCompound The nbt representation of the item
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
static @NotNull ItemStack fromItemNBT(@NotNull NBTCompound nbtCompound) {
|
||||
static @NotNull ItemStack fromItemNBT(@NotNull CompoundBinaryTag nbtCompound) {
|
||||
String id = nbtCompound.getString("id");
|
||||
Check.notNull(id, "Item NBT must contain an id field.");
|
||||
Material material = Material.fromNamespaceId(id);
|
||||
@ -71,7 +72,7 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
|
||||
Byte amount = nbtCompound.getByte("Count");
|
||||
if (amount == null) amount = 1;
|
||||
final NBTCompound tag = nbtCompound.getCompound("tag");
|
||||
final CompoundBinaryTag tag = nbtCompound.getCompound("tag");
|
||||
return tag != null ? fromNBT(material, tag, amount) : of(material, amount);
|
||||
}
|
||||
|
||||
@ -168,8 +169,13 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
|
||||
@Override
|
||||
default @NotNull HoverEvent<HoverEvent.ShowItem> asHoverEvent(@NotNull UnaryOperator<HoverEvent.ShowItem> op) {
|
||||
final BinaryTagHolder tagHolder = BinaryTagHolder.encode(meta().toNBT(), MinestomAdventure.NBT_CODEC);
|
||||
return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.showItem(material(), amount(), tagHolder)));
|
||||
try {
|
||||
final BinaryTagHolder tagHolder = BinaryTagHolder.encode(meta().toNBT(), MinestomAdventure.NBT_CODEC);
|
||||
return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.showItem(material(), amount(), tagHolder)));
|
||||
} catch (IOException e) {
|
||||
//todo(matt): revisit,
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,7 +184,7 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
* @return The nbt representation of the item
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@NotNull NBTCompound toItemNBT();
|
||||
@NotNull CompoundBinaryTag toItemNBT();
|
||||
|
||||
|
||||
@Deprecated
|
||||
@ -208,7 +214,7 @@ public sealed interface ItemStack extends TagReadable, HoverEventSource<HoverEve
|
||||
@NotNull Builder meta(@NotNull TagHandler tagHandler);
|
||||
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull NBTCompound compound);
|
||||
@NotNull Builder meta(@NotNull CompoundBinaryTag compound);
|
||||
|
||||
@Contract(value = "_ -> this")
|
||||
@NotNull Builder meta(@NotNull ItemMeta itemMeta);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.ServerFlag;
|
||||
import net.minestom.server.item.rule.VanillaStackingRule;
|
||||
import net.minestom.server.tag.Tag;
|
||||
@ -7,12 +8,7 @@ import net.minestom.server.tag.TagHandler;
|
||||
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.NBTByte;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTString;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implements ItemStack {
|
||||
@ -89,12 +85,13 @@ record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull NBTCompound toItemNBT() {
|
||||
final NBTString material = NBT.String(material().name());
|
||||
final NBTByte amount = NBT.Byte(amount());
|
||||
final NBTCompound nbt = meta().toNBT();
|
||||
if (nbt.isEmpty()) return NBT.Compound(Map.of("id", material, "Count", amount));
|
||||
return NBT.Compound(Map.of("id", material, "Count", amount, "tag", nbt));
|
||||
public @NotNull CompoundBinaryTag toItemNBT() {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
|
||||
.putString("id", material.name())
|
||||
.putByte("Count", (byte) amount);
|
||||
CompoundBinaryTag nbt = meta.toNBT();
|
||||
if (nbt.size() > 0) builder.put("tag", nbt);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Contract(value = "-> new", pure = true)
|
||||
@ -129,7 +126,7 @@ record ItemStackImpl(Material material, int amount, ItemMetaImpl meta) implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack.@NotNull Builder meta(@NotNull NBTCompound compound) {
|
||||
public ItemStack.@NotNull Builder meta(@NotNull CompoundBinaryTag compound) {
|
||||
return metaBuilder(new ItemMetaImpl.Builder(TagHandler.fromCompound(compound)));
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,19 @@
|
||||
package net.minestom.server.item.armor;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.minestom.server.item.Material;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class TrimManager {
|
||||
private final Set<TrimMaterial> trimMaterials;
|
||||
private final Set<TrimPattern> trimPatterns;
|
||||
private NBTCompound trimMaterialCache = null;
|
||||
private NBTCompound trimPatternCache = null;
|
||||
private CompoundBinaryTag trimMaterialCache = null;
|
||||
private CompoundBinaryTag trimPatternCache = null;
|
||||
|
||||
public TrimManager() {
|
||||
this.trimMaterials = new HashSet<>();
|
||||
@ -30,38 +29,28 @@ public class TrimManager {
|
||||
}
|
||||
|
||||
|
||||
public NBTCompound getTrimMaterialNBT() {
|
||||
public CompoundBinaryTag getTrimMaterialNBT() {
|
||||
if (trimMaterialCache == null) {
|
||||
var trimMaterials = this.trimMaterials.stream()
|
||||
.map((trimMaterial) -> NBT.Compound(Map.of(
|
||||
"id", NBT.Int(trimMaterial.id()),
|
||||
"name", NBT.String(trimMaterial.name()),
|
||||
"element", trimMaterial.asNBT()
|
||||
)))
|
||||
.toList();
|
||||
|
||||
trimMaterialCache = NBT.Compound(Map.of(
|
||||
"type", NBT.String("minecraft:trim_material"),
|
||||
"value", NBT.List(NBTType.TAG_Compound, trimMaterials)
|
||||
));
|
||||
ListBinaryTag.Builder<CompoundBinaryTag> entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
|
||||
for (TrimMaterial trimMaterial : this.trimMaterials)
|
||||
entries.add(trimMaterial.asNBT());
|
||||
trimMaterialCache = CompoundBinaryTag.builder()
|
||||
.putString("type", "minecraft:trim_material")
|
||||
.put("value", entries.build())
|
||||
.build();
|
||||
}
|
||||
return trimMaterialCache;
|
||||
}
|
||||
|
||||
public NBTCompound getTrimPatternNBT() {
|
||||
public CompoundBinaryTag getTrimPatternNBT() {
|
||||
if (trimPatternCache == null) {
|
||||
var trimPatterns = this.trimPatterns.stream()
|
||||
.map((trimPattern) -> NBT.Compound(Map.of(
|
||||
"id", NBT.Int(trimPattern.id()),
|
||||
"name", NBT.String(trimPattern.name()),
|
||||
"element", trimPattern.asNBT()
|
||||
)))
|
||||
.toList();
|
||||
|
||||
trimPatternCache = NBT.Compound(Map.of(
|
||||
"type", NBT.String("minecraft:trim_pattern"),
|
||||
"value", NBT.List(NBTType.TAG_Compound, trimPatterns)
|
||||
));
|
||||
ListBinaryTag.Builder<CompoundBinaryTag> entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
|
||||
for (TrimPattern trimPattern : this.trimPatterns)
|
||||
entries.add(trimPattern.asNBT());
|
||||
trimPatternCache = CompoundBinaryTag.builder()
|
||||
.putString("type", "minecraft:trim_pattern")
|
||||
.put("value", entries.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
return trimPatternCache;
|
||||
|
@ -1,13 +1,13 @@
|
||||
package net.minestom.server.item.armor;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@ -84,6 +84,6 @@ public interface TrimMaterial extends StaticProtocolObject {
|
||||
return registry().description();
|
||||
}
|
||||
|
||||
NBTCompound asNBT();
|
||||
CompoundBinaryTag asNBT();
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.minestom.server.item.armor;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.StringBinaryTag;
|
||||
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@ -31,19 +31,15 @@ record TrimMaterialImpl(Registry.TrimMaterialEntry registry, int id) implements
|
||||
return CONTAINER.values();
|
||||
}
|
||||
|
||||
public NBTCompound asNBT() {
|
||||
return NBT.Compound(nbt -> {
|
||||
nbt.setString("asset_name", assetName());
|
||||
nbt.setString("ingredient", ingredient().namespace().asString());
|
||||
nbt.setFloat("item_model_index", itemModelIndex());
|
||||
nbt.set("override_armor_materials", NBT.Compound(overrideArmorMaterials().entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
entry -> NBT.String(entry.getValue())
|
||||
))
|
||||
));
|
||||
nbt.set("description", NbtComponentSerializer.nbt().serialize(description()));
|
||||
});
|
||||
public CompoundBinaryTag asNBT() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("asset_name", assetName())
|
||||
.putString("ingredient", ingredient().namespace().asString())
|
||||
.putFloat("item_model_index", itemModelIndex())
|
||||
.put("override_armor_materials", CompoundBinaryTag.from(overrideArmorMaterials().entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, entry -> StringBinaryTag.stringBinaryTag(entry.getValue())))))
|
||||
.put("description", NbtComponentSerializer.nbt().serialize(description()))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package net.minestom.server.item.armor;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import net.minestom.server.registry.StaticProtocolObject;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@ -61,6 +61,6 @@ public interface TrimPattern extends StaticProtocolObject {
|
||||
return registry().decal();
|
||||
}
|
||||
|
||||
NBTCompound asNBT();
|
||||
CompoundBinaryTag asNBT();
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
package net.minestom.server.item.armor;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.adventure.serializer.nbt.NbtComponentSerializer;
|
||||
import net.minestom.server.registry.Registry;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -29,13 +28,13 @@ record TrimPatternImpl(Registry.TrimPatternEntry registry, int id) implements Tr
|
||||
return CONTAINER.values();
|
||||
}
|
||||
|
||||
public NBTCompound asNBT() {
|
||||
return NBT.Compound(nbt -> {
|
||||
nbt.setString("asset_id", assetID().asString());
|
||||
nbt.setString("template_item", template().namespace().asString());
|
||||
nbt.set("description", NbtComponentSerializer.nbt().serialize(description()));
|
||||
nbt.setByte("decal", (byte) (decal() ? 1 : 0));
|
||||
});
|
||||
public CompoundBinaryTag asNBT() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("asset_id", assetID().asString())
|
||||
.putString("template_item", template().namespace().asString())
|
||||
.put("description", NbtComponentSerializer.nbt().serialize(description()))
|
||||
.putBoolean("decal", decal())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
package net.minestom.server.item.firework;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.color.Color;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTIntArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public record FireworkEffect(boolean flicker, boolean trail,
|
||||
@NotNull FireworkEffectType type,
|
||||
@ -25,36 +22,34 @@ public record FireworkEffect(boolean flicker, boolean trail,
|
||||
* @param compound The NBT connection, which should be a fireworks effect.
|
||||
* @return A new created firework effect.
|
||||
*/
|
||||
public static @NotNull FireworkEffect fromCompound(@NotNull NBTCompound compound) {
|
||||
public static @NotNull FireworkEffect fromCompound(@NotNull CompoundBinaryTag compound) {
|
||||
List<Color> primaryColor = new ArrayList<>();
|
||||
List<Color> secondaryColor = new ArrayList<>();
|
||||
|
||||
if (compound.get("Colors") instanceof NBTIntArray colors) {
|
||||
for (int rgb : colors) primaryColor.add(new Color(rgb));
|
||||
}
|
||||
if (compound.get("FadeColors") instanceof NBTIntArray fadeColors) {
|
||||
for (int rgb : fadeColors) secondaryColor.add(new Color(rgb));
|
||||
}
|
||||
for (int rgb : compound.getIntArray("Colors"))
|
||||
primaryColor.add(new Color(rgb));
|
||||
for (int rgb : compound.getIntArray("FadeColors"))
|
||||
secondaryColor.add(new Color(rgb));
|
||||
|
||||
boolean flicker = compound.containsKey("Flicker") && compound.getBoolean("Flicker");
|
||||
boolean trail = compound.containsKey("Trail") && compound.getBoolean("Trail");
|
||||
FireworkEffectType type = compound.containsKey("Type") ?
|
||||
FireworkEffectType.byId(compound.getAsByte("Type")) : FireworkEffectType.SMALL_BALL;
|
||||
boolean flicker = compound.getBoolean("Flicker");
|
||||
boolean trail = compound.getBoolean("Trail");
|
||||
FireworkEffectType type = FireworkEffectType.byId(compound.getByte("Type"));
|
||||
|
||||
return new FireworkEffect(flicker, trail, type, primaryColor, secondaryColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the {@link FireworkEffect} as a {@link NBTCompound}.
|
||||
* Retrieves the {@link FireworkEffect} as a {@link CompoundBinaryTag}.
|
||||
*
|
||||
* @return The firework effect as a nbt compound.
|
||||
*/
|
||||
public @NotNull NBTCompound asCompound() {
|
||||
return NBT.Compound(Map.of(
|
||||
"Flicker", NBT.Boolean(flicker),
|
||||
"Trail", NBT.Boolean(trail),
|
||||
"Type", NBT.Byte(type.getType()),
|
||||
"Colors", NBT.IntArray(colors.stream().mapToInt(Color::asRGB).toArray()),
|
||||
"FadeColors", NBT.IntArray(fadeColors.stream().mapToInt(Color::asRGB).toArray())));
|
||||
public @NotNull CompoundBinaryTag asCompound() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putBoolean("Flicker", flicker)
|
||||
.putBoolean("Trail", trail)
|
||||
.putByte("Type", (byte) type.getType())
|
||||
.putIntArray("Colors", colors.stream().mapToInt(Color::asRGB).toArray())
|
||||
.putIntArray("FadeColors", fadeColors.stream().mapToInt(Color::asRGB).toArray())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,30 @@
|
||||
package net.minestom.server.item.metadata;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.minestom.server.entity.PlayerSkin;
|
||||
import net.minestom.server.item.ItemMetaView;
|
||||
import net.minestom.server.tag.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTList;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView<PlayerHeadMeta.Builder> {
|
||||
public static final Tag<UUID> SKULL_OWNER = Tag.UUID("Id").path("SkullOwner");
|
||||
public static final Tag<PlayerSkin> SKIN = Tag.Structure("Properties", new TagSerializer<PlayerSkin>() {
|
||||
private static final Tag<NBT> TEXTURES = Tag.NBT("textures");
|
||||
private static final Tag<BinaryTag> TEXTURES = Tag.NBT("textures");
|
||||
|
||||
@Override
|
||||
public @Nullable PlayerSkin read(@NotNull TagReadable reader) {
|
||||
final NBT result = reader.getTag(TEXTURES);
|
||||
if (!(result instanceof NBTList)) return null;
|
||||
final NBTList<NBTCompound> textures = (NBTList<NBTCompound>) result;
|
||||
final NBTCompound texture = textures.get(0);
|
||||
final BinaryTag result = reader.getTag(TEXTURES);
|
||||
if (!(result instanceof ListBinaryTag textures)) return null;
|
||||
final CompoundBinaryTag texture = textures.getCompound(0);
|
||||
final String value = texture.getString("Value");
|
||||
final String signature = texture.getString("Signature");
|
||||
return new PlayerSkin(value, signature);
|
||||
@ -36,9 +34,9 @@ public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView<Playe
|
||||
public void write(@NotNull TagWritable writer, @NotNull PlayerSkin playerSkin) {
|
||||
final String value = Objects.requireNonNullElse(playerSkin.textures(), "");
|
||||
final String signature = Objects.requireNonNullElse(playerSkin.signature(), "");
|
||||
NBTList<NBTCompound> textures = new NBTList<>(NBTType.TAG_Compound,
|
||||
List.of(NBT.Compound(Map.of("Value", NBT.String(value), "Signature", NBT.String(signature)))));
|
||||
writer.setTag(TEXTURES, textures);
|
||||
writer.setTag(TEXTURES, ListBinaryTag.listBinaryTag(BinaryTagTypes.COMPOUND, List.of(
|
||||
CompoundBinaryTag.builder().putString("Value", value).putString("Signature", signature).build()
|
||||
)));
|
||||
}
|
||||
}).path("SkullOwner");
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.listener;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.coordinate.BlockVec;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
@ -23,7 +24,6 @@ import net.minestom.server.network.packet.server.play.AcknowledgeBlockChangePack
|
||||
import net.minestom.server.network.packet.server.play.BlockEntityDataPacket;
|
||||
import net.minestom.server.utils.block.BlockUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
public final class PlayerDiggingListener {
|
||||
|
||||
@ -59,7 +59,7 @@ public final class PlayerDiggingListener {
|
||||
// Refresh block on player screen in case it had special data (like a sign)
|
||||
var registry = diggingResult.block().registry();
|
||||
if (registry.isBlockEntity()) {
|
||||
final NBTCompound data = BlockUtils.extractClientNbt(diggingResult.block());
|
||||
final CompoundBinaryTag data = BlockUtils.extractClientNbt(diggingResult.block());
|
||||
player.sendPacketToViewersAndSelf(new BlockEntityDataPacket(blockPosition, registry.blockEntityId(), data));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package net.minestom.server.message;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.TagStringIO;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.entity.Player;
|
||||
@ -7,11 +9,8 @@ import net.minestom.server.network.packet.server.play.SystemChatPacket;
|
||||
import net.minestom.server.utils.PacketUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTException;
|
||||
import org.jglrxavpok.hephaistos.parser.SNBTParser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
@ -27,11 +26,11 @@ public final class Messenger {
|
||||
private static final UUID NO_SENDER = new UUID(0, 0);
|
||||
private static final SystemChatPacket CANNOT_SEND_PACKET = new SystemChatPacket(CANNOT_SEND_MESSAGE, false);
|
||||
|
||||
private static final NBTCompound CHAT_REGISTRY;
|
||||
private static final CompoundBinaryTag CHAT_REGISTRY;
|
||||
|
||||
static {
|
||||
try {
|
||||
CHAT_REGISTRY = (NBTCompound) new SNBTParser(new StringReader(
|
||||
CHAT_REGISTRY = TagStringIO.get().asCompound(
|
||||
"""
|
||||
{
|
||||
"type": "minecraft:chat_type",
|
||||
@ -57,13 +56,13 @@ public final class Messenger {
|
||||
}
|
||||
} ]
|
||||
}"""
|
||||
)).parse();
|
||||
} catch (NBTException e) {
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull NBTCompound chatRegistry() {
|
||||
public static @NotNull CompoundBinaryTag chatRegistry() {
|
||||
return CHAT_REGISTRY;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.network;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
@ -32,7 +33,8 @@ import org.jctools.queues.MpscUnboundedArrayQueue;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@ -280,14 +282,15 @@ public final class ConnectionManager {
|
||||
|
||||
// Registry data (if it should be sent)
|
||||
if (event.willSendRegistryData()) {
|
||||
var registry = new HashMap<String, NBT>();
|
||||
registry.put("minecraft:chat_type", Messenger.chatRegistry());
|
||||
registry.put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT());
|
||||
registry.put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT());
|
||||
registry.put("minecraft:damage_type", DamageType.getNBT());
|
||||
registry.put("minecraft:trim_material", MinecraftServer.getTrimManager().getTrimMaterialNBT());
|
||||
registry.put("minecraft:trim_pattern", MinecraftServer.getTrimManager().getTrimPatternNBT());
|
||||
player.sendPacket(new RegistryDataPacket(NBT.Compound(registry)));
|
||||
var registryCompound = CompoundBinaryTag.builder()
|
||||
.put("minecraft:chat_type", Messenger.chatRegistry())
|
||||
.put("minecraft:dimension_type", MinecraftServer.getDimensionTypeManager().toNBT())
|
||||
.put("minecraft:worldgen/biome", MinecraftServer.getBiomeManager().toNBT())
|
||||
.put("minecraft:damage_type", DamageType.getNBT())
|
||||
// .put("minecraft:trim_material", MinecraftServer.getTrimManager().getTrimMaterialNBT())
|
||||
// .put("minecraft:trim_pattern", MinecraftServer.getTrimManager().getTrimPatternNBT())
|
||||
.build();
|
||||
player.sendPacket(new RegistryDataPacket(registryCompound));
|
||||
|
||||
player.sendPacket(TagsPacket.DEFAULT_TAGS);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.network;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.entity.Entity;
|
||||
@ -15,10 +16,9 @@ import net.minestom.server.utils.validate.Check;
|
||||
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.NBTReader;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTWriter;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.*;
|
||||
@ -40,7 +40,7 @@ public final class NetworkBuffer {
|
||||
public static final Type<Long> VAR_LONG = new NetworkBufferTypeImpl.VarLongType();
|
||||
public static final Type<byte[]> RAW_BYTES = new NetworkBufferTypeImpl.RawBytesType();
|
||||
public static final Type<String> STRING = new NetworkBufferTypeImpl.StringType();
|
||||
public static final Type<NBT> NBT = new NetworkBufferTypeImpl.NbtType();
|
||||
public static final Type<BinaryTag> NBT = new NetworkBufferTypeImpl.NbtType();
|
||||
public static final Type<Point> BLOCK_POSITION = new NetworkBufferTypeImpl.BlockPositionType();
|
||||
public static final Type<Component> COMPONENT = new NetworkBufferTypeImpl.ComponentType();
|
||||
public static final Type<Component> JSON_COMPONENT = new NetworkBufferTypeImpl.JsonComponentType();
|
||||
@ -79,8 +79,8 @@ public final class NetworkBuffer {
|
||||
int writeIndex;
|
||||
int readIndex;
|
||||
|
||||
NBTWriter nbtWriter;
|
||||
NBTReader nbtReader;
|
||||
DataOutput nbtWriter;
|
||||
DataInput nbtReader;
|
||||
|
||||
public NetworkBuffer(@NotNull ByteBuffer buffer, boolean resizable) {
|
||||
this.nioBuffer = buffer.order(ByteOrder.BIG_ENDIAN);
|
||||
|
@ -1,16 +1,16 @@
|
||||
package net.minestom.server.network.packet.server.configuration;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.NBT;
|
||||
|
||||
public record RegistryDataPacket(@NotNull NBTCompound data) implements ServerPacket.Configuration {
|
||||
public record RegistryDataPacket(@NotNull CompoundBinaryTag data) implements ServerPacket.Configuration {
|
||||
public RegistryDataPacket(@NotNull NetworkBuffer buffer) {
|
||||
this((NBTCompound) buffer.read(NBT));
|
||||
this((CompoundBinaryTag) buffer.read(NBT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,19 +1,19 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record BlockEntityDataPacket(@NotNull Point blockPosition, int action,
|
||||
@Nullable NBTCompound data) implements ServerPacket.Play {
|
||||
@Nullable CompoundBinaryTag data) implements ServerPacket.Play {
|
||||
public BlockEntityDataPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(BLOCK_POSITION), reader.read(VAR_INT), (NBTCompound) reader.read(NBT));
|
||||
this(reader.read(BLOCK_POSITION), reader.read(VAR_INT), (CompoundBinaryTag) reader.read(NBT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,20 +1,20 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.potion.Potion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record EntityEffectPacket(int entityId, @NotNull Potion potion,
|
||||
@Nullable NBTCompound factorCodec) implements ServerPacket.Play {
|
||||
@Nullable CompoundBinaryTag factorCodec) implements ServerPacket.Play {
|
||||
public EntityEffectPacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(VAR_INT), new Potion(reader),
|
||||
reader.read(BOOLEAN) ? (NBTCompound) reader.read(NBT) : null);
|
||||
reader.read(BOOLEAN) ? (CompoundBinaryTag) reader.read(NBT) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,16 +1,17 @@
|
||||
package net.minestom.server.network.packet.server.play;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record NbtQueryResponsePacket(int transactionId, NBTCompound data) implements ServerPacket.Play {
|
||||
public record NbtQueryResponsePacket(int transactionId, CompoundBinaryTag data) implements ServerPacket.Play {
|
||||
public NbtQueryResponsePacket(@NotNull NetworkBuffer reader) {
|
||||
this(reader.read(VAR_INT), (NBTCompound) reader.read(NBT));
|
||||
this(reader.read(VAR_INT), (CompoundBinaryTag) reader.read(NBT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,12 +1,12 @@
|
||||
package net.minestom.server.network.packet.server.play.data;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.block.BlockUtils;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -14,7 +14,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static net.minestom.server.network.NetworkBuffer.*;
|
||||
|
||||
public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data,
|
||||
public record ChunkData(@NotNull CompoundBinaryTag heightmaps, byte @NotNull [] data,
|
||||
@NotNull Map<Integer, Block> blockEntities) implements NetworkBuffer.Writer {
|
||||
public ChunkData {
|
||||
blockEntities = blockEntities.entrySet()
|
||||
@ -24,7 +24,7 @@ public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data,
|
||||
}
|
||||
|
||||
public ChunkData(@NotNull NetworkBuffer reader) {
|
||||
this((NBTCompound) reader.read(NBT), reader.read(BYTE_ARRAY),
|
||||
this((CompoundBinaryTag) reader.read(NBT), reader.read(BYTE_ARRAY),
|
||||
readBlockEntities(reader));
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data,
|
||||
writer.write(SHORT, (short) point.blockY()); // y
|
||||
|
||||
writer.write(VAR_INT, registry.blockEntityId());
|
||||
final NBTCompound nbt = BlockUtils.extractClientNbt(block);
|
||||
final CompoundBinaryTag nbt = BlockUtils.extractClientNbt(block);
|
||||
assert nbt != null;
|
||||
writer.write(NBT, nbt); // block nbt
|
||||
}
|
||||
@ -59,7 +59,7 @@ public record ChunkData(@NotNull NBTCompound heightmaps, byte @NotNull [] data,
|
||||
final byte xz = reader.read(BYTE);
|
||||
final short y = reader.read(SHORT);
|
||||
final int blockEntityId = reader.read(VAR_INT);
|
||||
final NBTCompound nbt = (NBTCompound) reader.read(NBT);
|
||||
final CompoundBinaryTag nbt = (CompoundBinaryTag) reader.read(NBT);
|
||||
// TODO create block object
|
||||
}
|
||||
return blockEntities;
|
||||
|
@ -1,23 +1,23 @@
|
||||
package net.minestom.server.permission;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Representation of a permission granted to a {@link CommandSender}.
|
||||
* Each permission has a string representation used as an identifier, and an optional
|
||||
* {@link NBTCompound} used to store additional data.
|
||||
* {@link CompoundBinaryTag} used to store additional data.
|
||||
* <p>
|
||||
* The class is immutable.
|
||||
*/
|
||||
public class Permission {
|
||||
|
||||
private final String permissionName;
|
||||
private final NBTCompound data;
|
||||
private final CompoundBinaryTag data;
|
||||
|
||||
/**
|
||||
* Creates a new permission object with optional data.
|
||||
@ -25,7 +25,7 @@ public class Permission {
|
||||
* @param permissionName the name of the permission
|
||||
* @param data the optional data of the permission
|
||||
*/
|
||||
public Permission(@NotNull String permissionName, @Nullable NBTCompound data) {
|
||||
public Permission(@NotNull String permissionName, @Nullable CompoundBinaryTag data) {
|
||||
this.permissionName = permissionName;
|
||||
this.data = data;
|
||||
}
|
||||
@ -55,7 +55,7 @@ public class Permission {
|
||||
* @return the nbt data of this permission, can be null if not any
|
||||
*/
|
||||
@Nullable
|
||||
public NBTCompound getNBTData() {
|
||||
public CompoundBinaryTag getNBTData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,6 @@ 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.parser.SNBTParser;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
@ -14,8 +12,7 @@ import java.util.regex.Pattern;
|
||||
* Permissions are in-memory only by default.
|
||||
* You have however the capacity to store them persistently as the {@link Permission} object
|
||||
* is serializer-friendly, {@link Permission#getPermissionName()} being a {@link String}
|
||||
* and {@link Permission#getNBTData()} serializable into a string using {@link NBTCompound#toSNBT()}
|
||||
* and deserialized back with {@link SNBTParser#parse()}.
|
||||
* and {@link Permission#getNBTData()} serializable into a string using {@link net.kyori.adventure.nbt.TagStringIO}.
|
||||
*/
|
||||
public interface PermissionHandler {
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
package net.minestom.server.permission;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
/**
|
||||
* Interface used to check if the {@link NBTCompound nbt data} of a {@link Permission} is correct.
|
||||
* Interface used to check if the {@link CompoundBinaryTag nbt data} of a {@link Permission} is correct.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PermissionVerifier {
|
||||
@ -16,5 +16,5 @@ public interface PermissionVerifier {
|
||||
* @return true if {@link PermissionHandler#hasPermission(String, PermissionVerifier)}
|
||||
* should return true, false otherwise
|
||||
*/
|
||||
boolean isValid(@Nullable NBTCompound nbtCompound);
|
||||
boolean isValid(@Nullable CompoundBinaryTag nbtCompound);
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package net.minestom.server.tag;
|
||||
|
||||
import net.kyori.adventure.nbt.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.ServerFlag;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import org.jglrxavpok.hephaistos.nbt.*;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
@ -13,40 +13,41 @@ import java.util.function.Function;
|
||||
* Basic serializers for {@link Tag tags}.
|
||||
*/
|
||||
final class Serializers {
|
||||
static final Entry<Byte, NBTByte> BYTE = new Entry<>(NBTType.TAG_Byte, NBTByte::getValue, NBT::Byte);
|
||||
static final Entry<Boolean, NBTByte> BOOLEAN = new Entry<>(NBTType.TAG_Byte, NBTByte::asBoolean, NBT::Boolean);
|
||||
static final Entry<Short, NBTShort> SHORT = new Entry<>(NBTType.TAG_Short, NBTShort::getValue, NBT::Short);
|
||||
static final Entry<Integer, NBTInt> INT = new Entry<>(NBTType.TAG_Int, NBTInt::getValue, NBT::Int);
|
||||
static final Entry<Long, NBTLong> LONG = new Entry<>(NBTType.TAG_Long, NBTLong::getValue, NBT::Long);
|
||||
static final Entry<Float, NBTFloat> FLOAT = new Entry<>(NBTType.TAG_Float, NBTFloat::getValue, NBT::Float);
|
||||
static final Entry<Double, NBTDouble> DOUBLE = new Entry<>(NBTType.TAG_Double, NBTDouble::getValue, NBT::Double);
|
||||
static final Entry<String, NBTString> STRING = new Entry<>(NBTType.TAG_String, NBTString::getValue, NBT::String);
|
||||
static final Entry<NBT, NBT> NBT_ENTRY = new Entry<>(null, Function.identity(), Function.identity());
|
||||
static final Entry<Byte, ByteBinaryTag> BYTE = new Entry<>(BinaryTagTypes.BYTE, ByteBinaryTag::value, ByteBinaryTag::byteBinaryTag);
|
||||
static final Entry<Boolean, ByteBinaryTag> BOOLEAN = new Entry<>(BinaryTagTypes.BYTE, b -> b.value() != 0, b -> b ? ByteBinaryTag.ONE : ByteBinaryTag.ZERO);
|
||||
static final Entry<Short, ShortBinaryTag> SHORT = new Entry<>(BinaryTagTypes.SHORT, ShortBinaryTag::value, ShortBinaryTag::shortBinaryTag);
|
||||
static final Entry<Integer, IntBinaryTag> INT = new Entry<>(BinaryTagTypes.INT, IntBinaryTag::value, IntBinaryTag::intBinaryTag);
|
||||
static final Entry<Long, LongBinaryTag> LONG = new Entry<>(BinaryTagTypes.LONG, LongBinaryTag::value, LongBinaryTag::longBinaryTag);
|
||||
static final Entry<Float, FloatBinaryTag> FLOAT = new Entry<>(BinaryTagTypes.FLOAT, FloatBinaryTag::value, FloatBinaryTag::floatBinaryTag);
|
||||
static final Entry<Double, DoubleBinaryTag> DOUBLE = new Entry<>(BinaryTagTypes.DOUBLE, DoubleBinaryTag::value, DoubleBinaryTag::doubleBinaryTag);
|
||||
static final Entry<String, StringBinaryTag> STRING = new Entry<>(BinaryTagTypes.STRING, StringBinaryTag::value, StringBinaryTag::stringBinaryTag);
|
||||
static final Entry<BinaryTag, BinaryTag> NBT_ENTRY = new Entry<>(null, Function.identity(), Function.identity());
|
||||
|
||||
static final Entry<java.util.UUID, NBTIntArray> UUID = new Entry<>(NBTType.TAG_Int_Array, intArray -> intArrayToUuid(intArray.getValue().copyArray()),
|
||||
uuid -> NBT.IntArray(uuidToIntArray(uuid)));
|
||||
static final Entry<ItemStack, NBTCompound> ITEM = new Entry<>(NBTType.TAG_Compound, ItemStack::fromItemNBT, ItemStack::toItemNBT);
|
||||
static final Entry<Component, NBTString> COMPONENT = new Entry<>(NBTType.TAG_String, input -> GsonComponentSerializer.gson().deserialize(input.getValue()),
|
||||
component -> NBT.String(GsonComponentSerializer.gson().serialize(component)));
|
||||
static final Entry<java.util.UUID, IntArrayBinaryTag> UUID = new Entry<>(BinaryTagTypes.INT_ARRAY,
|
||||
intArray -> intArrayToUuid(intArray.value()),
|
||||
uuid -> IntArrayBinaryTag.intArrayBinaryTag(uuidToIntArray(uuid)));
|
||||
static final Entry<ItemStack, CompoundBinaryTag> ITEM = new Entry<>(BinaryTagTypes.COMPOUND, ItemStack::fromItemNBT, ItemStack::toItemNBT);
|
||||
static final Entry<Component, StringBinaryTag> COMPONENT = new Entry<>(BinaryTagTypes.STRING, input -> GsonComponentSerializer.gson().deserialize(input.value()),
|
||||
component -> StringBinaryTag.stringBinaryTag(GsonComponentSerializer.gson().serialize(component)));
|
||||
|
||||
static final Entry<Object, NBTByte> EMPTY = new Entry<>(NBTType.TAG_Byte, unused -> null, component -> null);
|
||||
static final Entry<Object, ByteBinaryTag> EMPTY = new Entry<>(BinaryTagTypes.BYTE, unused -> null, component -> null);
|
||||
|
||||
static <T> Entry<T, NBTCompound> fromTagSerializer(TagSerializer<T> serializer) {
|
||||
return new Serializers.Entry<>(NBTType.TAG_Compound,
|
||||
(NBTCompound compound) -> {
|
||||
if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && compound.isEmpty()) return null;
|
||||
static <T> Entry<T, CompoundBinaryTag> fromTagSerializer(TagSerializer<T> serializer) {
|
||||
return new Serializers.Entry<>(BinaryTagTypes.COMPOUND,
|
||||
(CompoundBinaryTag compound) -> {
|
||||
if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && compound.size() == 0) return null;
|
||||
return serializer.read(TagHandler.fromCompound(compound));
|
||||
},
|
||||
(value) -> {
|
||||
if (value == null) return NBTCompound.EMPTY;
|
||||
if (value == null) return CompoundBinaryTag.empty();
|
||||
TagHandler handler = TagHandler.newHandler();
|
||||
serializer.write(handler, value);
|
||||
return handler.asCompound();
|
||||
});
|
||||
}
|
||||
|
||||
record Entry<T, N extends NBT>(NBTType<N> nbtType, Function<N, T> reader, Function<T, N> writer, boolean isPath) {
|
||||
Entry(NBTType<N> nbtType, Function<N, T> reader, Function<T, N> writer) {
|
||||
record Entry<T, N extends BinaryTag>(BinaryTagType<N> nbtType, Function<N, T> reader, Function<T, N> writer, boolean isPath) {
|
||||
Entry(BinaryTagType<N> nbtType, Function<N, T> reader, Function<T, N> writer) {
|
||||
this(nbtType, reader, writer, false);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.tag;
|
||||
|
||||
import net.kyori.adventure.nbt.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.utils.collection.AutoIncrementMap;
|
||||
@ -7,11 +8,6 @@ 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.NBTCompoundLike;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTList;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTType;
|
||||
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -37,7 +33,7 @@ public class Tag<T> {
|
||||
|
||||
final int index;
|
||||
private final String key;
|
||||
final Serializers.Entry<T, NBT> entry;
|
||||
final Serializers.Entry<T, BinaryTag> entry;
|
||||
private final Supplier<T> defaultValue;
|
||||
|
||||
final Function<?, ?> readComparator;
|
||||
@ -48,7 +44,7 @@ public class Tag<T> {
|
||||
|
||||
Tag(int index, String key,
|
||||
Function<?, ?> readComparator,
|
||||
Serializers.Entry<T, NBT> entry,
|
||||
Serializers.Entry<T, BinaryTag> entry,
|
||||
Supplier<T> defaultValue, PathEntry[] path, UnaryOperator<T> copy, int listScope) {
|
||||
assert index == INDEX_MAP.get(key);
|
||||
this.index = index;
|
||||
@ -61,8 +57,8 @@ public class Tag<T> {
|
||||
this.listScope = listScope;
|
||||
}
|
||||
|
||||
static <T, N extends NBT> Tag<T> tag(@NotNull String key, @NotNull Serializers.Entry<T, N> entry) {
|
||||
return new Tag<>(INDEX_MAP.get(key), key, entry.reader(), (Serializers.Entry<T, NBT>) entry,
|
||||
static <T, N extends BinaryTag> Tag<T> tag(@NotNull String key, @NotNull Serializers.Entry<T, N> entry) {
|
||||
return new Tag<>(INDEX_MAP.get(key), key, entry.reader(), (Serializers.Entry<T, BinaryTag>) entry,
|
||||
null, null, null, 0);
|
||||
}
|
||||
|
||||
@ -98,11 +94,11 @@ public class Tag<T> {
|
||||
public <R> Tag<R> map(@NotNull Function<T, R> readMap,
|
||||
@NotNull Function<R, T> writeMap) {
|
||||
var entry = this.entry;
|
||||
final Function<NBT, R> readFunction = entry.reader().andThen(t -> {
|
||||
final Function<BinaryTag, R> readFunction = entry.reader().andThen(t -> {
|
||||
if (t == null) return null;
|
||||
return readMap.apply(t);
|
||||
});
|
||||
final Function<R, NBT> writeFunction = writeMap.andThen(entry.writer());
|
||||
final Function<R, BinaryTag> writeFunction = writeMap.andThen(entry.writer());
|
||||
return new Tag<>(index, key, readMap,
|
||||
new Serializers.Entry<>(entry.nbtType(), readFunction, writeFunction),
|
||||
// Default value
|
||||
@ -120,18 +116,18 @@ public class Tag<T> {
|
||||
var entry = this.entry;
|
||||
var readFunction = entry.reader();
|
||||
var writeFunction = entry.writer();
|
||||
var listEntry = new Serializers.Entry<List<T>, NBTList<?>>(
|
||||
NBTType.TAG_List,
|
||||
var listEntry = new Serializers.Entry<List<T>, ListBinaryTag>(
|
||||
BinaryTagTypes.LIST,
|
||||
read -> {
|
||||
if (read.isEmpty()) return List.of();
|
||||
return read.asListView().stream().map(readFunction).toList();
|
||||
if (read.size() == 0) return List.of();
|
||||
return read.stream().map(readFunction).toList();
|
||||
},
|
||||
write -> {
|
||||
if (write.isEmpty())
|
||||
return NBT.List(NBTType.TAG_String); // String is the default type for lists
|
||||
final List<NBT> list = write.stream().map(writeFunction).toList();
|
||||
final NBTType<?> type = list.get(0).getID();
|
||||
return NBT.List(type, list);
|
||||
return ListBinaryTag.empty();
|
||||
final List<BinaryTag> list = write.stream().map(writeFunction).toList();
|
||||
final BinaryTagType<?> type = list.get(0).type();
|
||||
return ListBinaryTag.listBinaryTag(type, list);
|
||||
});
|
||||
UnaryOperator<List<T>> co = this.copy != null ? ts -> {
|
||||
final int size = ts.size();
|
||||
@ -165,8 +161,8 @@ public class Tag<T> {
|
||||
return new Tag<>(index, key, readComparator, entry, defaultValue, pathEntries, copy, listScope);
|
||||
}
|
||||
|
||||
public @Nullable T read(@NotNull NBTCompoundLike nbt) {
|
||||
final NBT readable = isView() ? nbt.toCompound() : nbt.get(key);
|
||||
public @Nullable T read(@NotNull CompoundBinaryTag nbt) {
|
||||
final BinaryTag readable = isView() ? nbt : nbt.get(key);
|
||||
final T result;
|
||||
try {
|
||||
if (readable == null || (result = entry.read(readable)) == null)
|
||||
@ -177,18 +173,20 @@ public class Tag<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public void write(@NotNull MutableNBTCompound nbtCompound, @Nullable T value) {
|
||||
public void write(@NotNull CompoundBinaryTag.Builder nbtCompound, @Nullable T value) {
|
||||
if (value != null) {
|
||||
final NBT nbt = entry.write(value);
|
||||
if (isView()) nbtCompound.copyFrom((NBTCompoundLike) nbt);
|
||||
else nbtCompound.set(key, nbt);
|
||||
final BinaryTag nbt = entry.write(value);
|
||||
if (isView()) nbtCompound.put((CompoundBinaryTag) nbt);
|
||||
else nbtCompound.put(key, nbt);
|
||||
} else {
|
||||
if (isView()) nbtCompound.clear();
|
||||
else nbtCompound.remove(key);
|
||||
if (isView()) {
|
||||
// Adventure compound builder doesn't currently have a clear method.
|
||||
nbtCompound.build().keySet().forEach(nbtCompound::remove);
|
||||
} else nbtCompound.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeUnsafe(@NotNull MutableNBTCompound nbtCompound, @Nullable Object value) {
|
||||
public void writeUnsafe(@NotNull CompoundBinaryTag.Builder nbtCompound, @Nullable Object value) {
|
||||
//noinspection unchecked
|
||||
write(nbtCompound, (T) value);
|
||||
}
|
||||
@ -279,11 +277,11 @@ public class Tag<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a flexible tag able to read and write any {@link NBT} objects.
|
||||
* Creates a flexible tag able to read and write any {@link BinaryTag} objects.
|
||||
* <p>
|
||||
* Specialized tags are recommended if the type is known as conversion will be required both way (read and write).
|
||||
*/
|
||||
public static @NotNull Tag<NBT> NBT(@NotNull String key) {
|
||||
public static @NotNull Tag<BinaryTag> NBT(@NotNull String key) {
|
||||
return tag(key, Serializers.NBT_ENTRY);
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
package net.minestom.server.tag;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompoundLike;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
@ -26,7 +25,7 @@ public interface TagHandler extends TagReadable, TagWritable {
|
||||
/**
|
||||
* Creates a copy of this handler.
|
||||
* <p>
|
||||
* Similar to {@link #fromCompound(NBTCompoundLike)} using {@link #asCompound()}
|
||||
* Similar to {@link #fromCompound(CompoundBinaryTag)} using {@link #asCompound()}
|
||||
* with the advantage that cached objects and adaptive optimizations may be reused.
|
||||
*
|
||||
* @return a copy of this handler
|
||||
@ -36,18 +35,18 @@ public interface TagHandler extends TagReadable, TagWritable {
|
||||
/**
|
||||
* Updates the content of this handler.
|
||||
* <p>
|
||||
* Can be used as a clearing method with {@link NBTCompound#EMPTY}.
|
||||
* Can be used as a clearing method with {@link CompoundBinaryTag#empty()}.
|
||||
*
|
||||
* @param compound the new content of this handler
|
||||
*/
|
||||
void updateContent(@NotNull NBTCompoundLike compound);
|
||||
void updateContent(@NotNull CompoundBinaryTag compound);
|
||||
|
||||
/**
|
||||
* Converts the content of this handler into a {@link NBTCompound}.
|
||||
* Converts the content of this handler into a {@link CompoundBinaryTag}.
|
||||
*
|
||||
* @return a nbt compound representation of this handler
|
||||
*/
|
||||
@NotNull NBTCompound asCompound();
|
||||
@NotNull CompoundBinaryTag asCompound();
|
||||
|
||||
@ApiStatus.Experimental
|
||||
<T> void updateTag(@NotNull Tag<T> tag,
|
||||
@ -67,12 +66,12 @@ public interface TagHandler extends TagReadable, TagWritable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the content of the given {@link NBTCompoundLike} into a new {@link TagHandler}.
|
||||
* Copy the content of the given {@link CompoundBinaryTag} into a new {@link TagHandler}.
|
||||
*
|
||||
* @param compound the compound to read tags from
|
||||
* @return a new tag handler with the content of the given compound
|
||||
*/
|
||||
static @NotNull TagHandler fromCompound(@NotNull NBTCompoundLike compound) {
|
||||
static @NotNull TagHandler fromCompound(@NotNull CompoundBinaryTag compound) {
|
||||
return TagHandlerImpl.fromCompound(compound);
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,21 @@
|
||||
package net.minestom.server.tag;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagType;
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.ServerFlag;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompoundLike;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTType;
|
||||
import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound;
|
||||
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.Map;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
final class TagHandlerImpl implements TagHandler {
|
||||
static final Serializers.Entry<Node, NBTCompound> NODE_SERIALIZER = new Serializers.Entry<>(NBTType.TAG_Compound, entries -> fromCompound(entries).root, Node::compound, true);
|
||||
static final Serializers.Entry<Node, CompoundBinaryTag> NODE_SERIALIZER = new Serializers.Entry<>(BinaryTagTypes.COMPOUND, entries -> fromCompound(entries).root, Node::compound, true);
|
||||
|
||||
private final Node root;
|
||||
private volatile Node copy;
|
||||
@ -29,8 +28,7 @@ final class TagHandlerImpl implements TagHandler {
|
||||
this.root = new Node();
|
||||
}
|
||||
|
||||
static TagHandlerImpl fromCompound(NBTCompoundLike compoundLike) {
|
||||
final NBTCompound compound = compoundLike.toCompound();
|
||||
static TagHandlerImpl fromCompound(CompoundBinaryTag compound) {
|
||||
TagHandlerImpl handler = new TagHandlerImpl();
|
||||
TagNbtSeparator.separate(compound, entry -> handler.setTag(entry.tag(), entry.value()));
|
||||
handler.root.compound = compound;
|
||||
@ -50,7 +48,7 @@ final class TagHandlerImpl implements TagHandler {
|
||||
synchronized (this) {
|
||||
Node syncNode = traversePathWrite(root, tag, value != null);
|
||||
if (syncNode != null) {
|
||||
syncNode.updateContent(value != null ? (NBTCompound) tag.entry.write(value) : NBTCompound.EMPTY);
|
||||
syncNode.updateContent(value != null ? (CompoundBinaryTag) tag.entry.write(value) : CompoundBinaryTag.empty());
|
||||
syncNode.invalidate();
|
||||
}
|
||||
}
|
||||
@ -103,7 +101,7 @@ final class TagHandlerImpl implements TagHandler {
|
||||
if (tag.isView()) {
|
||||
final T previousValue = tag.read(node.compound());
|
||||
final T newValue = value.apply(previousValue);
|
||||
node.updateContent((NBTCompoundLike) tag.entry.write(newValue));
|
||||
node.updateContent((CompoundBinaryTag) tag.entry.write(newValue));
|
||||
node.invalidate();
|
||||
return returnPrevious ? previousValue : newValue;
|
||||
}
|
||||
@ -116,7 +114,7 @@ final class TagHandlerImpl implements TagHandler {
|
||||
if (previousEntry != null) {
|
||||
final Object previousTmp = previousEntry.value;
|
||||
if (previousTmp instanceof Node n) {
|
||||
final NBTCompound compound = NBT.Compound(Map.of(tag.getKey(), n.compound()));
|
||||
final CompoundBinaryTag compound = CompoundBinaryTag.from(Map.of(tag.getKey(), n.compound()));
|
||||
previousValue = tag.read(compound);
|
||||
} else {
|
||||
previousValue = (T) previousTmp;
|
||||
@ -149,12 +147,12 @@ final class TagHandlerImpl implements TagHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateContent(@NotNull NBTCompoundLike compound) {
|
||||
public synchronized void updateContent(@NotNull CompoundBinaryTag compound) {
|
||||
this.root.updateContent(compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull NBTCompound asCompound() {
|
||||
public @NotNull CompoundBinaryTag asCompound() {
|
||||
VarHandle.fullFence();
|
||||
return root.compound();
|
||||
}
|
||||
@ -200,7 +198,7 @@ final class TagHandlerImpl implements TagHandler {
|
||||
// Slow path is taken if the entry comes from a Structure tag, requiring conversion from NBT
|
||||
Node tmp = local;
|
||||
local = new Node(tmp);
|
||||
if (synEntry != null && synEntry.updatedNbt() instanceof NBTCompound compound) {
|
||||
if (synEntry != null && synEntry.updatedNbt() instanceof CompoundBinaryTag compound) {
|
||||
local.updateContent(compound);
|
||||
}
|
||||
tmp.entries.put(pathIndex, Entry.makePathEntry(path.name(), local));
|
||||
@ -211,8 +209,8 @@ final class TagHandlerImpl implements TagHandler {
|
||||
}
|
||||
|
||||
private <T> Entry<?> valueToEntry(Node parent, Tag<T> tag, @NotNull T value) {
|
||||
if (value instanceof NBT nbt) {
|
||||
if (nbt instanceof NBTCompound compound) {
|
||||
if (value instanceof BinaryTag nbt) {
|
||||
if (nbt instanceof CompoundBinaryTag compound) {
|
||||
final TagHandlerImpl handler = fromCompound(compound);
|
||||
return Entry.makePathEntry(tag, new Node(parent, handler.root.entries));
|
||||
} else {
|
||||
@ -227,7 +225,7 @@ final class TagHandlerImpl implements TagHandler {
|
||||
final class Node implements TagReadable {
|
||||
final Node parent;
|
||||
final StaticIntMap<Entry<?>> entries;
|
||||
NBTCompound compound;
|
||||
CompoundBinaryTag compound;
|
||||
|
||||
public Node(Node parent, StaticIntMap<Entry<?>> entries) {
|
||||
this.parent = parent;
|
||||
@ -260,44 +258,43 @@ final class TagHandlerImpl implements TagHandler {
|
||||
return (T) entry.value;
|
||||
}
|
||||
// Value must be parsed from nbt if the tag is different
|
||||
final NBT nbt = entry.updatedNbt();
|
||||
final Serializers.Entry<T, NBT> serializerEntry = tag.entry;
|
||||
final NBTType<NBT> type = serializerEntry.nbtType();
|
||||
return type == null || type == nbt.getID() ? serializerEntry.read(nbt) : tag.createDefault();
|
||||
final BinaryTag nbt = entry.updatedNbt();
|
||||
final Serializers.Entry<T, BinaryTag> serializerEntry = tag.entry;
|
||||
final BinaryTagType<BinaryTag> type = serializerEntry.nbtType();
|
||||
return type == null || type.equals(nbt.type()) ? serializerEntry.read(nbt) : tag.createDefault();
|
||||
}
|
||||
|
||||
void updateContent(@NotNull NBTCompoundLike compoundLike) {
|
||||
final NBTCompound compound = compoundLike.toCompound();
|
||||
void updateContent(@NotNull CompoundBinaryTag compound) {
|
||||
final TagHandlerImpl converted = fromCompound(compound);
|
||||
this.entries.updateContent(converted.root.entries);
|
||||
this.compound = compound;
|
||||
}
|
||||
|
||||
NBTCompound compound() {
|
||||
NBTCompound compound;
|
||||
CompoundBinaryTag compound() {
|
||||
CompoundBinaryTag compound;
|
||||
if (!ServerFlag.TAG_HANDLER_CACHE_ENABLED || (compound = this.compound) == null) {
|
||||
MutableNBTCompound tmp = new MutableNBTCompound();
|
||||
CompoundBinaryTag.Builder tmp = CompoundBinaryTag.builder();
|
||||
this.entries.forValues(entry -> {
|
||||
final Tag tag = entry.tag;
|
||||
final NBT nbt = entry.updatedNbt();
|
||||
if (nbt != null && (!tag.entry.isPath() || (!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && !((NBTCompound) nbt).isEmpty())) {
|
||||
final BinaryTag nbt = entry.updatedNbt();
|
||||
if (nbt != null && (!tag.entry.isPath() || (!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && ((CompoundBinaryTag) nbt).size() > 0)) {
|
||||
tmp.put(tag.getKey(), nbt);
|
||||
}
|
||||
});
|
||||
this.compound = compound = tmp.toCompound();
|
||||
this.compound = compound = tmp.build();
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
|
||||
@Contract("null -> !null")
|
||||
Node copy(Node parent) {
|
||||
MutableNBTCompound tmp = new MutableNBTCompound();
|
||||
CompoundBinaryTag.Builder tmp = CompoundBinaryTag.builder();
|
||||
Node result = new Node(parent, new StaticIntMap.Array<>());
|
||||
StaticIntMap<Entry<?>> entries = result.entries;
|
||||
this.entries.forValues(entry -> {
|
||||
Tag tag = entry.tag;
|
||||
Object value = entry.value;
|
||||
NBT nbt;
|
||||
BinaryTag nbt;
|
||||
if (value instanceof Node node) {
|
||||
Node copy = node.copy(result);
|
||||
if (copy == null)
|
||||
@ -313,9 +310,10 @@ final class TagHandlerImpl implements TagHandler {
|
||||
tmp.put(tag.getKey(), nbt);
|
||||
entries.put(tag.index, valueToEntry(result, tag, value));
|
||||
});
|
||||
if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && tmp.isEmpty() && parent != null)
|
||||
var compound = tmp.build();
|
||||
if ((!ServerFlag.SERIALIZE_EMPTY_COMPOUND) && compound.size() == 0 && parent != null)
|
||||
return null; // Empty child node
|
||||
result.compound = tmp.toCompound();
|
||||
result.compound = compound;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -330,7 +328,7 @@ final class TagHandlerImpl implements TagHandler {
|
||||
private static final class Entry<T> {
|
||||
private final Tag<T> tag;
|
||||
T value;
|
||||
NBT nbt;
|
||||
BinaryTag nbt;
|
||||
|
||||
Entry(Tag<T> tag, T value) {
|
||||
this.tag = tag;
|
||||
@ -345,9 +343,9 @@ final class TagHandlerImpl implements TagHandler {
|
||||
return makePathEntry(tag.getKey(), node);
|
||||
}
|
||||
|
||||
NBT updatedNbt() {
|
||||
BinaryTag updatedNbt() {
|
||||
if (tag.entry.isPath()) return ((Node) value).compound();
|
||||
NBT nbt = this.nbt;
|
||||
BinaryTag nbt = this.nbt;
|
||||
if (nbt == null) this.nbt = nbt = tag.entry.write(value);
|
||||
return nbt;
|
||||
}
|
||||
@ -360,7 +358,7 @@ final class TagHandlerImpl implements TagHandler {
|
||||
|
||||
Node toNode() {
|
||||
if (tag.entry.isPath()) return (Node) value;
|
||||
if (updatedNbt() instanceof NBTCompound compound) {
|
||||
if (updatedNbt() instanceof CompoundBinaryTag compound) {
|
||||
// Slow path forcing a conversion of the structure to NBTCompound
|
||||
// TODO should the handler be cached inside the entry?
|
||||
return fromCompound(compound).root;
|
||||
|
@ -1,9 +1,7 @@
|
||||
package net.minestom.server.tag;
|
||||
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTList;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTType;
|
||||
import net.kyori.adventure.nbt.*;
|
||||
import net.minestom.server.utils.NBTUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -15,30 +13,30 @@ import java.util.function.Function;
|
||||
import static java.util.Map.entry;
|
||||
|
||||
/**
|
||||
* Handles conversion of {@link NBT} subtypes into one or multiple primitive {@link Tag tags}.
|
||||
* Handles conversion of {@link BinaryTag} subtypes into one or multiple primitive {@link Tag tags}.
|
||||
*/
|
||||
final class TagNbtSeparator {
|
||||
static final Map<NBTType<?>, Function<String, Tag<?>>> SUPPORTED_TYPES = Map.ofEntries(
|
||||
entry(NBTType.TAG_Byte, Tag::Byte),
|
||||
entry(NBTType.TAG_Short, Tag::Short),
|
||||
entry(NBTType.TAG_Int, Tag::Integer),
|
||||
entry(NBTType.TAG_Long, Tag::Long),
|
||||
entry(NBTType.TAG_Float, Tag::Float),
|
||||
entry(NBTType.TAG_Double, Tag::Double),
|
||||
entry(NBTType.TAG_String, Tag::String));
|
||||
static final Map<BinaryTagType<?>, Function<String, Tag<?>>> SUPPORTED_TYPES = Map.ofEntries(
|
||||
entry(BinaryTagTypes.BYTE, Tag::Byte),
|
||||
entry(BinaryTagTypes.SHORT, Tag::Short),
|
||||
entry(BinaryTagTypes.INT, Tag::Integer),
|
||||
entry(BinaryTagTypes.LONG, Tag::Long),
|
||||
entry(BinaryTagTypes.FLOAT, Tag::Float),
|
||||
entry(BinaryTagTypes.DOUBLE, Tag::Double),
|
||||
entry(BinaryTagTypes.STRING, Tag::String));
|
||||
|
||||
static void separate(NBTCompound nbtCompound, Consumer<Entry> consumer) {
|
||||
static void separate(CompoundBinaryTag nbtCompound, Consumer<Entry> consumer) {
|
||||
for (var ent : nbtCompound) {
|
||||
convert(new ArrayList<>(), ent.getKey(), ent.getValue(), consumer);
|
||||
}
|
||||
}
|
||||
|
||||
static void separate(String key, NBT nbt, Consumer<Entry> consumer) {
|
||||
static void separate(String key, BinaryTag nbt, Consumer<Entry> consumer) {
|
||||
convert(new ArrayList<>(), key, nbt, consumer);
|
||||
}
|
||||
|
||||
static Entry separateSingle(String key, NBT nbt) {
|
||||
assert !(nbt instanceof NBTCompound);
|
||||
static Entry separateSingle(String key, BinaryTag nbt) {
|
||||
assert !(nbt instanceof CompoundBinaryTag);
|
||||
AtomicReference<Entry<?>> entryRef = new AtomicReference<>();
|
||||
convert(new ArrayList<>(), key, nbt, entry -> {
|
||||
assert entryRef.getPlain() == null : "Multiple entries found for nbt tag: " + key + " -> " + nbt;
|
||||
@ -49,28 +47,28 @@ final class TagNbtSeparator {
|
||||
return entry;
|
||||
}
|
||||
|
||||
private static void convert(List<String> path, String key, NBT nbt, Consumer<Entry> consumer) {
|
||||
var tagFunction = SUPPORTED_TYPES.get(nbt.getID());
|
||||
private static void convert(List<String> path, String key, BinaryTag nbt, Consumer<Entry> consumer) {
|
||||
var tagFunction = SUPPORTED_TYPES.get(nbt.type());
|
||||
if (tagFunction != null) {
|
||||
Tag tag = tagFunction.apply(key);
|
||||
consumer.accept(makeEntry(path, tag, nbt.getValue()));
|
||||
} else if (nbt instanceof NBTCompound nbtCompound) {
|
||||
consumer.accept(makeEntry(path, tag, NBTUtils.nbtValueFromTag(nbt)));
|
||||
} else if (nbt instanceof CompoundBinaryTag nbtCompound) {
|
||||
for (var ent : nbtCompound) {
|
||||
var newPath = new ArrayList<>(path);
|
||||
newPath.add(key);
|
||||
convert(newPath, ent.getKey(), ent.getValue(), consumer);
|
||||
}
|
||||
} else if (nbt instanceof NBTList<?> nbtList) {
|
||||
tagFunction = SUPPORTED_TYPES.get(nbtList.getSubtagType());
|
||||
} else if (nbt instanceof ListBinaryTag nbtList) {
|
||||
tagFunction = SUPPORTED_TYPES.get(nbtList.elementType());
|
||||
if (tagFunction == null) {
|
||||
// Invalid list subtype, fallback to nbt
|
||||
consumer.accept(makeEntry(path, Tag.NBT(key), nbt));
|
||||
} else {
|
||||
try {
|
||||
var tag = tagFunction.apply(key).list();
|
||||
Object[] values = new Object[nbtList.getSize()];
|
||||
Object[] values = new Object[nbtList.size()];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = nbtList.get(i).getValue();
|
||||
values[i] = NBTUtils.nbtValueFromTag(nbtList.get(i));
|
||||
}
|
||||
consumer.accept(makeEntry(path, Tag.class.cast(tag), List.of(values)));
|
||||
} catch (Exception e) {
|
||||
|
@ -1,11 +1,11 @@
|
||||
package net.minestom.server.tag;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -44,7 +44,7 @@ final class TagRecord {
|
||||
final Tag<?> tag;
|
||||
if (componentType.isRecord()) {
|
||||
tag = Tag.Structure(componentName, serializers.get(componentType));
|
||||
} else if (NBT.class.isAssignableFrom(componentType)) {
|
||||
} else if (BinaryTag.class.isAssignableFrom(componentType)) {
|
||||
tag = Tag.NBT(componentName);
|
||||
} else {
|
||||
final var fun = SUPPORTED_TYPES.get(componentType);
|
||||
@ -73,7 +73,7 @@ final class TagRecord {
|
||||
static final class Serializer<T extends Record> implements TagSerializer<T> {
|
||||
final Constructor<T> constructor;
|
||||
final Entry[] entries;
|
||||
final Serializers.Entry<T, NBTCompound> serializerEntry;
|
||||
final Serializers.Entry<T, CompoundBinaryTag> serializerEntry;
|
||||
|
||||
Serializer(Constructor<T> constructor, Entry[] entries) {
|
||||
this.constructor = constructor;
|
||||
|
@ -1,9 +1,9 @@
|
||||
package net.minestom.server.tag;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@ -31,11 +31,11 @@ public interface TagSerializer<T> {
|
||||
void write(@NotNull TagWritable writer, @NotNull T value);
|
||||
|
||||
@ApiStatus.Experimental
|
||||
TagSerializer<NBTCompound> COMPOUND = TagSerializerImpl.COMPOUND;
|
||||
TagSerializer<CompoundBinaryTag> COMPOUND = TagSerializerImpl.COMPOUND;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
static <T> TagSerializer<T> fromCompound(@NotNull Function<NBTCompound, T> reader,
|
||||
@NotNull Function<T, NBTCompound> writer) {
|
||||
static <T> TagSerializer<T> fromCompound(@NotNull Function<CompoundBinaryTag, T> reader,
|
||||
@NotNull Function<T, CompoundBinaryTag> writer) {
|
||||
return TagSerializerImpl.fromCompound(reader, writer);
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
package net.minestom.server.tag;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
final class TagSerializerImpl {
|
||||
public static final TagSerializer<NBTCompound> COMPOUND = new TagSerializer<>() {
|
||||
public static final TagSerializer<CompoundBinaryTag> COMPOUND = new TagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull NBTCompound read(@NotNull TagReadable reader) {
|
||||
public @NotNull CompoundBinaryTag read(@NotNull TagReadable reader) {
|
||||
return ((TagHandler) reader).asCompound();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull TagWritable writer, @NotNull NBTCompound value) {
|
||||
public void write(@NotNull TagWritable writer, @NotNull CompoundBinaryTag value) {
|
||||
TagNbtSeparator.separate(value, entry -> writer.setTag(entry.tag(), entry.value()));
|
||||
}
|
||||
};
|
||||
|
||||
static <T> TagSerializer<T> fromCompound(Function<NBTCompound, T> readFunc, Function<T, NBTCompound> writeFunc) {
|
||||
static <T> TagSerializer<T> fromCompound(Function<CompoundBinaryTag, T> readFunc, Function<T, CompoundBinaryTag> writeFunc) {
|
||||
return new TagSerializer<>() {
|
||||
@Override
|
||||
public @Nullable T read(@NotNull TagReadable reader) {
|
||||
final NBTCompound compound = COMPOUND.read(reader);
|
||||
final CompoundBinaryTag compound = COMPOUND.read(reader);
|
||||
return readFunc.apply(compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull TagWritable writer, @NotNull T value) {
|
||||
final NBTCompound compound = writeFunc.apply(value);
|
||||
final CompoundBinaryTag compound = writeFunc.apply(value);
|
||||
COMPOUND.write(writer, compound);
|
||||
}
|
||||
};
|
||||
|
59
src/main/java/net/minestom/server/utils/NBTUtils.java
Normal file
59
src/main/java/net/minestom/server/utils/NBTUtils.java
Normal file
@ -0,0 +1,59 @@
|
||||
package net.minestom.server.utils;
|
||||
|
||||
import net.kyori.adventure.nbt.*;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class NBTUtils {
|
||||
private static final BinaryTagType<?>[] TYPES = new BinaryTagType[]{
|
||||
BinaryTagTypes.END,
|
||||
BinaryTagTypes.BYTE,
|
||||
BinaryTagTypes.SHORT,
|
||||
BinaryTagTypes.INT,
|
||||
BinaryTagTypes.LONG,
|
||||
BinaryTagTypes.FLOAT,
|
||||
BinaryTagTypes.DOUBLE,
|
||||
BinaryTagTypes.BYTE_ARRAY,
|
||||
BinaryTagTypes.STRING,
|
||||
BinaryTagTypes.LIST,
|
||||
BinaryTagTypes.COMPOUND,
|
||||
BinaryTagTypes.INT_ARRAY,
|
||||
BinaryTagTypes.LONG_ARRAY,
|
||||
};
|
||||
|
||||
public static @NotNull BinaryTagType<?> nbtTypeFromId(byte id) {
|
||||
Check.argCondition(id < 0 || id >= TYPES.length, "Invalid NBT type id: " + id);
|
||||
return TYPES[id];
|
||||
}
|
||||
|
||||
public static @NotNull Object nbtValueFromTag(@NotNull BinaryTag tag) {
|
||||
if (tag instanceof ByteBinaryTag byteTag) {
|
||||
return byteTag.value();
|
||||
} else if (tag instanceof ShortBinaryTag shortTag) {
|
||||
return shortTag.value();
|
||||
} else if (tag instanceof IntBinaryTag intTag) {
|
||||
return intTag.value();
|
||||
} else if (tag instanceof LongBinaryTag longTag) {
|
||||
return longTag.value();
|
||||
} else if (tag instanceof FloatBinaryTag floatTag) {
|
||||
return floatTag.value();
|
||||
} else if (tag instanceof DoubleBinaryTag doubleTag) {
|
||||
return doubleTag.value();
|
||||
} else if (tag instanceof ByteArrayBinaryTag byteArrayTag) {
|
||||
return byteArrayTag.value();
|
||||
} else if (tag instanceof StringBinaryTag stringTag) {
|
||||
return stringTag.value();
|
||||
} else if (tag instanceof IntArrayBinaryTag intArrayTag) {
|
||||
return intArrayTag.value();
|
||||
} else if (tag instanceof LongArrayBinaryTag longArrayTag) {
|
||||
return longArrayTag.value();
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported NBT type: " + tag.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
private NBTUtils() {
|
||||
}
|
||||
}
|
@ -2,8 +2,6 @@ package net.minestom.server.utils.binary;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTReader;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBTWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -17,8 +15,6 @@ import java.nio.channels.WritableByteChannel;
|
||||
@ApiStatus.Internal
|
||||
public final class BinaryBuffer {
|
||||
private ByteBuffer nioBuffer; // To become a `MemorySegment` once released
|
||||
private NBTReader nbtReader;
|
||||
private NBTWriter nbtWriter;
|
||||
|
||||
private final int capacity;
|
||||
private int readerOffset, writerOffset;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.utils.binary;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
@ -8,7 +9,6 @@ import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.Either;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.BufferUnderflowException;
|
||||
@ -263,7 +263,7 @@ public class BinaryReader extends InputStream {
|
||||
return buffer.readableBytes();
|
||||
}
|
||||
|
||||
public NBT readTag() {
|
||||
public BinaryTag readTag() {
|
||||
return buffer.read(NBT);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.utils.binary;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
@ -8,7 +9,6 @@ import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.Either;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jglrxavpok.hephaistos.nbt.NBT;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -167,7 +167,7 @@ public class BinaryWriter extends OutputStream {
|
||||
this.buffer.write(ITEM, itemStack);
|
||||
}
|
||||
|
||||
public void writeNBT(@NotNull String name, @NotNull NBT tag) {
|
||||
public void writeNBT(@NotNull String name, @NotNull BinaryTag tag) {
|
||||
this.buffer.write(NBT, tag);
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
package net.minestom.server.utils.block;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockHandler;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.utils.StringUtils;
|
||||
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;
|
||||
@ -90,22 +88,22 @@ public class BlockUtils {
|
||||
return new Object2ObjectArrayMap<>(keys, values, entryCount);
|
||||
}
|
||||
|
||||
public static @Nullable NBTCompound extractClientNbt(@NotNull Block block) {
|
||||
public static @Nullable CompoundBinaryTag extractClientNbt(@NotNull Block block) {
|
||||
if (!block.registry().isBlockEntity()) return null;
|
||||
// Append handler tags
|
||||
final BlockHandler handler = block.handler();
|
||||
final NBTCompound blockNbt = Objects.requireNonNullElseGet(block.nbt(), NBTCompound::new);
|
||||
final CompoundBinaryTag blockNbt = Objects.requireNonNullElseGet(block.nbt(), CompoundBinaryTag::empty);
|
||||
if (handler != null) {
|
||||
// Extract explicitly defined tags and keep the rest server-side
|
||||
return NBT.Compound(nbt -> {
|
||||
for (Tag<?> tag : handler.getBlockEntityTags()) {
|
||||
final var value = tag.read(blockNbt);
|
||||
if (value != null) {
|
||||
// Tag is present and valid
|
||||
tag.writeUnsafe(nbt, value);
|
||||
}
|
||||
var builder = CompoundBinaryTag.builder();
|
||||
for (Tag<?> tag : handler.getBlockEntityTags()) {
|
||||
final var value = tag.read(blockNbt);
|
||||
if (value != null) {
|
||||
// Tag is present and valid
|
||||
tag.writeUnsafe(builder, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
// Complete nbt shall be sent if the block has no handler
|
||||
// Necessary to support all vanilla blocks
|
||||
|
@ -1,13 +1,10 @@
|
||||
package net.minestom.server.world;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jglrxavpok.hephaistos.mcdata.SizesKt;
|
||||
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;
|
||||
|
||||
@ -18,6 +15,9 @@ public class DimensionType {
|
||||
|
||||
private static final AtomicInteger idCounter = new AtomicInteger(0);
|
||||
|
||||
private static final int VANILLA_MIN_Y = -64;
|
||||
private static final int VANILLA_MAX_Y = 319;
|
||||
|
||||
public static final DimensionType OVERWORLD = DimensionType.builder(NamespaceID.from("minecraft:overworld"))
|
||||
.ultrawarm(false)
|
||||
.natural(true)
|
||||
@ -91,55 +91,56 @@ public class DimensionType {
|
||||
return new DimensionTypeBuilder();
|
||||
}
|
||||
|
||||
public static DimensionType fromNBT(NBTCompound nbt) {
|
||||
public static DimensionType fromNBT(CompoundBinaryTag nbt) {
|
||||
return DimensionType.builder(NamespaceID.from(nbt.getString("name")))
|
||||
.ambientLight(nbt.getFloat("ambient_light"))
|
||||
.infiniburn(NamespaceID.from(nbt.getString("infiniburn").replaceFirst("#", "")))
|
||||
.natural(nbt.getByte("natural") != 0)
|
||||
.ceilingEnabled(nbt.getByte("has_ceiling") != 0)
|
||||
.skylightEnabled(nbt.getByte("has_skylight") != 0)
|
||||
.ultrawarm(nbt.getByte("ultrawarm") != 0)
|
||||
.raidCapable(nbt.getByte("has_raids") != 0)
|
||||
.respawnAnchorSafe(nbt.getByte("respawn_anchor_works") != 0)
|
||||
.bedSafe(nbt.getByte("bed_works") != 0)
|
||||
.natural(nbt.getBoolean("natural"))
|
||||
.ceilingEnabled(nbt.getBoolean("has_ceiling"))
|
||||
.skylightEnabled(nbt.getBoolean("has_skylight"))
|
||||
.ultrawarm(nbt.getBoolean("ultrawarm"))
|
||||
.raidCapable(nbt.getBoolean("has_raids"))
|
||||
.respawnAnchorSafe(nbt.getBoolean("respawn_anchor_works"))
|
||||
.bedSafe(nbt.getBoolean("bed_works"))
|
||||
.effects(nbt.getString("effects"))
|
||||
.piglinSafe(nbt.getByte("piglin_safe") != 0)
|
||||
.piglinSafe(nbt.getBoolean("piglin_safe"))
|
||||
.logicalHeight(nbt.getInt("logical_height"))
|
||||
.coordinateScale(nbt.getDouble("coordinate_scale"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NBTCompound toIndexedNBT() {
|
||||
return NBT.Compound(Map.of(
|
||||
"name", NBT.String(name.toString()),
|
||||
"id", NBT.Int(id),
|
||||
"element", toNBT()));
|
||||
public CompoundBinaryTag toIndexedNBT() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("name", name.toString())
|
||||
.putInt("id", id)
|
||||
.put("element", toNBT())
|
||||
.build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NBTCompound toNBT() {
|
||||
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.setDouble("coordinate_scale", coordinateScale);
|
||||
nbt.setString("name", name.toString());
|
||||
nbt.setInt("monster_spawn_block_light_limit", 0);
|
||||
nbt.setInt("monster_spawn_light_level", 11);
|
||||
if (fixedTime != null) nbt.setLong("fixed_time", fixedTime);
|
||||
});
|
||||
public CompoundBinaryTag toNBT() {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
builder.putFloat("ambient_light", ambientLight);
|
||||
builder.putString("infiniburn", "#" + infiniburn.toString());
|
||||
builder.putByte("natural", (byte) (natural ? 0x01 : 0x00));
|
||||
builder.putByte("has_ceiling", (byte) (ceilingEnabled ? 0x01 : 0x00));
|
||||
builder.putByte("has_skylight", (byte) (skylightEnabled ? 0x01 : 0x00));
|
||||
builder.putByte("ultrawarm", (byte) (ultrawarm ? 0x01 : 0x00));
|
||||
builder.putByte("has_raids", (byte) (raidCapable ? 0x01 : 0x00));
|
||||
builder.putByte("respawn_anchor_works", (byte) (respawnAnchorSafe ? 0x01 : 0x00));
|
||||
builder.putByte("bed_works", (byte) (bedSafe ? 0x01 : 0x00));
|
||||
builder.putString("effects", effects);
|
||||
builder.putByte("piglin_safe", (byte) (piglinSafe ? 0x01 : 0x00));
|
||||
builder.putInt("min_y", minY);
|
||||
builder.putInt("height", height);
|
||||
builder.putInt("logical_height", logicalHeight);
|
||||
builder.putDouble("coordinate_scale", coordinateScale);
|
||||
builder.putString("name", name.toString());
|
||||
builder.putInt("monster_spawn_block_light_limit", 0);
|
||||
builder.putInt("monster_spawn_light_level", 11);
|
||||
if (fixedTime != null) builder.putLong("fixed_time", fixedTime);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -261,9 +262,9 @@ public class DimensionType {
|
||||
private boolean bedSafe = true;
|
||||
private String effects = "minecraft:overworld";
|
||||
private boolean piglinSafe = false;
|
||||
private int minY = SizesKt.getVanillaMinY();
|
||||
private int logicalHeight = SizesKt.getVanillaMaxY() - SizesKt.getVanillaMinY() + 1;
|
||||
private int height = SizesKt.getVanillaMaxY() - SizesKt.getVanillaMinY() + 1;
|
||||
private int minY = VANILLA_MIN_Y;
|
||||
private int logicalHeight = VANILLA_MAX_Y - VANILLA_MIN_Y + 1;
|
||||
private int height = VANILLA_MAX_Y - VANILLA_MIN_Y + 1;
|
||||
private double coordinateScale = 1.0;
|
||||
private NamespaceID infiniburn = NamespaceID.from("minecraft:infiniburn_overworld");
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
package net.minestom.server.world;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
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.NBTType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -81,21 +81,19 @@ public final class DimensionTypeManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link NBTCompound} containing all the registered dimensions.
|
||||
* Creates the {@link CompoundBinaryTag} containing all the registered dimensions.
|
||||
* <p>
|
||||
* Used when a player connects.
|
||||
*
|
||||
* @return an nbt compound containing the registered dimensions
|
||||
*/
|
||||
public @NotNull NBTCompound toNBT() {
|
||||
return NBT.Compound(dimensions -> {
|
||||
dimensions.setString("type", "minecraft:dimension_type");
|
||||
dimensions.set("value", NBT.List(
|
||||
NBTType.TAG_Compound,
|
||||
dimensionTypes.stream()
|
||||
.map(DimensionType::toIndexedNBT)
|
||||
.toList()
|
||||
));
|
||||
});
|
||||
public @NotNull CompoundBinaryTag toNBT() {
|
||||
ListBinaryTag.Builder<CompoundBinaryTag> entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
|
||||
for (DimensionType dimensionType : dimensionTypes)
|
||||
entries.add(dimensionType.toIndexedNBT());
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("type", "minecraft:dimension_type")
|
||||
.put("value", entries.build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.world.biomes;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.registry.ProtocolObject;
|
||||
import net.minestom.server.registry.Registry;
|
||||
@ -8,8 +9,6 @@ import net.minestom.server.utils.validate.Check;
|
||||
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.Locale;
|
||||
|
||||
@ -54,18 +53,20 @@ sealed public interface Biome extends ProtocolObject permits BiomeImpl {
|
||||
}
|
||||
}
|
||||
|
||||
default @NotNull NBTCompound toNbt() {
|
||||
default @NotNull CompoundBinaryTag toNbt() {
|
||||
Check.notNull(name(), "The biome namespace cannot be null");
|
||||
Check.notNull(effects(), "The biome effects cannot be null");
|
||||
|
||||
return NBT.Compound(element -> {
|
||||
element.setFloat("temperature", temperature());
|
||||
element.setFloat("downfall", downfall());
|
||||
element.setByte("has_precipitation", (byte) (precipitation() == Precipitation.NONE ? 0 : 1));
|
||||
if (temperatureModifier() != TemperatureModifier.NONE)
|
||||
element.setString("temperature_modifier", temperatureModifier().name().toLowerCase(Locale.ROOT));
|
||||
element.set("effects", effects().toNbt());
|
||||
});
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
|
||||
.putFloat("temperature", temperature())
|
||||
.putFloat("downfall", downfall())
|
||||
.putByte("has_precipitation", (byte) (precipitation() == Precipitation.NONE ? 0 : 1))
|
||||
.putString("precipitation", precipitation().name().toLowerCase(Locale.ROOT));
|
||||
if (temperatureModifier() != TemperatureModifier.NONE)
|
||||
builder.putString("temperature_modifier", temperatureModifier().name().toLowerCase(Locale.ROOT));
|
||||
return builder
|
||||
.put("effects", effects().toNbt())
|
||||
.build();
|
||||
}
|
||||
|
||||
static @NotNull Builder builder() {
|
||||
|
@ -1,12 +1,10 @@
|
||||
package net.minestom.server.world.biomes;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
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,
|
||||
@ -18,29 +16,29 @@ public record BiomeEffects(int fogColor, int skyColor, int waterColor, int water
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public NBTCompound toNbt() {
|
||||
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 CompoundBinaryTag toNbt() {
|
||||
var builder = CompoundBinaryTag.builder();
|
||||
builder.putInt("fog_color", fogColor);
|
||||
if (foliageColor != -1)
|
||||
builder.putInt("foliage_color", foliageColor);
|
||||
if (grassColor != -1)
|
||||
builder.putInt("grass_color", grassColor);
|
||||
builder.putInt("sky_color", skyColor);
|
||||
builder.putInt("water_color", waterColor);
|
||||
builder.putInt("water_fog_color", waterFogColor);
|
||||
if (grassColorModifier != null)
|
||||
builder.putString("grass_color_modifier", grassColorModifier.name().toLowerCase(Locale.ROOT));
|
||||
if (biomeParticle != null)
|
||||
builder.put("particle", biomeParticle.toNbt());
|
||||
if (ambientSound != null)
|
||||
builder.putString("ambient_sound", ambientSound.toString());
|
||||
if (moodSound != null)
|
||||
builder.put("mood_sound", moodSound.toNbt());
|
||||
if (additionsSound != null)
|
||||
builder.put("additions_sound", additionsSound.toNbt());
|
||||
if (music != null)
|
||||
builder.put("music", music.toNbt());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public enum GrassColorModifier {
|
||||
@ -48,30 +46,33 @@ 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() {
|
||||
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 @NotNull CompoundBinaryTag toNbt() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("sound", sound.toString())
|
||||
.putInt("tick_delay", tickDelay)
|
||||
.putInt("block_search_extent", blockSearchExtent)
|
||||
.putDouble("offset", offset)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public record AdditionsSound(NamespaceID sound, double tickChance) {
|
||||
public @NotNull NBTCompound toNbt() {
|
||||
return NBT.Compound(Map.of(
|
||||
"sound", NBT.String(sound.toString()),
|
||||
"tick_chance", NBT.Double(tickChance)));
|
||||
public @NotNull CompoundBinaryTag toNbt() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("sound", sound.toString())
|
||||
.putDouble("tick_chance", tickChance)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public record Music(NamespaceID sound, int minDelay, int maxDelay, boolean replaceCurrentMusic) {
|
||||
public @NotNull NBTCompound toNbt() {
|
||||
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)));
|
||||
public @NotNull CompoundBinaryTag toNbt() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("sound", sound.toString())
|
||||
.putInt("min_delay", minDelay)
|
||||
.putInt("max_delay", maxDelay)
|
||||
.putBoolean("replace_current_music", replaceCurrentMusic)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
package net.minestom.server.world.biomes;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
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.NBTType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -25,7 +25,7 @@ public final class BiomeManager {
|
||||
private final Map<NamespaceID, Integer> idMappings = new ConcurrentHashMap<>();
|
||||
|
||||
private final AtomicInteger ID_COUNTER = new AtomicInteger(0);
|
||||
private NBTCompound nbtCache = null;
|
||||
private CompoundBinaryTag nbtCache = null;
|
||||
|
||||
public BiomeManager() {
|
||||
// Need to register plains for the client to work properly
|
||||
@ -101,18 +101,21 @@ public final class BiomeManager {
|
||||
return getByName(namespace);
|
||||
}
|
||||
|
||||
public @NotNull NBTCompound toNBT() {
|
||||
public @NotNull CompoundBinaryTag toNBT() {
|
||||
if (nbtCache != null) return nbtCache;
|
||||
nbtCache = NBT.Compound(Map.of(
|
||||
"type", NBT.String("minecraft:worldgen/biome"),
|
||||
"value", NBT.List(NBTType.TAG_Compound, biomes.values().stream().map(biome -> {
|
||||
return NBT.Compound(Map.of(
|
||||
"id", NBT.Int(getId(biome)),
|
||||
"name", NBT.String(biome.namespace().toString()),
|
||||
"element", biome.toNbt()
|
||||
));
|
||||
}).toList())));
|
||||
|
||||
ListBinaryTag.Builder<CompoundBinaryTag> entries = ListBinaryTag.builder(BinaryTagTypes.COMPOUND);
|
||||
for (Biome biome : biomes.values()) {
|
||||
entries.add(CompoundBinaryTag.builder()
|
||||
.putInt("id", getId(biome))
|
||||
.putString("name", biome.namespace().toString())
|
||||
.put("element", biome.toNbt())
|
||||
.build());
|
||||
}
|
||||
nbtCache = CompoundBinaryTag.builder()
|
||||
.putString("type", "minecraft:worldgen/biome")
|
||||
.put("value", entries.build())
|
||||
.build();
|
||||
return nbtCache;
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,22 @@
|
||||
package net.minestom.server.world.biomes;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
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() {
|
||||
return NBT.Compound(Map.of(
|
||||
"probability", NBT.Float(probability),
|
||||
"options", option.toNbt()));
|
||||
public CompoundBinaryTag toNbt() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putFloat("probability", probability)
|
||||
.put("options", option.toNbt())
|
||||
.build();
|
||||
}
|
||||
|
||||
public interface Option {
|
||||
NBTCompound toNbt();
|
||||
CompoundBinaryTag toNbt();
|
||||
}
|
||||
|
||||
public record BlockOption(Block block) implements Option {
|
||||
@ -24,15 +24,17 @@ public record BiomeParticle(float probability, Option option) {
|
||||
private static final String type = "block";
|
||||
|
||||
@Override
|
||||
public NBTCompound toNbt() {
|
||||
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)));
|
||||
}
|
||||
});
|
||||
public CompoundBinaryTag toNbt() {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
builder.putString("type", type);
|
||||
builder.putString("Name", block.name());
|
||||
Map<String, String> propertiesMap = block.properties();
|
||||
if (!propertiesMap.isEmpty()) {
|
||||
CompoundBinaryTag.Builder properties = CompoundBinaryTag.builder();
|
||||
propertiesMap.forEach(properties::putString);
|
||||
builder.put("Properties", properties.build());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,13 +42,14 @@ public record BiomeParticle(float probability, Option option) {
|
||||
private static final String type = "dust";
|
||||
|
||||
@Override
|
||||
public NBTCompound toNbt() {
|
||||
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)));
|
||||
public CompoundBinaryTag toNbt() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("type", type)
|
||||
.putFloat("r", red)
|
||||
.putFloat("g", green)
|
||||
.putFloat("b", blue)
|
||||
.putFloat("scale", scale)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,17 +57,19 @@ public record BiomeParticle(float probability, Option option) {
|
||||
private static final String type = "item";
|
||||
|
||||
@Override
|
||||
public NBTCompound toNbt() {
|
||||
public CompoundBinaryTag toNbt() {
|
||||
//todo test count might be wrong type
|
||||
NBTCompound nbtCompound = item.meta().toNBT();
|
||||
return nbtCompound.modify(n -> n.setString("type", type));
|
||||
return item.meta().toNBT()
|
||||
.putString("type", type);
|
||||
}
|
||||
}
|
||||
|
||||
public record NormalOption(NamespaceID type) implements Option {
|
||||
@Override
|
||||
public NBTCompound toNbt() {
|
||||
return NBT.Compound(Map.of("type", NBT.String(type.toString())));
|
||||
public CompoundBinaryTag toNbt() {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("type", type.toString())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user