mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-14 03:11:25 +01:00
chore: more components
This commit is contained in:
parent
65e04d0a94
commit
af85459761
@ -18,6 +18,7 @@ import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent.ShowEntity;
|
||||
import net.kyori.adventure.text.event.HoverEventSource;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import net.kyori.adventure.title.TitlePart;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.ServerFlag;
|
||||
@ -48,9 +49,10 @@ import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.inventory.Inventory;
|
||||
import net.minestom.server.inventory.PlayerInventory;
|
||||
import net.minestom.server.item.ItemComponent;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.item.metadata.WrittenBookMeta;
|
||||
import net.minestom.server.item.component.WrittenBookContent;
|
||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||
import net.minestom.server.message.ChatMessageType;
|
||||
import net.minestom.server.message.ChatPosition;
|
||||
@ -181,7 +183,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
protected PlayerInventory inventory;
|
||||
private Inventory openInventory;
|
||||
// Used internally to allow the closing of inventory within the inventory listener
|
||||
private boolean didCloseInventory;
|
||||
private boolean skipClosePacket;
|
||||
|
||||
private byte heldSlot;
|
||||
|
||||
@ -1000,13 +1002,13 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
closeInventory();
|
||||
}
|
||||
|
||||
// TODO: when adventure updates, delete this
|
||||
String title = PlainTextComponentSerializer.plainText().serialize(book.title());
|
||||
String author = PlainTextComponentSerializer.plainText().serialize(book.author());
|
||||
final ItemStack writtenBook = ItemStack.builder(Material.WRITTEN_BOOK)
|
||||
.meta(WrittenBookMeta.class, builder -> builder.resolved(false)
|
||||
.generation(WrittenBookMeta.WrittenBookGeneration.ORIGINAL)
|
||||
.author(book.author())
|
||||
.title(book.title())
|
||||
.pages(book.pages()))
|
||||
.set(ItemComponent.WRITTEN_BOOK_CONTENT, new WrittenBookContent(book.pages(), title, author, 0, false))
|
||||
.build();
|
||||
|
||||
// Set book in offhand
|
||||
sendPacket(new SetSlotPacket((byte) 0, 0, (short) PlayerInventoryUtils.OFFHAND_SLOT, writtenBook));
|
||||
// Open the book
|
||||
@ -1726,6 +1728,19 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
return openInventory;
|
||||
}
|
||||
|
||||
private void tryCloseInventory(boolean skipClosePacket) {
|
||||
var closedInventory = getOpenInventory();
|
||||
if (closedInventory == null) return;
|
||||
|
||||
this.skipClosePacket = skipClosePacket;
|
||||
|
||||
if (closedInventory.removeViewer(this)) {
|
||||
if (closedInventory == getOpenInventory()) {
|
||||
this.openInventory = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the specified Inventory, close the previous inventory if existing.
|
||||
*
|
||||
@ -1736,21 +1751,12 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
InventoryOpenEvent inventoryOpenEvent = new InventoryOpenEvent(inventory, this);
|
||||
|
||||
EventDispatcher.callCancellable(inventoryOpenEvent, () -> {
|
||||
Inventory openInventory = getOpenInventory();
|
||||
if (openInventory != null) {
|
||||
openInventory.removeViewer(this);
|
||||
}
|
||||
tryCloseInventory(true);
|
||||
|
||||
Inventory newInventory = inventoryOpenEvent.getInventory();
|
||||
if (newInventory == null) {
|
||||
// just close the inventory
|
||||
return;
|
||||
if (newInventory.addViewer(this)) {
|
||||
this.openInventory = newInventory;
|
||||
}
|
||||
|
||||
sendPacket(new OpenWindowPacket(newInventory.getWindowId(),
|
||||
newInventory.getInventoryType().getWindowType(), newInventory.getTitle()));
|
||||
newInventory.addViewer(this);
|
||||
this.openInventory = newInventory;
|
||||
});
|
||||
return !inventoryOpenEvent.isCancelled();
|
||||
}
|
||||
@ -1799,27 +1805,16 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally to prevent an inventory click to be processed
|
||||
* when the inventory listeners closed the inventory.
|
||||
* <p>
|
||||
* Should only be used within an inventory listener (event or condition).
|
||||
*
|
||||
* @return true if the inventory has been closed, false otherwise
|
||||
*/
|
||||
public boolean didCloseInventory() {
|
||||
return didCloseInventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally to reset the didCloseInventory field.
|
||||
* Used internally to reset the skipClosePacket field, which determines when sending the close inventory packet
|
||||
* should be skipped.
|
||||
* <p>
|
||||
* Shouldn't be used externally without proper understanding of its consequence.
|
||||
*
|
||||
* @param didCloseInventory the new didCloseInventory field
|
||||
* @param skipClosePacket the new skipClosePacket field
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public void UNSAFE_changeDidCloseInventory(boolean didCloseInventory) {
|
||||
this.didCloseInventory = didCloseInventory;
|
||||
public void UNSAFE_changeSkipClosePacket(boolean skipClosePacket) {
|
||||
this.skipClosePacket = skipClosePacket;
|
||||
}
|
||||
|
||||
public int getNextTeleportId() {
|
||||
|
@ -51,8 +51,8 @@ public sealed interface ItemComponent<T> extends StaticProtocolObject permits It
|
||||
ItemComponent<List<ItemStack>> BUNDLE_CONTENTS = declare("bundle_contents", NetworkBuffer.ITEM.list(Short.MAX_VALUE), BinaryTagSerializer.ITEM.list());
|
||||
ItemComponent<Void> POTION_CONTENTS = declare("potion_contents", null, null); //todo
|
||||
ItemComponent<Void> SUSPICIOUS_STEW_EFFECTS = declare("suspicious_stew_effects", null, null); //todo
|
||||
ItemComponent<Void> WRITABLE_BOOK_CONTENT = declare("writable_book_content", null, null); //todo
|
||||
ItemComponent<Void> WRITTEN_BOOK_CONTENT = declare("written_book_content", null, null); //todo
|
||||
ItemComponent<WritableBookContent> WRITABLE_BOOK_CONTENT = declare("writable_book_content", WritableBookContent.NETWORK_TYPE, WritableBookContent.NBT_TYPE);
|
||||
ItemComponent<WrittenBookContent> WRITTEN_BOOK_CONTENT = declare("written_book_content", WrittenBookContent.NETWORK_TYPE, WrittenBookContent.NBT_TYPE);
|
||||
ItemComponent<Void> TRIM = declare("trim", null, null); //todo
|
||||
ItemComponent<Void> DEBUG_STICK_STATE = declare("debug_stick_state", null, null); //todo
|
||||
ItemComponent<CustomData> ENTITY_DATA = declare("entity_data", CustomData.NETWORK_TYPE, CustomData.NBT_TYPE);
|
||||
@ -76,8 +76,11 @@ public sealed interface ItemComponent<T> extends StaticProtocolObject permits It
|
||||
ItemComponent<SeededContainerLoot> CONTAINER_LOOT = declare("container_loot", null, SeededContainerLoot.NBT_TYPE);
|
||||
|
||||
@NotNull T read(@NotNull BinaryTag tag);
|
||||
@NotNull BinaryTag write(@NotNull T value);
|
||||
|
||||
@NotNull T read(@NotNull NetworkBuffer reader);
|
||||
void write(@NotNull NetworkBuffer writer, @NotNull T value);
|
||||
|
||||
|
||||
static @Nullable ItemComponent<?> fromNamespaceId(@NotNull String namespaceId) {
|
||||
return ItemComponentImpl.NAMESPACES.get(namespaceId);
|
||||
|
@ -5,10 +5,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface ItemComponentMap {
|
||||
|
||||
static @NotNull Builder builder() {
|
||||
//todo
|
||||
}
|
||||
|
||||
boolean has(@NotNull ItemComponent<?> component);
|
||||
|
||||
<T> @Nullable T get(@NotNull ItemComponent<T> component);
|
||||
@ -18,12 +14,4 @@ public interface ItemComponentMap {
|
||||
return value != null ? value : defaultValue;
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
|
||||
<T> @NotNull Builder set(@NotNull ItemComponent<T> component, @NotNull T value);
|
||||
|
||||
void remove(@NotNull ItemComponent<?> component);
|
||||
|
||||
@NotNull ItemComponentMap build();
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,141 @@
|
||||
package net.minestom.server.item;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public sealed interface ItemComponentPatch extends ItemComponentMap permits ItemComponentPatchImpl {
|
||||
import java.util.Map;
|
||||
|
||||
@NotNull NetworkBuffer.Type<ItemComponentPatch> NETWORK_TYPE = null;
|
||||
@NotNull BinaryTagSerializer<ItemComponentPatch> NBT_TYPE = null;
|
||||
/**
|
||||
* <p>Holds the altered components of an itemstack.</p>
|
||||
*
|
||||
* <p>The inner map contains the value for added components, null for removed components, and no entry for unmodified components.</p>
|
||||
*
|
||||
* @param patch
|
||||
*/
|
||||
record ItemComponentPatch(@NotNull Int2ObjectMap<Object> patch) {
|
||||
private static final char REMOVAL_PREFIX = '!';
|
||||
|
||||
<T> @NotNull ItemComponentPatch with(@NotNull ItemComponent<T> component, T value);
|
||||
public static final ItemComponentPatch EMPTY = new ItemComponentPatch(new Int2ObjectArrayMap<>(0));
|
||||
|
||||
@NotNull ItemComponentPatch without(@NotNull ItemComponent<?> component);
|
||||
public static final @NotNull NetworkBuffer.Type<ItemComponentPatch> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, ItemComponentPatch value) {
|
||||
int added = 0;
|
||||
for (Object o : value.patch.values()) {
|
||||
if (o != null) added++;
|
||||
}
|
||||
|
||||
buffer.write(NetworkBuffer.VAR_INT, added);
|
||||
buffer.write(NetworkBuffer.VAR_INT, value.patch.size() - added);
|
||||
for (Int2ObjectMap.Entry<Object> entry : value.patch.int2ObjectEntrySet()) {
|
||||
if (entry.getValue() != null) {
|
||||
buffer.write(NetworkBuffer.VAR_INT, entry.getIntKey());
|
||||
//noinspection unchecked
|
||||
ItemComponent<Object> type = (ItemComponent<Object>) ItemComponent.fromId(entry.getIntKey());
|
||||
assert type != null;
|
||||
type.write(entry.getValue());
|
||||
}
|
||||
}
|
||||
for (Int2ObjectMap.Entry<Object> entry : value.patch.int2ObjectEntrySet()) {
|
||||
if (entry.getValue() == null) {
|
||||
buffer.write(NetworkBuffer.VAR_INT, entry.getIntKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemComponentPatch read(@NotNull NetworkBuffer buffer) {
|
||||
int added = buffer.read(NetworkBuffer.VAR_INT);
|
||||
int removed = buffer.read(NetworkBuffer.VAR_INT);
|
||||
Int2ObjectMap<Object> patch = new Int2ObjectArrayMap<>(added + removed);
|
||||
for (int i = 0; i < added; i++) {
|
||||
int id = buffer.read(NetworkBuffer.VAR_INT);
|
||||
//noinspection unchecked
|
||||
ItemComponent<Object> type = (ItemComponent<Object>) ItemComponent.fromId(id);
|
||||
Check.notNull(type, "Unknown item component id: {0}", id);
|
||||
patch.put(id, type.read(buffer));
|
||||
}
|
||||
for (int i = 0; i < removed; i++) {
|
||||
int id = buffer.read(NetworkBuffer.VAR_INT);
|
||||
patch.put(id, null);
|
||||
}
|
||||
return new ItemComponentPatch(patch);
|
||||
}
|
||||
};
|
||||
public static final @NotNull BinaryTagSerializer<ItemComponentPatch> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
tag -> {
|
||||
if (tag.size() == 0) return EMPTY;
|
||||
Int2ObjectMap<Object> patch = new Int2ObjectArrayMap<>(tag.size());
|
||||
for (Map.Entry<String, ? extends BinaryTag> entry : tag) {
|
||||
String key = entry.getKey();
|
||||
boolean remove = false;
|
||||
if (!key.isEmpty() && key.charAt(0) == REMOVAL_PREFIX) {
|
||||
key = key.substring(1);
|
||||
remove = true;
|
||||
}
|
||||
ItemComponent<?> type = ItemComponent.fromNamespaceId(key);
|
||||
Check.notNull(type, "Unknown item component: {0}", key);
|
||||
if (remove) {
|
||||
patch.put(type.id(), null);
|
||||
} else {
|
||||
Object value = type.read(entry.getValue());
|
||||
patch.put(type.id(), value);
|
||||
}
|
||||
}
|
||||
return new ItemComponentPatch(patch);
|
||||
},
|
||||
patch -> {
|
||||
if (patch.patch.isEmpty()) return CompoundBinaryTag.empty();
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
for (Int2ObjectMap.Entry<Object> entry : patch.patch.int2ObjectEntrySet()) {
|
||||
//noinspection unchecked
|
||||
ItemComponent<Object> type = (ItemComponent<Object>) ItemComponent.fromId(entry.getIntKey());
|
||||
Check.notNull(type, "Unknown item component id: {0}", entry.getIntKey());
|
||||
if (entry.getValue() == null) {
|
||||
builder.put(REMOVAL_PREFIX + type.name(), CompoundBinaryTag.empty());
|
||||
} else {
|
||||
builder.put(type.name(), type.write(entry.getValue()));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
);
|
||||
|
||||
public boolean has(@NotNull ItemComponentMap prototype, @NotNull ItemComponent<?> component) {
|
||||
if (patch.containsKey(component.id())) {
|
||||
return patch.get(component.id()) != null;
|
||||
} else {
|
||||
return prototype.has(component);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> @Nullable T get(@NotNull ItemComponentMap prototype, @NotNull ItemComponent<T> component) {
|
||||
if (patch.containsKey(component.id())) {
|
||||
return (T) patch.get(component.id());
|
||||
} else {
|
||||
return prototype.get(component);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> @NotNull ItemComponentPatch with(@NotNull ItemComponent<T> component, @NotNull T value) {
|
||||
Int2ObjectMap<Object> newPatch = new Int2ObjectArrayMap<>(patch);
|
||||
newPatch.put(component.id(), value);
|
||||
return new ItemComponentPatch(newPatch);
|
||||
}
|
||||
|
||||
public <T> @NotNull ItemComponentPatch without(@NotNull ItemComponent<T> component) {
|
||||
Int2ObjectMap<Object> newPatch = new Int2ObjectArrayMap<>(patch);
|
||||
newPatch.put(component.id(), null);
|
||||
return new ItemComponentPatch(newPatch);
|
||||
}
|
||||
|
||||
interface Builder extends ItemComponentMap {
|
||||
|
||||
|
@ -4,6 +4,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.event.HoverEventSource;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.item.component.ItemComponent;
|
||||
import net.minestom.server.item.component.ItemComponentMap;
|
||||
import net.minestom.server.inventory.ContainerInventory;
|
||||
@ -33,6 +34,8 @@ public sealed interface ItemStack extends TagReadable, ItemComponentMap, HoverEv
|
||||
*/
|
||||
@NotNull ItemStack AIR = ItemStack.of(Material.AIR);
|
||||
|
||||
@NotNull NetworkBuffer.Type<ItemStack> NETWORK_TYPE = ItemStackImpl.NETWORK_TYPE;
|
||||
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
static @NotNull Builder builder(@NotNull Material material) {
|
||||
return new ItemStackImpl.Builder(material, 1);
|
||||
@ -93,7 +96,7 @@ public sealed interface ItemStack extends TagReadable, ItemComponentMap, HoverEv
|
||||
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
default <T> @NotNull ItemStack withTag(@NotNull Tag<T> tag, @Nullable T value) {
|
||||
return withMeta(builder -> builder.set(tag, value));
|
||||
return with(ItemComponent.CUSTOM_DATA, get(ItemComponent.CUSTOM_DATA, CustomData.EMPTY).withTag(tag, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,7 +2,10 @@ package net.minestom.server.item;
|
||||
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.minestom.server.item.component.CustomData;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.tag.Tag;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -11,23 +14,26 @@ import java.util.function.Consumer;
|
||||
|
||||
record ItemStackImpl(Material material, int amount, ItemComponentPatch components) implements ItemStack {
|
||||
|
||||
static final NetworkBuffer.Type<ItemStack> NETWORK_TYPE = null;
|
||||
static final BinaryTagSerializer<ItemStack> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(ItemStackImpl::fromCompound, ItemStackImpl::toCompound);
|
||||
|
||||
static ItemStack create(Material material, int amount, ItemComponentPatch components) {
|
||||
if (amount <= 0) return AIR;
|
||||
return new ItemStackImpl(material, amount, components);
|
||||
}
|
||||
|
||||
static ItemStack create(Material material, int amount) {
|
||||
return create(material, amount, ItemComponentPatch.builder(material).build());
|
||||
return create(material, amount, ItemComponentPatch.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T get(@NotNull ItemComponent<T> component) {
|
||||
return components.get(component);
|
||||
return components.get(material.prototype(), component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(@NotNull ItemComponent<?> component) {
|
||||
return components.has(component);
|
||||
return components.has(material.prototype(), component);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -71,6 +77,8 @@ record ItemStackImpl(Material material, int amount, ItemComponentPatch component
|
||||
|
||||
@Override
|
||||
public @NotNull CompoundBinaryTag toItemNBT() {
|
||||
return (CompoundBinaryTag) NBT_TYPE.write(this);
|
||||
|
||||
// CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder()
|
||||
// .putString("id", material.name())
|
||||
// .putByte("Count", (byte) amount);
|
||||
@ -85,6 +93,23 @@ record ItemStackImpl(Material material, int amount, ItemComponentPatch component
|
||||
return new Builder(material, amount, components.builder());
|
||||
}
|
||||
|
||||
private static @NotNull ItemStack fromCompound(@NotNull CompoundBinaryTag tag) {
|
||||
String id = tag.getString("id");
|
||||
Material material = Material.fromNamespaceId(id);
|
||||
Check.notNull(material, "Unknown material: {0}", id);
|
||||
int count = tag.getInt("count", 1);
|
||||
ItemComponentPatch patch = ItemComponentPatch.NBT_TYPE.read(tag.getCompound("components"));
|
||||
return new ItemStackImpl(material, count, patch);
|
||||
}
|
||||
|
||||
private static @NotNull CompoundBinaryTag toCompound(@NotNull ItemStack itemStack) {
|
||||
return CompoundBinaryTag.builder()
|
||||
.putString("id", itemStack.material().name())
|
||||
.putInt("count", itemStack.amount())
|
||||
.put("components", ItemComponentPatch.NBT_TYPE.write(((ItemStackImpl) itemStack).components))
|
||||
.build();
|
||||
}
|
||||
|
||||
static final class Builder implements ItemStack.Builder {
|
||||
final Material material;
|
||||
int amount;
|
||||
|
@ -0,0 +1,60 @@
|
||||
package net.minestom.server.item.book;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public record FilteredText<T>(@NotNull T text, @Nullable T filtered) {
|
||||
|
||||
public static @NotNull NetworkBuffer.Type<FilteredText<String>> STRING_NETWORK_TYPE = createNetworkType(NetworkBuffer.STRING);
|
||||
public static @NotNull BinaryTagSerializer<FilteredText<String>> STRING_NBT_TYPE = createNbtType(BinaryTagSerializer.STRING);
|
||||
|
||||
public static @NotNull NetworkBuffer.Type<FilteredText<Component>> COMPONENT_NETWORK_TYPE = createNetworkType(NetworkBuffer.COMPONENT);
|
||||
public static @NotNull BinaryTagSerializer<FilteredText<Component>> COMPONENT_NBT_TYPE = createNbtType(BinaryTagSerializer.JSON_COMPONENT);
|
||||
|
||||
private static <T> NetworkBuffer.@NotNull Type<FilteredText<T>> createNetworkType(@NotNull NetworkBuffer.Type<T> inner) {
|
||||
return new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, FilteredText<T> value) {
|
||||
buffer.write(inner, value.text);
|
||||
buffer.writeOptional(inner, value.filtered);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilteredText<T> read(@NotNull NetworkBuffer buffer) {
|
||||
return new FilteredText<>(buffer.read(inner), buffer.readOptional(inner));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static <T> @NotNull BinaryTagSerializer<FilteredText<T>> createNbtType(@NotNull BinaryTagSerializer<T> inner) {
|
||||
return new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull FilteredText<T> value) {
|
||||
CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
builder.put("text", inner.write(value.text));
|
||||
if (value.filtered != null) {
|
||||
builder.put("filtered", inner.write(value.filtered));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FilteredText<T> read(@NotNull BinaryTag tag) {
|
||||
if (tag instanceof CompoundBinaryTag compound) {
|
||||
BinaryTag textTag = compound.get("text");
|
||||
if (textTag != null) {
|
||||
BinaryTag filteredTag = compound.get("filtered");
|
||||
T filtered = filteredTag == null ? null : inner.read(filteredTag);
|
||||
return new FilteredText<>(inner.read(textTag), filtered);
|
||||
}
|
||||
}
|
||||
return new FilteredText<>(inner.read(tag), null);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.minestom.server.item.book.FilteredText;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public record WritableBookContent(@NotNull List<FilteredText<String>> pages) {
|
||||
public static final WritableBookContent EMPTY = new WritableBookContent(List.of());
|
||||
|
||||
public static final NetworkBuffer.Type<WritableBookContent> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, WritableBookContent value) {
|
||||
buffer.writeCollection(FilteredText.STRING_NETWORK_TYPE, value.pages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WritableBookContent read(@NotNull NetworkBuffer buffer) {
|
||||
return new WritableBookContent(buffer.readCollection(FilteredText.STRING_NETWORK_TYPE, 100));
|
||||
}
|
||||
};
|
||||
|
||||
public static final BinaryTagSerializer<WritableBookContent> NBT_TYPE = new BinaryTagSerializer<>() {
|
||||
@Override
|
||||
public @NotNull BinaryTag write(@NotNull WritableBookContent value) {
|
||||
ListBinaryTag.Builder<BinaryTag> pages = ListBinaryTag.builder();
|
||||
for (FilteredText<String> page : value.pages) {
|
||||
pages.add(FilteredText.STRING_NBT_TYPE.write(page));
|
||||
}
|
||||
return CompoundBinaryTag.builder().put("pages", pages.build()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull WritableBookContent read(@NotNull BinaryTag tag) {
|
||||
if (!(tag instanceof CompoundBinaryTag compound)) return EMPTY;
|
||||
ListBinaryTag pagesTag = compound.getList("pages");
|
||||
if (pagesTag.size() == 0) return EMPTY;
|
||||
|
||||
List<FilteredText<String>> pages = new ArrayList<>(pagesTag.size());
|
||||
for (BinaryTag pageTag : pagesTag) {
|
||||
pages.add(FilteredText.STRING_NBT_TYPE.read(pageTag));
|
||||
}
|
||||
return new WritableBookContent(pages);
|
||||
}
|
||||
};
|
||||
|
||||
public WritableBookContent {
|
||||
pages = List.copyOf(pages);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package net.minestom.server.item.component;
|
||||
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.book.FilteredText;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.utils.nbt.BinaryTagSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record WrittenBookContent(@NotNull List<FilteredText<Component>> pages, @NotNull FilteredText<String> title, @NotNull String author, int generation, boolean resolved) {
|
||||
public static final WrittenBookContent EMPTY = new WrittenBookContent(List.of(), new FilteredText<>("", null), "", 0, true);
|
||||
|
||||
public static final @NotNull NetworkBuffer.Type<WrittenBookContent> NETWORK_TYPE = new NetworkBuffer.Type<>() {
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer buffer, WrittenBookContent value) {
|
||||
buffer.write(FilteredText.STRING_NETWORK_TYPE, value.title);
|
||||
buffer.write(NetworkBuffer.STRING, value.author);
|
||||
buffer.write(NetworkBuffer.VAR_INT, value.generation);
|
||||
buffer.writeCollection(FilteredText.COMPONENT_NETWORK_TYPE, value.pages);
|
||||
buffer.write(NetworkBuffer.BOOLEAN, value.resolved);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrittenBookContent read(@NotNull NetworkBuffer buffer) {
|
||||
FilteredText<String> title = buffer.read(FilteredText.STRING_NETWORK_TYPE);
|
||||
String author = buffer.read(NetworkBuffer.STRING);
|
||||
int generation = buffer.read(NetworkBuffer.VAR_INT);
|
||||
List<FilteredText<Component>> pages = buffer.readCollection(FilteredText.COMPONENT_NETWORK_TYPE, 100);
|
||||
boolean resolved = buffer.read(NetworkBuffer.BOOLEAN);
|
||||
return new WrittenBookContent(pages, title, author, generation, resolved);
|
||||
}
|
||||
};
|
||||
|
||||
public static final @NotNull BinaryTagSerializer<WrittenBookContent> NBT_TYPE = BinaryTagSerializer.COMPOUND.map(
|
||||
compound -> {
|
||||
ListBinaryTag pagesTag = compound.getList("pages");
|
||||
List<FilteredText<Component>> pages = pagesTag.stream()
|
||||
.map(FilteredText.COMPONENT_NBT_TYPE::read)
|
||||
.toList();
|
||||
FilteredText<String> title = FilteredText.STRING_NBT_TYPE.read(compound.get("title"));
|
||||
String author = compound.getString("author");
|
||||
int generation = compound.getInt("generation");
|
||||
boolean resolved = compound.getBoolean("resolved");
|
||||
return new WrittenBookContent(pages, title, author, generation, resolved);
|
||||
},
|
||||
value -> {
|
||||
ListBinaryTag.Builder<BinaryTag> pagesTag = ListBinaryTag.builder();
|
||||
for (FilteredText<Component> page : value.pages) {
|
||||
pagesTag.add(FilteredText.COMPONENT_NBT_TYPE.write(page));
|
||||
}
|
||||
return CompoundBinaryTag.builder()
|
||||
.put("pages", pagesTag.build())
|
||||
.put("title", FilteredText.STRING_NBT_TYPE.write(value.title))
|
||||
.putString("author", value.author)
|
||||
.putInt("generation", value.generation)
|
||||
.putBoolean("resolved", value.resolved)
|
||||
.build();
|
||||
}
|
||||
);
|
||||
|
||||
public WrittenBookContent {
|
||||
pages = List.copyOf(pages);
|
||||
}
|
||||
|
||||
public WrittenBookContent(@NotNull List<Component> pages, @NotNull String title, @NotNull String author, int generation, boolean resolved) {
|
||||
this(pages.stream().map(page -> new FilteredText<>(page, null)).toList(), new FilteredText<>(title, null), author, generation, resolved);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import net.kyori.adventure.nbt.*;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class BinaryTagUtil {
|
||||
@ -54,6 +55,10 @@ public final class BinaryTagUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable String getStringOrNull(@NotNull CompoundBinaryTag tag, @NotNull String key) {
|
||||
return tag.keySet().contains(key) ? tag.getString(key) : null;
|
||||
}
|
||||
|
||||
private BinaryTagUtil() {
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user