From 308dbe0fdb922860140ca4568a304b8b1bd234f3 Mon Sep 17 00:00:00 2001 From: themode Date: Wed, 31 Mar 2021 16:50:08 +0200 Subject: [PATCH 01/77] Initial item api rework --- .../java/net/minestom/server/item/Item.java | 64 +++++++++++++++++++ .../net/minestom/server/item/ItemBuilder.java | 45 +++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/main/java/net/minestom/server/item/Item.java create mode 100644 src/main/java/net/minestom/server/item/ItemBuilder.java diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java new file mode 100644 index 000000000..9b5cb2b3d --- /dev/null +++ b/src/main/java/net/minestom/server/item/Item.java @@ -0,0 +1,64 @@ +package net.minestom.server.item; + +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.IntUnaryOperator; + +public class Item { + + private final Material material; + private final int amount; + private final Component displayName; + private final List lore; + + protected Item(Material material, int amount, Component displayName, List lore) { + this.material = material; + this.amount = amount; + this.displayName = displayName; + this.lore = lore; + } + + @NotNull + public static ItemBuilder builder(@NotNull Material material) { + return new ItemBuilder(material); + } + + public ItemBuilder builder() { + return new ItemBuilder(material) + .amount(amount) + .displayName(displayName) + .lore(lore); + } + + @NotNull + public Item with(@NotNull Consumer builderConsumer) { + var builder = builder(); + builderConsumer.accept(builder); + return builder.build(); + } + + public int getAmount() { + return amount; + } + + @NotNull + public Item withAmount(int amount) { + return builder().amount(amount).build(); + } + + @NotNull + public Item withAmount(@NotNull IntUnaryOperator intUnaryOperator) { + return withAmount(intUnaryOperator.applyAsInt(amount)); + } + + public Component getDisplayName() { + return displayName; + } + + public List getLore() { + return lore; + } +} diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java new file mode 100644 index 000000000..b707d1af2 --- /dev/null +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -0,0 +1,45 @@ +package net.minestom.server.item; + +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class ItemBuilder { + + private int amount; + private Component displayName; + private List lore; + + protected ItemBuilder(@NotNull Material material) { + + } + + public ItemBuilder amount(int amount) { + this.amount = amount; + return this; + } + + public ItemBuilder displayName(Component displayName) { + this.displayName = displayName; + return this; + } + + public ItemBuilder lore(Component... lore) { + this.lore = Arrays.asList(lore); + return this; + } + + public ItemBuilder lore(List lore) { + this.lore = Collections.unmodifiableList(lore); + return this; + } + + @NotNull + public Item build() { + return null; // TODO + } + +} From cba09e6a269500809eec1199dd073cf0d8a6fa8e Mon Sep 17 00:00:00 2001 From: themode Date: Wed, 31 Mar 2021 16:58:07 +0200 Subject: [PATCH 02/77] Reuse lore code --- src/main/java/net/minestom/server/item/ItemBuilder.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index b707d1af2..6c99c9136 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -27,16 +27,15 @@ public class ItemBuilder { return this; } - public ItemBuilder lore(Component... lore) { - this.lore = Arrays.asList(lore); - return this; - } - public ItemBuilder lore(List lore) { this.lore = Collections.unmodifiableList(lore); return this; } + public ItemBuilder lore(Component... lore) { + return lore(Arrays.asList(lore)); + } + @NotNull public Item build() { return null; // TODO From e66fdee4b13d7dabd5d172da12a05a3ac7e40a0d Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 1 Apr 2021 00:09:02 +0200 Subject: [PATCH 03/77] More methods & annotation --- .../java/net/minestom/server/item/Item.java | 28 ++++++++++++++++++- .../net/minestom/server/item/ItemBuilder.java | 10 +++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java index 9b5cb2b3d..08fce86b4 100644 --- a/src/main/java/net/minestom/server/item/Item.java +++ b/src/main/java/net/minestom/server/item/Item.java @@ -2,10 +2,12 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.Consumer; import java.util.function.IntUnaryOperator; +import java.util.function.UnaryOperator; public class Item { @@ -14,7 +16,8 @@ public class Item { private final Component displayName; private final List lore; - protected Item(Material material, int amount, Component displayName, List lore) { + protected Item(@NotNull Material material, int amount, + @Nullable Component displayName, @Nullable List lore) { this.material = material; this.amount = amount; this.displayName = displayName; @@ -26,6 +29,7 @@ public class Item { return new ItemBuilder(material); } + @NotNull public ItemBuilder builder() { return new ItemBuilder(material) .amount(amount) @@ -54,11 +58,33 @@ public class Item { return withAmount(intUnaryOperator.applyAsInt(amount)); } + @Nullable public Component getDisplayName() { return displayName; } + @NotNull + public Item withDisplayName(@Nullable Component displayName) { + return builder().displayName(displayName).build(); + } + + @NotNull + public Item withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) { + return withDisplayName(componentUnaryOperator.apply(displayName)); + } + + @Nullable public List getLore() { return lore; } + + @NotNull + public Item withLore(@Nullable List<@NotNull Component> lore) { + return builder().lore(lore).build(); + } + + @NotNull + public Item withLore(@NotNull UnaryOperator<@Nullable List> loreUnaryOperator) { + return withLore(loreUnaryOperator.apply(lore)); + } } diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index 6c99c9136..6d4076767 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -9,36 +9,42 @@ import java.util.List; public class ItemBuilder { + private final Material material; private int amount; private Component displayName; private List lore; protected ItemBuilder(@NotNull Material material) { - + this.material = material; + this.amount = 0; } + @NotNull public ItemBuilder amount(int amount) { this.amount = amount; return this; } + @NotNull public ItemBuilder displayName(Component displayName) { this.displayName = displayName; return this; } + @NotNull public ItemBuilder lore(List lore) { this.lore = Collections.unmodifiableList(lore); return this; } + @NotNull public ItemBuilder lore(Component... lore) { return lore(Arrays.asList(lore)); } @NotNull public Item build() { - return null; // TODO + return new Item(material, amount, displayName, lore); } } From 5807da47a676e592d6f6847f9479c2304eae5782 Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 1 Apr 2021 00:20:59 +0200 Subject: [PATCH 04/77] Update annotations + add example --- .../java/net/minestom/server/item/Item.java | 43 +++++++++---------- .../net/minestom/server/item/ItemBuilder.java | 22 +++++----- src/test/java/demo/PlayerInit.java | 13 ++++++ 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java index 08fce86b4..5446e2a9c 100644 --- a/src/main/java/net/minestom/server/item/Item.java +++ b/src/main/java/net/minestom/server/item/Item.java @@ -1,6 +1,7 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -24,21 +25,21 @@ public class Item { this.lore = lore; } - @NotNull - public static ItemBuilder builder(@NotNull Material material) { + @Contract(value = "_ -> new", pure = true) + public static @NotNull ItemBuilder builder(@NotNull Material material) { return new ItemBuilder(material); } - @NotNull - public ItemBuilder builder() { + @Contract(value = "-> new", pure = true) + public @NotNull ItemBuilder builder() { return new ItemBuilder(material) .amount(amount) .displayName(displayName) .lore(lore); } - @NotNull - public Item with(@NotNull Consumer builderConsumer) { + @Contract(value = "_, -> new", pure = true) + public @NotNull Item with(@NotNull Consumer builderConsumer) { var builder = builder(); builderConsumer.accept(builder); return builder.build(); @@ -48,43 +49,41 @@ public class Item { return amount; } - @NotNull - public Item withAmount(int amount) { + @Contract(value = "_, -> new", pure = true) + public @NotNull Item withAmount(int amount) { return builder().amount(amount).build(); } - @NotNull - public Item withAmount(@NotNull IntUnaryOperator intUnaryOperator) { + @Contract(value = "_, -> new", pure = true) + public @NotNull Item withAmount(@NotNull IntUnaryOperator intUnaryOperator) { return withAmount(intUnaryOperator.applyAsInt(amount)); } - @Nullable - public Component getDisplayName() { + public @Nullable Component getDisplayName() { return displayName; } - @NotNull - public Item withDisplayName(@Nullable Component displayName) { + @Contract(value = "_, -> new", pure = true) + public @NotNull Item withDisplayName(@Nullable Component displayName) { return builder().displayName(displayName).build(); } - @NotNull - public Item withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) { + @Contract(value = "_, -> new", pure = true) + public @NotNull Item withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) { return withDisplayName(componentUnaryOperator.apply(displayName)); } - @Nullable - public List getLore() { + public @Nullable List<@NotNull Component> getLore() { return lore; } - @NotNull - public Item withLore(@Nullable List<@NotNull Component> lore) { + @Contract(value = "_, -> new", pure = true) + public @NotNull Item withLore(@Nullable List<@NotNull Component> lore) { return builder().lore(lore).build(); } - @NotNull - public Item withLore(@NotNull UnaryOperator<@Nullable List> loreUnaryOperator) { + @Contract(value = "_, -> new", pure = true) + public @NotNull Item withLore(@NotNull UnaryOperator<@Nullable List<@NotNull Component>> loreUnaryOperator) { return withLore(loreUnaryOperator.apply(lore)); } } diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index 6d4076767..048ae7a64 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -1,7 +1,9 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.Collections; @@ -19,31 +21,31 @@ public class ItemBuilder { this.amount = 0; } - @NotNull - public ItemBuilder amount(int amount) { + @Contract(value = "_ -> this") + public @NotNull ItemBuilder amount(int amount) { this.amount = amount; return this; } - @NotNull - public ItemBuilder displayName(Component displayName) { + @Contract(value = "_ -> this") + public @NotNull ItemBuilder displayName(@Nullable Component displayName) { this.displayName = displayName; return this; } - @NotNull - public ItemBuilder lore(List lore) { + @Contract(value = "_ -> this") + public @NotNull ItemBuilder lore(List<@NotNull Component> lore) { this.lore = Collections.unmodifiableList(lore); return this; } - @NotNull - public ItemBuilder lore(Component... lore) { + @Contract(value = "_ -> this") + public @NotNull ItemBuilder lore(Component... lore) { return lore(Arrays.asList(lore)); } - @NotNull - public Item build() { + @Contract(value = "-> new", pure = true) + public @NotNull Item build() { return new Item(material, amount, displayName, lore); } diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 64d50e014..f3931c48b 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -26,6 +26,7 @@ import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.PlayerInventory; +import net.minestom.server.item.Item; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.network.ConnectionManager; @@ -62,6 +63,18 @@ public class PlayerInit { inventoryConditionResult.setCancel(slot == 3); });*/ //inventory.setItemStack(3, new ItemStack(Material.DIAMOND, (byte) 34)); + + { + Item item = Item.builder(Material.STONE) + .amount(5) + .displayName(Component.text("displayName")) + .build(); + + item = item.with(itemBuilder -> itemBuilder + .amount(10) + .lore(Component.text("Lore"))); + } + } public static void init() { From 70191e23e9ec04c0cc1e710df014dd33f38a819f Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 1 Apr 2021 00:32:21 +0200 Subject: [PATCH 05/77] Even more annotations --- src/main/java/net/minestom/server/item/Item.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java index 5446e2a9c..74957d5d4 100644 --- a/src/main/java/net/minestom/server/item/Item.java +++ b/src/main/java/net/minestom/server/item/Item.java @@ -39,12 +39,13 @@ public class Item { } @Contract(value = "_, -> new", pure = true) - public @NotNull Item with(@NotNull Consumer builderConsumer) { + public @NotNull Item with(@NotNull Consumer<@NotNull ItemBuilder> builderConsumer) { var builder = builder(); builderConsumer.accept(builder); return builder.build(); } + @Contract(pure = true) public int getAmount() { return amount; } @@ -59,6 +60,7 @@ public class Item { return withAmount(intUnaryOperator.applyAsInt(amount)); } + @Contract(pure = true) public @Nullable Component getDisplayName() { return displayName; } @@ -73,6 +75,7 @@ public class Item { return withDisplayName(componentUnaryOperator.apply(displayName)); } + @Contract(pure = true) public @Nullable List<@NotNull Component> getLore() { return lore; } From 0ab66113c8926a293947c9d4f4b4484532840cef Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 1 Apr 2021 19:08:21 +0200 Subject: [PATCH 06/77] WIP item meta API --- src/main/java/net/minestom/server/item/Item.java | 6 ++++++ .../java/net/minestom/server/item/ItemBuilder.java | 8 ++++++++ .../net/minestom/server/item/ItemMetaBuilder.java | 5 +++++ src/test/java/demo/PlayerInit.java | 13 ++++++++++++- 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/minestom/server/item/ItemMetaBuilder.java diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java index 74957d5d4..4f7d2a3ea 100644 --- a/src/main/java/net/minestom/server/item/Item.java +++ b/src/main/java/net/minestom/server/item/Item.java @@ -1,6 +1,7 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; +import net.minestom.server.item.metadata.ItemMeta; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,6 +15,7 @@ public class Item { private final Material material; private final int amount; + //private final ItemMeta meta; private final Component displayName; private final List lore; @@ -60,6 +62,10 @@ public class Item { return withAmount(intUnaryOperator.applyAsInt(amount)); } + public @NotNull Item withMeta(Class metaType, Consumer metaConsumer) { + return builder().meta(metaType, metaConsumer).build(); + } + @Contract(pure = true) public @Nullable Component getDisplayName() { return displayName; diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index 048ae7a64..36aaa5f6b 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -1,6 +1,7 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; +import net.minestom.server.item.metadata.ItemMeta; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -8,6 +9,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.function.Consumer; public class ItemBuilder { @@ -27,6 +29,12 @@ public class ItemBuilder { return this; } + @Contract(value = "_, _ -> this") + public @NotNull ItemBuilder meta(Class metaType, Consumer metaConsumer) { + // TODO + return this; + } + @Contract(value = "_ -> this") public @NotNull ItemBuilder displayName(@Nullable Component displayName) { this.displayName = displayName; diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java new file mode 100644 index 000000000..5a9cde88b --- /dev/null +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -0,0 +1,5 @@ +package net.minestom.server.item; + +public class ItemMetaBuilder { + +} diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index f3931c48b..b37ad564b 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -29,6 +29,7 @@ import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.Item; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.item.metadata.WritableBookMeta; import net.minestom.server.network.ConnectionManager; import net.minestom.server.ping.ResponseDataConsumer; import net.minestom.server.utils.Position; @@ -65,14 +66,24 @@ public class PlayerInit { //inventory.setItemStack(3, new ItemStack(Material.DIAMOND, (byte) 34)); { - Item item = Item.builder(Material.STONE) + Item item = Item.builder(Material.WRITABLE_BOOK) .amount(5) + .meta(WritableBookMeta.class, writableBookMeta -> { + writableBookMeta.setTitle("Title"); + }) .displayName(Component.text("displayName")) .build(); item = item.with(itemBuilder -> itemBuilder .amount(10) + .meta(WritableBookMeta.class, writableBookMeta -> { + writableBookMeta.setTitle("Title2"); + }) .lore(Component.text("Lore"))); + + item = item.withMeta(WritableBookMeta.class, writableBookMeta -> { + writableBookMeta.setTitle("Title3"); + }); } } From cbfeb4e15b59d07ad86c15433ea27ee578b1ff07 Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 1 Apr 2021 20:02:03 +0200 Subject: [PATCH 07/77] WIP meta support --- .../java/net/minestom/server/item/Item.java | 28 +++----- .../net/minestom/server/item/ItemBuilder.java | 28 ++++---- .../net/minestom/server/item/ItemMeta.java | 35 ++++++++++ .../minestom/server/item/ItemMetaBuilder.java | 41 ++++++++++- .../server/item/meta/CompassMeta.java | 68 +++++++++++++++++++ src/test/java/demo/PlayerInit.java | 16 ++--- 6 files changed, 176 insertions(+), 40 deletions(-) create mode 100644 src/main/java/net/minestom/server/item/ItemMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/CompassMeta.java diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java index 4f7d2a3ea..044b97bc9 100644 --- a/src/main/java/net/minestom/server/item/Item.java +++ b/src/main/java/net/minestom/server/item/Item.java @@ -1,7 +1,6 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; -import net.minestom.server.item.metadata.ItemMeta; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,16 +14,12 @@ public class Item { private final Material material; private final int amount; - //private final ItemMeta meta; - private final Component displayName; - private final List lore; + private final ItemMeta meta; - protected Item(@NotNull Material material, int amount, - @Nullable Component displayName, @Nullable List lore) { + protected Item(@NotNull Material material, int amount, ItemMeta meta) { this.material = material; this.amount = amount; - this.displayName = displayName; - this.lore = lore; + this.meta = meta; } @Contract(value = "_ -> new", pure = true) @@ -34,10 +29,8 @@ public class Item { @Contract(value = "-> new", pure = true) public @NotNull ItemBuilder builder() { - return new ItemBuilder(material) - .amount(amount) - .displayName(displayName) - .lore(lore); + return new ItemBuilder(material, meta.builder()) + .amount(amount); } @Contract(value = "_, -> new", pure = true) @@ -62,13 +55,14 @@ public class Item { return withAmount(intUnaryOperator.applyAsInt(amount)); } - public @NotNull Item withMeta(Class metaType, Consumer metaConsumer) { + @Contract(value = "_, _ -> new", pure = true) + public @NotNull Item withMeta(Class metaType, Consumer metaConsumer) { return builder().meta(metaType, metaConsumer).build(); } @Contract(pure = true) public @Nullable Component getDisplayName() { - return displayName; + return meta.getDisplayName(); } @Contract(value = "_, -> new", pure = true) @@ -78,12 +72,12 @@ public class Item { @Contract(value = "_, -> new", pure = true) public @NotNull Item withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) { - return withDisplayName(componentUnaryOperator.apply(displayName)); + return withDisplayName(componentUnaryOperator.apply(getDisplayName())); } @Contract(pure = true) public @Nullable List<@NotNull Component> getLore() { - return lore; + return meta.getLore(); } @Contract(value = "_, -> new", pure = true) @@ -93,6 +87,6 @@ public class Item { @Contract(value = "_, -> new", pure = true) public @NotNull Item withLore(@NotNull UnaryOperator<@Nullable List<@NotNull Component>> loreUnaryOperator) { - return withLore(loreUnaryOperator.apply(lore)); + return withLore(loreUnaryOperator.apply(getLore())); } } diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index 36aaa5f6b..2c7781d3c 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -1,13 +1,11 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; -import net.minestom.server.item.metadata.ItemMeta; +import net.minestom.server.item.meta.CompassMeta; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.function.Consumer; @@ -15,12 +13,17 @@ public class ItemBuilder { private final Material material; private int amount; - private Component displayName; - private List lore; + protected ItemMetaBuilder metaBuilder; - protected ItemBuilder(@NotNull Material material) { + protected ItemBuilder(@NotNull Material material, @NotNull ItemMetaBuilder metaBuilder) { this.material = material; this.amount = 0; + this.metaBuilder=metaBuilder; + } + + protected ItemBuilder(@NotNull Material material) { + // TODO: meta depends on material + this(material, new CompassMeta.Builder()); } @Contract(value = "_ -> this") @@ -30,31 +33,32 @@ public class ItemBuilder { } @Contract(value = "_, _ -> this") - public @NotNull ItemBuilder meta(Class metaType, Consumer metaConsumer) { - // TODO + public @NotNull ItemBuilder meta(Class metaType, Consumer itemMetaConsumer) { + itemMetaConsumer.accept((T) metaBuilder); return this; } @Contract(value = "_ -> this") public @NotNull ItemBuilder displayName(@Nullable Component displayName) { - this.displayName = displayName; + this.metaBuilder.displayName(displayName); return this; } @Contract(value = "_ -> this") public @NotNull ItemBuilder lore(List<@NotNull Component> lore) { - this.lore = Collections.unmodifiableList(lore); + this.metaBuilder.lore(lore); return this; } @Contract(value = "_ -> this") public @NotNull ItemBuilder lore(Component... lore) { - return lore(Arrays.asList(lore)); + this.metaBuilder.lore(lore); + return this; } @Contract(value = "-> new", pure = true) public @NotNull Item build() { - return new Item(material, amount, displayName, lore); + return new Item(material, amount, metaBuilder.build()); } } diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java new file mode 100644 index 000000000..5a14f12fb --- /dev/null +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -0,0 +1,35 @@ +package net.minestom.server.item; + +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class ItemMeta implements Cloneable { + + private final ItemMetaBuilder builder; + private final Component displayName; + private final List lore; + + protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { + this.builder = metaBuilder.clone(); + this.displayName = metaBuilder.displayName; + this.lore = metaBuilder.lore; + } + + @Contract(pure = true) + public @Nullable Component getDisplayName() { + return displayName; + } + + @Contract(pure = true) + public @Nullable List<@NotNull Component> getLore() { + return lore; + } + + protected @NotNull ItemMetaBuilder builder() { + return builder.clone(); + } +} diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 5a9cde88b..4475b644b 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -1,5 +1,44 @@ package net.minestom.server.item; -public class ItemMetaBuilder { +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public abstract class ItemMetaBuilder implements Cloneable { + + protected Component displayName; + protected List lore; + + public void displayName(@Nullable Component displayName) { + this.displayName = displayName; + } + + public void lore(List<@NotNull Component> lore) { + this.lore = Collections.unmodifiableList(lore); + } + + public void lore(Component... lore) { + lore(Arrays.asList(lore)); + } + + public abstract @NotNull ItemMeta build(); + + protected abstract void deepClone(@NotNull ItemMetaBuilder metaBuilder); + + @Override + protected ItemMetaBuilder clone() { + try { + var builder = (ItemMetaBuilder) super.clone(); + deepClone(builder); + return builder; + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + throw new UnsupportedOperationException("Weird thing happened"); + } + } } diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/meta/CompassMeta.java new file mode 100644 index 000000000..ffb218c3b --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/CompassMeta.java @@ -0,0 +1,68 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import net.minestom.server.utils.Position; +import org.jetbrains.annotations.NotNull; + +public class CompassMeta extends ItemMeta { + + private final boolean lodestoneTracked; + private final String lodestoneDimension; + private final Position lodestonePosition; + + protected CompassMeta(ItemMetaBuilder metaBuilder, + boolean lodestoneTracked, String lodestoneDimension, Position lodestonePosition) { + super(metaBuilder); + this.lodestoneTracked = lodestoneTracked; + this.lodestoneDimension = lodestoneDimension; + this.lodestonePosition = lodestonePosition; + } + + public boolean isLodestoneTracked() { + return lodestoneTracked; + } + + public String getLodestoneDimension() { + return lodestoneDimension; + } + + public Position getLodestonePosition() { + return lodestonePosition; + } + + public static class Builder extends ItemMetaBuilder { + + private boolean lodestoneTracked; + private String lodestoneDimension; + private Position lodestonePosition; + + public Builder lodestoneTracked(boolean lodestoneTracked) { + this.lodestoneTracked = lodestoneTracked; + return this; + } + + public Builder lodestoneDimension(String lodestoneDimension) { + this.lodestoneDimension = lodestoneDimension; + return this; + } + + public Builder lodestonePosition(Position lodestonePosition) { + this.lodestonePosition = lodestonePosition; + return this; + } + + @Override + public @NotNull CompassMeta build() { + return new CompassMeta(this, lodestoneTracked, lodestoneDimension, lodestonePosition); + } + + @Override + protected void deepClone(@NotNull ItemMetaBuilder metaBuilder) { + var compassBuilder = (CompassMeta.Builder) metaBuilder; + compassBuilder.lodestoneTracked = lodestoneTracked; + compassBuilder.lodestoneDimension = lodestoneDimension; + compassBuilder.lodestonePosition = lodestonePosition; + } + } +} diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index b37ad564b..12c0f2d25 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -29,7 +29,7 @@ import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.Item; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.minestom.server.item.metadata.WritableBookMeta; +import net.minestom.server.item.meta.CompassMeta; import net.minestom.server.network.ConnectionManager; import net.minestom.server.ping.ResponseDataConsumer; import net.minestom.server.utils.Position; @@ -66,24 +66,20 @@ public class PlayerInit { //inventory.setItemStack(3, new ItemStack(Material.DIAMOND, (byte) 34)); { - Item item = Item.builder(Material.WRITABLE_BOOK) + Item item = Item.builder(Material.COMPASS) .amount(5) - .meta(WritableBookMeta.class, writableBookMeta -> { - writableBookMeta.setTitle("Title"); + .meta(CompassMeta.Builder.class, builder -> { + builder.lodestonePosition(new Position(0, 0, 0)); }) .displayName(Component.text("displayName")) .build(); item = item.with(itemBuilder -> itemBuilder .amount(10) - .meta(WritableBookMeta.class, writableBookMeta -> { - writableBookMeta.setTitle("Title2"); + .meta(CompassMeta.Builder.class, builder -> { + builder.lodestonePosition(new Position(5, 0, 0)); }) .lore(Component.text("Lore"))); - - item = item.withMeta(WritableBookMeta.class, writableBookMeta -> { - writableBookMeta.setTitle("Title3"); - }); } } From 066b041bba8b8694e8e954abe024c83408332dbe Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 1 Apr 2021 20:06:10 +0200 Subject: [PATCH 08/77] Allow to directly pass an ItemMeta --- src/main/java/net/minestom/server/item/ItemBuilder.java | 8 +++++++- src/test/java/demo/PlayerInit.java | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index 2c7781d3c..6ab8e1d46 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -18,7 +18,7 @@ public class ItemBuilder { protected ItemBuilder(@NotNull Material material, @NotNull ItemMetaBuilder metaBuilder) { this.material = material; this.amount = 0; - this.metaBuilder=metaBuilder; + this.metaBuilder = metaBuilder; } protected ItemBuilder(@NotNull Material material) { @@ -32,6 +32,12 @@ public class ItemBuilder { return this; } + @Contract(value = "_ -> this") + public @NotNull ItemBuilder meta(@NotNull ItemMeta itemMeta) { + this.metaBuilder = itemMeta.builder(); + return this; + } + @Contract(value = "_, _ -> this") public @NotNull ItemBuilder meta(Class metaType, Consumer itemMetaConsumer) { itemMetaConsumer.accept((T) metaBuilder); diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 12c0f2d25..8cd6121a6 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -66,8 +66,14 @@ public class PlayerInit { //inventory.setItemStack(3, new ItemStack(Material.DIAMOND, (byte) 34)); { + + CompassMeta compassMeta = new CompassMeta.Builder() + .lodestonePosition(new Position(0, 0, 0)) + .build(); + Item item = Item.builder(Material.COMPASS) .amount(5) + .meta(compassMeta) .meta(CompassMeta.Builder.class, builder -> { builder.lodestonePosition(new Position(0, 0, 0)); }) From debf21927b616ffb19e55ed11bed5eabca6318b9 Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 1 Apr 2021 20:26:19 +0200 Subject: [PATCH 09/77] Change Item#builder visibility --- src/main/java/net/minestom/server/item/Item.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java index 044b97bc9..0ee9f427d 100644 --- a/src/main/java/net/minestom/server/item/Item.java +++ b/src/main/java/net/minestom/server/item/Item.java @@ -27,12 +27,6 @@ public class Item { return new ItemBuilder(material); } - @Contract(value = "-> new", pure = true) - public @NotNull ItemBuilder builder() { - return new ItemBuilder(material, meta.builder()) - .amount(amount); - } - @Contract(value = "_, -> new", pure = true) public @NotNull Item with(@NotNull Consumer<@NotNull ItemBuilder> builderConsumer) { var builder = builder(); @@ -89,4 +83,10 @@ public class Item { public @NotNull Item withLore(@NotNull UnaryOperator<@Nullable List<@NotNull Component>> loreUnaryOperator) { return withLore(loreUnaryOperator.apply(getLore())); } + + @Contract(value = "-> new", pure = true) + protected @NotNull ItemBuilder builder() { + return new ItemBuilder(material, meta.builder()) + .amount(amount); + } } From 3ba74639bfe5d97fae6f472d73fcd26b4d6beb27 Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 1 Apr 2021 22:28:32 +0200 Subject: [PATCH 10/77] Added Item#getUuid --- src/main/java/net/minestom/server/item/Item.java | 12 ++++++++++++ src/main/java/net/minestom/server/item/ItemMeta.java | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java index 0ee9f427d..2123dbe76 100644 --- a/src/main/java/net/minestom/server/item/Item.java +++ b/src/main/java/net/minestom/server/item/Item.java @@ -6,12 +6,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.UUID; import java.util.function.Consumer; import java.util.function.IntUnaryOperator; import java.util.function.UnaryOperator; public class Item { + private final UUID uuid = UUID.randomUUID(); private final Material material; private final int amount; private final ItemMeta meta; @@ -27,6 +29,16 @@ public class Item { return new ItemBuilder(material); } + @Contract(pure = true) + public @NotNull UUID getUuid() { + return uuid; + } + + @Contract(pure = true) + public @NotNull Material getMaterial() { + return material; + } + @Contract(value = "_, -> new", pure = true) public @NotNull Item with(@NotNull Consumer<@NotNull ItemBuilder> builderConsumer) { var builder = builder(); diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 5a14f12fb..9bfff624f 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.function.Consumer; public class ItemMeta implements Cloneable { @@ -19,6 +20,13 @@ public class ItemMeta implements Cloneable { this.lore = metaBuilder.lore; } + @Contract(value = "_, -> new", pure = true) + public @NotNull ItemMeta with(@NotNull Consumer<@NotNull ItemMetaBuilder> builderConsumer) { + var builder = builder(); + builderConsumer.accept(builder); + return builder.build(); + } + @Contract(pure = true) public @Nullable Component getDisplayName() { return displayName; From 042c7c864b75e9a0fe721ff7fb1c97e6c2efad15 Mon Sep 17 00:00:00 2001 From: themode Date: Thu, 1 Apr 2021 22:52:28 +0200 Subject: [PATCH 11/77] Added covariant return type + enchantment --- .../minestom/server/item/ItemMetaBuilder.java | 34 +++++++++++--- .../server/item/meta/CompassMeta.java | 44 +++++++++++++++++++ src/test/java/demo/PlayerInit.java | 4 +- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 4475b644b..017cde45e 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -4,25 +4,45 @@ import net.kyori.adventure.text.Component; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; public abstract class ItemMetaBuilder implements Cloneable { protected Component displayName; protected List lore; + protected Map enchantmentMap = new HashMap<>(); - public void displayName(@Nullable Component displayName) { + protected ItemMetaBuilder() { + } + + public @NotNull ItemMetaBuilder displayName(@Nullable Component displayName) { this.displayName = displayName; + return this; } - public void lore(List<@NotNull Component> lore) { + public @NotNull ItemMetaBuilder lore(List<@NotNull Component> lore) { this.lore = Collections.unmodifiableList(lore); + return this; } - public void lore(Component... lore) { + public @NotNull ItemMetaBuilder lore(Component... lore) { lore(Arrays.asList(lore)); + return this; + } + + public @NotNull ItemMetaBuilder enchantments(@NotNull Map enchantments) { + this.enchantmentMap.putAll(enchantments); + return this; + } + + public @NotNull ItemMetaBuilder enchantment(@NotNull Enchantment enchantment, short level) { + this.enchantmentMap.put(enchantment, level); + return this; + } + + public @NotNull ItemMetaBuilder clearEnchantment() { + this.enchantmentMap.clear(); + return this; } public abstract @NotNull ItemMeta build(); @@ -33,6 +53,8 @@ public abstract class ItemMetaBuilder implements Cloneable { protected ItemMetaBuilder clone() { try { var builder = (ItemMetaBuilder) super.clone(); + builder.displayName = displayName; + builder.lore = lore; deepClone(builder); return builder; } catch (CloneNotSupportedException e) { diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/meta/CompassMeta.java index ffb218c3b..92c98a2fd 100644 --- a/src/main/java/net/minestom/server/item/meta/CompassMeta.java +++ b/src/main/java/net/minestom/server/item/meta/CompassMeta.java @@ -1,9 +1,15 @@ package net.minestom.server.item.meta; +import net.kyori.adventure.text.Component; +import net.minestom.server.item.Enchantment; import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemMetaBuilder; import net.minestom.server.utils.Position; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; public class CompassMeta extends ItemMeta { @@ -52,6 +58,44 @@ public class CompassMeta extends ItemMeta { return this; } + @Override + public @NotNull Builder displayName(@Nullable Component displayName) { + super.displayName(displayName); + return this; + } + + @Override + public @NotNull Builder lore(List<@NotNull Component> lore) { + super.lore(lore); + return this; + + } + + @Override + public @NotNull Builder lore(Component... lore) { + super.lore(lore); + return this; + } + + @Override + public @NotNull Builder enchantments(@NotNull Map enchantments) { + super.enchantments(enchantments); + return this; + + } + + @Override + public @NotNull Builder enchantment(@NotNull Enchantment enchantment, short level) { + super.enchantment(enchantment, level); + return this; + } + + @Override + public @NotNull Builder clearEnchantment() { + super.clearEnchantment(); + return this; + } + @Override public @NotNull CompassMeta build() { return new CompassMeta(this, lodestoneTracked, lodestoneDimension, lodestonePosition); diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 8cd6121a6..8df5d5cca 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -26,6 +26,7 @@ import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.PlayerInventory; +import net.minestom.server.item.Enchantment; import net.minestom.server.item.Item; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; @@ -39,6 +40,7 @@ import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.world.DimensionType; import java.util.Collection; +import java.util.Map; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -66,9 +68,9 @@ public class PlayerInit { //inventory.setItemStack(3, new ItemStack(Material.DIAMOND, (byte) 34)); { - CompassMeta compassMeta = new CompassMeta.Builder() .lodestonePosition(new Position(0, 0, 0)) + .enchantments(Map.of(Enchantment.KNOCKBACK, (short) 5, Enchantment.EFFICIENCY, (short) 10)) .build(); Item item = Item.builder(Material.COMPASS) From cf0450f21fca979e8dbd23118b3547611f071b5a Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 14:02:24 +0200 Subject: [PATCH 12/77] Only make immutable lists when built --- src/main/java/net/minestom/server/item/ItemMeta.java | 3 ++- src/main/java/net/minestom/server/item/ItemMetaBuilder.java | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 9bfff624f..cf4c41ba5 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.List; import java.util.function.Consumer; @@ -17,7 +18,7 @@ public class ItemMeta implements Cloneable { protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { this.builder = metaBuilder.clone(); this.displayName = metaBuilder.displayName; - this.lore = metaBuilder.lore; + this.lore = Collections.unmodifiableList(metaBuilder.lore); } @Contract(value = "_, -> new", pure = true) diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 017cde45e..9c23cdf4a 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -21,7 +21,7 @@ public abstract class ItemMetaBuilder implements Cloneable { } public @NotNull ItemMetaBuilder lore(List<@NotNull Component> lore) { - this.lore = Collections.unmodifiableList(lore); + this.lore = lore; return this; } @@ -54,7 +54,8 @@ public abstract class ItemMetaBuilder implements Cloneable { try { var builder = (ItemMetaBuilder) super.clone(); builder.displayName = displayName; - builder.lore = lore; + builder.lore = new ArrayList<>(lore); + builder.enchantmentMap = new HashMap<>(enchantmentMap); deepClone(builder); return builder; } catch (CloneNotSupportedException e) { From a70870d261006fcb15e8371c105f7421f419833a Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 15:42:58 +0200 Subject: [PATCH 13/77] Added ItemMetaBuilder.Provider --- src/main/java/net/minestom/server/item/Item.java | 2 +- src/main/java/net/minestom/server/item/ItemBuilder.java | 2 +- src/main/java/net/minestom/server/item/ItemMetaBuilder.java | 3 +++ src/main/java/net/minestom/server/item/meta/CompassMeta.java | 2 +- src/test/java/demo/PlayerInit.java | 4 ++-- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java index 2123dbe76..065481bfa 100644 --- a/src/main/java/net/minestom/server/item/Item.java +++ b/src/main/java/net/minestom/server/item/Item.java @@ -62,7 +62,7 @@ public class Item { } @Contract(value = "_, _ -> new", pure = true) - public @NotNull Item withMeta(Class metaType, Consumer metaConsumer) { + public > @NotNull Item withMeta(Class metaType, Consumer metaConsumer) { return builder().meta(metaType, metaConsumer).build(); } diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index 6ab8e1d46..33f38fa8a 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -39,7 +39,7 @@ public class ItemBuilder { } @Contract(value = "_, _ -> this") - public @NotNull ItemBuilder meta(Class metaType, Consumer itemMetaConsumer) { + public > @NotNull ItemBuilder meta(Class metaType, Consumer itemMetaConsumer) { itemMetaConsumer.accept((T) metaBuilder); return this; } diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 9c23cdf4a..301665141 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -64,4 +64,7 @@ public abstract class ItemMetaBuilder implements Cloneable { } } + public interface Provider { + } + } diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/meta/CompassMeta.java index 92c98a2fd..4651f79d5 100644 --- a/src/main/java/net/minestom/server/item/meta/CompassMeta.java +++ b/src/main/java/net/minestom/server/item/meta/CompassMeta.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -public class CompassMeta extends ItemMeta { +public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider { private final boolean lodestoneTracked; private final String lodestoneDimension; diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 8df5d5cca..974fe977e 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -76,7 +76,7 @@ public class PlayerInit { Item item = Item.builder(Material.COMPASS) .amount(5) .meta(compassMeta) - .meta(CompassMeta.Builder.class, builder -> { + .meta(CompassMeta.class, builder -> { builder.lodestonePosition(new Position(0, 0, 0)); }) .displayName(Component.text("displayName")) @@ -84,7 +84,7 @@ public class PlayerInit { item = item.with(itemBuilder -> itemBuilder .amount(10) - .meta(CompassMeta.Builder.class, builder -> { + .meta(CompassMeta.class, builder -> { builder.lodestonePosition(new Position(5, 0, 0)); }) .lore(Component.text("Lore"))); From a128d30b6b8ffcc606d86f79b90bfa36af8c7130 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 18:13:02 +0200 Subject: [PATCH 14/77] WIP Item rework implementation --- .../entitytypes/EntityTypeContainer.java | 2 +- .../minestom/demo/largeframebuffers/Demo.java | 1 - .../server/advancements/Advancement.java | 4 +- .../server/advancements/AdvancementRoot.java | 1 - .../notifications/Notification.java | 3 +- .../minestom/server/chat/ChatHoverEvent.java | 8 +- .../minecraft/ArgumentItemStack.java | 4 +- .../minestom/server/entity/ItemEntity.java | 2 +- .../minestom/server/entity/LivingEntity.java | 16 +- .../net/minestom/server/entity/Metadata.java | 41 +- .../net/minestom/server/entity/Player.java | 41 +- .../metadata/item/ItemContainingMeta.java | 2 +- .../metadata/other/FireworkRocketMeta.java | 2 +- .../entity/metadata/other/ItemFrameMeta.java | 2 +- .../type/decoration/EntityArmorStand.java | 12 +- .../type/decoration/EntityItemFrame.java | 3 +- .../type/projectile/EntityEyeOfEnder.java | 2 +- .../entity/type/projectile/EntityPotion.java | 2 +- .../ConditionedFunctionWrapper.java | 2 +- .../server/gamedata/loottables/LootTable.java | 18 +- .../loottables/entries/AlternativesEntry.java | 4 +- .../loottables/entries/ItemEntry.java | 4 +- .../loottables/entries/SequenceEntry.java | 4 +- .../gamedata/loottables/entries/TagEntry.java | 12 +- .../minestom/server/inventory/Inventory.java | 19 +- .../server/inventory/PlayerInventory.java | 19 +- .../click/InventoryClickProcessor.java | 42 +- .../java/net/minestom/server/item/Item.java | 104 -- .../net/minestom/server/item/ItemBuilder.java | 6 +- .../net/minestom/server/item/ItemMeta.java | 53 + .../minestom/server/item/ItemMetaBuilder.java | 2 +- .../net/minestom/server/item/ItemStack.java | 946 ++---------------- .../server/item/metadata/CrossbowMeta.java | 16 +- .../server/item/metadata/ItemMeta.java | 1 - .../server/item/metadata/PotionMeta.java | 2 +- .../server/item/rule/VanillaStackingRule.java | 5 +- .../server/listener/AnimationListener.java | 2 +- .../listener/BlockPlacementListener.java | 13 +- .../listener/PlayerDiggingListener.java | 14 +- .../server/listener/UseItemListener.java | 3 +- .../client/play/ClientClickWindowPacket.java | 2 +- .../ClientCreativeInventoryActionPacket.java | 2 +- .../client/play/ClientEditBookPacket.java | 2 +- .../client/play/ClientNameItemPacket.java | 2 +- .../server/play/AdvancementsPacket.java | 15 +- .../server/play/DeclareRecipesPacket.java | 9 +- .../server/play/EntityEquipmentPacket.java | 5 +- .../packet/server/play/SetSlotPacket.java | 2 +- .../packet/server/play/TradeListPacket.java | 2 +- .../minestom/server/recipe/ShapedRecipe.java | 10 +- .../net/minestom/server/utils/NBTUtils.java | 249 ++--- .../server/utils/binary/BinaryReader.java | 6 +- .../server/utils/binary/BinaryWriter.java | 5 +- .../server/world/biomes/BiomeParticles.java | 2 +- src/test/java/demo/PlayerInit.java | 18 +- .../readwritepackets/ReadWritePackets.java | 17 +- 56 files changed, 388 insertions(+), 1399 deletions(-) delete mode 100644 src/main/java/net/minestom/server/item/Item.java diff --git a/src/generators/java/net/minestom/codegen/entitytypes/EntityTypeContainer.java b/src/generators/java/net/minestom/codegen/entitytypes/EntityTypeContainer.java index cdd2a37b2..9732ef965 100644 --- a/src/generators/java/net/minestom/codegen/entitytypes/EntityTypeContainer.java +++ b/src/generators/java/net/minestom/codegen/entitytypes/EntityTypeContainer.java @@ -33,7 +33,7 @@ public class EntityTypeContainer implements Comparable { String metaClassName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name.getPath()); // special cases switch (metaClassName) { - case "Item": + case "ItemStack": metaClassName = "ItemEntity"; break; case "Tnt": diff --git a/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java b/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java index 2e7c3b2b7..2516082d7 100644 --- a/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java +++ b/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java @@ -6,7 +6,6 @@ import net.minestom.server.entity.GameMode; import net.minestom.server.entity.type.decoration.EntityItemFrame; import net.minestom.server.instance.Instance; import net.minestom.server.instance.InstanceManager; -import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.metadata.MapMeta; import net.minestom.server.map.Framebuffer; diff --git a/src/main/java/net/minestom/server/advancements/Advancement.java b/src/main/java/net/minestom/server/advancements/Advancement.java index d16c1a449..2610d0876 100644 --- a/src/main/java/net/minestom/server/advancements/Advancement.java +++ b/src/main/java/net/minestom/server/advancements/Advancement.java @@ -60,7 +60,7 @@ public class Advancement { public Advancement(@NotNull JsonMessage title, @NotNull JsonMessage description, @NotNull Material icon, @NotNull FrameType frameType, float x, float y) { - this(title, description, new ItemStack(icon, (byte) 1), frameType, x, y); + this(title, description, ItemStack.of(icon, 1), frameType, x, y); } public Advancement(@NotNull Component title, Component description, @@ -77,7 +77,7 @@ public class Advancement { public Advancement(@NotNull Component title, @NotNull Component description, @NotNull Material icon, @NotNull FrameType frameType, float x, float y) { - this(title, description, new ItemStack(icon, (byte) 1), frameType, x, y); + this(title, description, ItemStack.of(icon, 1), frameType, x, y); } /** diff --git a/src/main/java/net/minestom/server/advancements/AdvancementRoot.java b/src/main/java/net/minestom/server/advancements/AdvancementRoot.java index 3aa224d30..f298d9fb6 100644 --- a/src/main/java/net/minestom/server/advancements/AdvancementRoot.java +++ b/src/main/java/net/minestom/server/advancements/AdvancementRoot.java @@ -1,7 +1,6 @@ package net.minestom.server.advancements; import net.kyori.adventure.text.Component; -import net.minestom.server.chat.ColoredText; import net.minestom.server.chat.JsonMessage; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; diff --git a/src/main/java/net/minestom/server/advancements/notifications/Notification.java b/src/main/java/net/minestom/server/advancements/notifications/Notification.java index 456028ad0..201499a39 100644 --- a/src/main/java/net/minestom/server/advancements/notifications/Notification.java +++ b/src/main/java/net/minestom/server/advancements/notifications/Notification.java @@ -33,7 +33,7 @@ public class Notification { } public Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull Material icon) { - this(title, frameType, new ItemStack(icon, (byte) 1)); + this(title, frameType, ItemStack.of(icon)); } public Notification(@NotNull Component title, @NotNull FrameType frameType, @NotNull ItemStack icon) { @@ -46,7 +46,6 @@ public class Notification { * Gets the title of the notification. * * @return the notification title - * * @deprecated Use {@link #getTitle()} */ @NotNull diff --git a/src/main/java/net/minestom/server/chat/ChatHoverEvent.java b/src/main/java/net/minestom/server/chat/ChatHoverEvent.java index f10722f71..cfcd5e9ae 100644 --- a/src/main/java/net/minestom/server/chat/ChatHoverEvent.java +++ b/src/main/java/net/minestom/server/chat/ChatHoverEvent.java @@ -1,6 +1,5 @@ package net.minestom.server.chat; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import net.kyori.adventure.text.Component; @@ -93,11 +92,8 @@ public class ChatHoverEvent { JsonObject obj = GsonComponentSerializer.gson().serializer().toJsonTree(Component.empty().hoverEvent(event)).getAsJsonObject(); obj = obj.get("hoverEvent").getAsJsonObject().get("contents").getAsJsonObject(); - if (itemStack.getItemMeta() != null) { - NBTCompound compound = new NBTCompound(); - itemStack.getItemMeta().write(compound); - obj.add("tag", new JsonPrimitive(compound.toSNBT())); - } + NBTCompound compound = itemStack.getMeta().toNBT(); + obj.add("tag", new JsonPrimitive(compound.toSNBT())); return new ChatHoverEvent("show_item", obj); } diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java index 0060a6624..746343557 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java @@ -42,12 +42,12 @@ public class ArgumentItemStack extends Argument { if (nbtIndex == -1) { // Only item name final Material material = Registries.getMaterial(input); - return new ItemStack(material, (byte) 1); + return ItemStack.of(material); } else { final String materialName = input.substring(0, nbtIndex); final Material material = Registries.getMaterial(materialName); - ItemStack itemStack = new ItemStack(material, (byte) 1); + ItemStack itemStack = ItemStack.of(material); final String sNBT = input.substring(nbtIndex).replace("\\\"", "\""); diff --git a/src/main/java/net/minestom/server/entity/ItemEntity.java b/src/main/java/net/minestom/server/entity/ItemEntity.java index 5b19e5867..869e5f863 100644 --- a/src/main/java/net/minestom/server/entity/ItemEntity.java +++ b/src/main/java/net/minestom/server/entity/ItemEntity.java @@ -109,7 +109,7 @@ public class ItemEntity extends ObjectEntity { if (!canApply) continue; - final ItemStack result = stackingRule.apply(itemStack.clone(), totalAmount); + final ItemStack result = stackingRule.apply(itemStack, totalAmount); EntityItemMergeEvent entityItemMergeEvent = new EntityItemMergeEvent(this, itemEntity, result); callCancellableEvent(EntityItemMergeEvent.class, entityItemMergeEvent, () -> { diff --git a/src/main/java/net/minestom/server/entity/LivingEntity.java b/src/main/java/net/minestom/server/entity/LivingEntity.java index caa1c64e6..bb8ea3f3f 100644 --- a/src/main/java/net/minestom/server/entity/LivingEntity.java +++ b/src/main/java/net/minestom/server/entity/LivingEntity.java @@ -37,7 +37,7 @@ import java.util.concurrent.ConcurrentHashMap; //TODO: Default attributes registration (and limitation ?) public class LivingEntity extends Entity implements EquipmentHandler { - // Item pickup + // ItemStack pickup protected boolean canPickupItem; protected UpdateOption itemPickupCooldown = new UpdateOption(5, TimeUnit.TICK); private long lastItemPickupCheckTime; @@ -112,13 +112,13 @@ public class LivingEntity extends Entity implements EquipmentHandler { } private void initEquipments() { - this.mainHandItem = ItemStack.getAirItem(); - this.offHandItem = ItemStack.getAirItem(); + this.mainHandItem = ItemStack.AIR; + this.offHandItem = ItemStack.AIR; - this.helmet = ItemStack.getAirItem(); - this.chestplate = ItemStack.getAirItem(); - this.leggings = ItemStack.getAirItem(); - this.boots = ItemStack.getAirItem(); + this.helmet = ItemStack.AIR; + this.chestplate = ItemStack.AIR; + this.leggings = ItemStack.AIR; + this.boots = ItemStack.AIR; } @NotNull @@ -551,7 +551,7 @@ public class LivingEntity extends Entity implements EquipmentHandler { playerConnection.sendPacket(getEquipmentsPacket()); playerConnection.sendPacket(getPropertiesPacket()); - if (getTeam() != null){ + if (getTeam() != null) { playerConnection.sendPacket(getTeam().createTeamsCreationPacket()); } diff --git a/src/main/java/net/minestom/server/entity/Metadata.java b/src/main/java/net/minestom/server/entity/Metadata.java index 5e64f841b..ac54d707b 100644 --- a/src/main/java/net/minestom/server/entity/Metadata.java +++ b/src/main/java/net/minestom/server/entity/Metadata.java @@ -1,15 +1,14 @@ package net.minestom.server.entity; import net.kyori.adventure.text.Component; -import net.minestom.server.adventure.AdventureSerializer; import net.minestom.server.MinecraftServer; +import net.minestom.server.adventure.AdventureSerializer; import net.minestom.server.chat.ColoredText; import net.minestom.server.chat.JsonMessage; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.play.EntityMetaDataPacket; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.Direction; -import net.minestom.server.utils.Position; import net.minestom.server.utils.Vector; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; @@ -21,8 +20,8 @@ import org.jglrxavpok.hephaistos.nbt.NBT; import org.jglrxavpok.hephaistos.nbt.NBTEnd; import org.jglrxavpok.hephaistos.nbt.NBTException; -import java.util.*; import java.io.IOException; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Function; @@ -61,14 +60,14 @@ public class Metadata { writer.writeSizedString(value.toString()); } }, - reader -> { - boolean present = reader.readBoolean(); - if(present) { - return reader.readJsonMessage(Integer.MAX_VALUE); - } else { - return null; - } - }); + reader -> { + boolean present = reader.readBoolean(); + if (present) { + return reader.readJsonMessage(Integer.MAX_VALUE); + } else { + return null; + } + }); } public static Value Chat(@NotNull Component value) { @@ -84,7 +83,7 @@ public class Metadata { } }, reader -> { boolean present = reader.readBoolean(); - if(present) { + if (present) { return reader.readComponent(Integer.MAX_VALUE); } return null; @@ -120,7 +119,7 @@ public class Metadata { } }, reader -> { boolean present = reader.readBoolean(); - if(present) { + if (present) { return reader.readBlockPosition(); } else { return null; @@ -141,7 +140,7 @@ public class Metadata { } }, reader -> { boolean present = reader.readBoolean(); - if(present) { + if (present) { return reader.readUuid(); } else { return null; @@ -155,7 +154,7 @@ public class Metadata { writer.writeVarInt(present ? value : 0); }, reader -> { boolean present = reader.readBoolean(); - if(present) { + if (present) { return reader.readVarInt(); } else { return null; @@ -183,7 +182,7 @@ public class Metadata { writer.writeVarInt(villagerType); writer.writeVarInt(villagerProfession); writer.writeVarInt(level); - }, reader -> new int[] { + }, reader -> new int[]{ reader.readVarInt(), reader.readVarInt(), reader.readVarInt() @@ -196,7 +195,7 @@ public class Metadata { writer.writeVarInt(present ? value + 1 : 0); }, reader -> { boolean present = reader.readBoolean(); - if(present) { + if (present) { return reader.readVarInt(); } else { return null; @@ -331,7 +330,7 @@ public class Metadata { } private static Value getCorrespondingNewEmptyValue(int type) { - switch(type) { + switch (type) { case TYPE_BYTE: return (Value) Byte((byte) 0); case TYPE_VARINT: @@ -345,13 +344,13 @@ public class Metadata { case TYPE_OPTCHAT: return (Value) OptChat((Component) null); case TYPE_SLOT: - return (Value) Slot(ItemStack.getAirItem()); + return (Value) Slot(ItemStack.AIR); case TYPE_BOOLEAN: return (Value) Boolean(false); case TYPE_ROTATION: return (Value) Rotation(new Vector()); case TYPE_POSITION: - return (Value) Position(new BlockPosition(0,0,0)); + return (Value) Position(new BlockPosition(0, 0, 0)); case TYPE_OPTPOSITION: return (Value) OptPosition(null); case TYPE_DIRECTION: @@ -365,7 +364,7 @@ public class Metadata { case TYPE_PARTICLE: throw new UnsupportedOperationException(); case TYPE_VILLAGERDATA: - return (Value) VillagerData(0,0,0); + return (Value) VillagerData(0, 0, 0); case TYPE_OPTVARINT: return (Value) OptVarInt(null); case TYPE_POSE: diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index abd5360bb..41f55a2d7 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -78,7 +78,6 @@ import org.jetbrains.annotations.Nullable; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.UnaryOperator; @@ -591,11 +590,12 @@ public class Player extends LivingEntity implements CommandSender, Localizable, } } - // Item ownership cache + // ItemStack ownership cache { ItemStack[] itemStacks = inventory.getItemStacks(); for (ItemStack itemStack : itemStacks) { - ItemStack.DATA_OWNERSHIP.clearCache(itemStack.getIdentifier()); + // FIXME: item data + //ItemStack.DATA_OWNERSHIP.clearCache(itemStack.getIdentifier()); } } @@ -1109,37 +1109,12 @@ public class Player extends LivingEntity implements CommandSender, Localizable, MinecraftServer.getBossBarManager().removeBossBar(this, bar); } - /** - * Opens a book ui for the player with the given book metadata. - * - * @param bookMeta The metadata of the book to open - * @deprecated Use {@link #openBook(Book)} - */ - @Deprecated - public void openBook(@NotNull WrittenBookMeta bookMeta) { - // Set book in offhand - final ItemStack writtenBook = new ItemStack(Material.WRITTEN_BOOK, (byte) 1); - writtenBook.setItemMeta(bookMeta); - final SetSlotPacket setSlotPacket = new SetSlotPacket(); - setSlotPacket.windowId = 0; - setSlotPacket.slot = 45; - setSlotPacket.itemStack = writtenBook; - this.playerConnection.sendPacket(setSlotPacket); - - // Open the book - final OpenBookPacket openBookPacket = new OpenBookPacket(); - openBookPacket.hand = Hand.OFF; - this.playerConnection.sendPacket(openBookPacket); - - // Update inventory to remove book (which the actual inventory does not have) - this.inventory.update(); - } - @Override public void openBook(@NotNull Book book) { // make the book - ItemStack writtenBook = new ItemStack(Material.WRITTEN_BOOK, (byte) 1); - writtenBook.setItemMeta(WrittenBookMeta.fromAdventure(book, this)); + ItemStack writtenBook = ItemStack.of(Material.WRITTEN_BOOK); + // TODO: WRITTEN_BOOK meta + //writtenBook.setItemMeta(WrittenBookMeta.fromAdventure(book, this)); // Set book in offhand SetSlotPacket setBookPacket = new SetSlotPacket(); @@ -2009,10 +1984,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable, ItemStack cursorItem; if (openInventory == null) { cursorItem = getInventory().getCursorItem(); - getInventory().setCursorItem(ItemStack.getAirItem()); + getInventory().setCursorItem(ItemStack.AIR); } else { cursorItem = openInventory.getCursorItem(this); - openInventory.setCursorItem(this, ItemStack.getAirItem()); + openInventory.setCursorItem(this, ItemStack.AIR); } if (!cursorItem.isAir()) { // Add item to inventory if he hasn't been able to drop it diff --git a/src/main/java/net/minestom/server/entity/metadata/item/ItemContainingMeta.java b/src/main/java/net/minestom/server/entity/metadata/item/ItemContainingMeta.java index 18e2512b7..ac3066584 100644 --- a/src/main/java/net/minestom/server/entity/metadata/item/ItemContainingMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/item/ItemContainingMeta.java @@ -13,7 +13,7 @@ class ItemContainingMeta extends EntityMeta { protected ItemContainingMeta(@NotNull Entity entity, @NotNull Metadata metadata, @NotNull Material defaultItemMaterial) { super(entity, metadata); - this.defaultItem = new ItemStack(defaultItemMaterial, (byte) 1); + this.defaultItem = ItemStack.of(defaultItemMaterial, 1); } @NotNull diff --git a/src/main/java/net/minestom/server/entity/metadata/other/FireworkRocketMeta.java b/src/main/java/net/minestom/server/entity/metadata/other/FireworkRocketMeta.java index c3155617d..c019323de 100644 --- a/src/main/java/net/minestom/server/entity/metadata/other/FireworkRocketMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/other/FireworkRocketMeta.java @@ -18,7 +18,7 @@ public class FireworkRocketMeta extends EntityMeta implements ProjectileMeta { @NotNull public ItemStack getFireworkInfo() { - return super.metadata.getIndex((byte) 7, ItemStack.getAirItem()); + return super.metadata.getIndex((byte) 7, ItemStack.AIR); } public void setFireworkInfo(@NotNull ItemStack value) { diff --git a/src/main/java/net/minestom/server/entity/metadata/other/ItemFrameMeta.java b/src/main/java/net/minestom/server/entity/metadata/other/ItemFrameMeta.java index b4d0e2f68..080694213 100644 --- a/src/main/java/net/minestom/server/entity/metadata/other/ItemFrameMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/other/ItemFrameMeta.java @@ -19,7 +19,7 @@ public class ItemFrameMeta extends EntityMeta implements ObjectDataProvider { @NotNull public ItemStack getItem() { - return super.metadata.getIndex((byte) 7, ItemStack.getAirItem()); + return super.metadata.getIndex((byte) 7, ItemStack.AIR); } public void setItem(@NotNull ItemStack value) { diff --git a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java index d95df9cee..429b2bcdf 100644 --- a/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java +++ b/src/main/java/net/minestom/server/entity/type/decoration/EntityArmorStand.java @@ -41,13 +41,13 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler { setLeftLegRotation(new Vector(-1f, 0, -1f)); setRightLegRotation(new Vector(1, 0, 1)); - this.mainHandItem = ItemStack.getAirItem(); - this.offHandItem = ItemStack.getAirItem(); + this.mainHandItem = ItemStack.AIR; + this.offHandItem = ItemStack.AIR; - this.helmet = ItemStack.getAirItem(); - this.chestplate = ItemStack.getAirItem(); - this.leggings = ItemStack.getAirItem(); - this.boots = ItemStack.getAirItem(); + this.helmet = ItemStack.AIR; + this.chestplate = ItemStack.AIR; + this.leggings = ItemStack.AIR; + this.boots = ItemStack.AIR; } diff --git a/src/main/java/net/minestom/server/entity/type/decoration/EntityItemFrame.java b/src/main/java/net/minestom/server/entity/type/decoration/EntityItemFrame.java index 7683a76ce..f3fd2ffe5 100644 --- a/src/main/java/net/minestom/server/entity/type/decoration/EntityItemFrame.java +++ b/src/main/java/net/minestom/server/entity/type/decoration/EntityItemFrame.java @@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull; // FIXME: https://wiki.vg/Object_Data#Item_Frame_.28id_71.29 // "You have to set both Orientation and Yaw/Pitch accordingly, otherwise it will not work." + /** * @deprecated Use {@link net.minestom.server.entity.metadata.other.ItemFrameMeta} instead. */ @@ -37,7 +38,7 @@ public class EntityItemFrame extends ObjectEntity { */ @NotNull public ItemStack getItemStack() { - return metadata.getIndex((byte) 7, ItemStack.getAirItem()); + return metadata.getIndex((byte) 7, ItemStack.AIR); } /** diff --git a/src/main/java/net/minestom/server/entity/type/projectile/EntityEyeOfEnder.java b/src/main/java/net/minestom/server/entity/type/projectile/EntityEyeOfEnder.java index ae9f28c5c..4ebfa357d 100644 --- a/src/main/java/net/minestom/server/entity/type/projectile/EntityEyeOfEnder.java +++ b/src/main/java/net/minestom/server/entity/type/projectile/EntityEyeOfEnder.java @@ -26,7 +26,7 @@ public class EntityEyeOfEnder extends Entity { * @return the item */ public ItemStack getItemStack() { - return metadata.getIndex((byte) 7, ItemStack.getAirItem()); + return metadata.getIndex((byte) 7, ItemStack.AIR); } /** diff --git a/src/main/java/net/minestom/server/entity/type/projectile/EntityPotion.java b/src/main/java/net/minestom/server/entity/type/projectile/EntityPotion.java index c42ec9b97..f0c1e1c76 100644 --- a/src/main/java/net/minestom/server/entity/type/projectile/EntityPotion.java +++ b/src/main/java/net/minestom/server/entity/type/projectile/EntityPotion.java @@ -22,7 +22,7 @@ public class EntityPotion extends Entity { @NotNull public ItemStack getPotion() { - return metadata.getIndex((byte) 7, ItemStack.getAirItem()); + return metadata.getIndex((byte) 7, ItemStack.AIR); } public void setPotion(@NotNull ItemStack potion) { diff --git a/src/main/java/net/minestom/server/gamedata/loottables/ConditionedFunctionWrapper.java b/src/main/java/net/minestom/server/gamedata/loottables/ConditionedFunctionWrapper.java index 93c6f0c00..4b4b9d0f6 100644 --- a/src/main/java/net/minestom/server/gamedata/loottables/ConditionedFunctionWrapper.java +++ b/src/main/java/net/minestom/server/gamedata/loottables/ConditionedFunctionWrapper.java @@ -22,7 +22,7 @@ public class ConditionedFunctionWrapper implements LootTableFunction { @Override public ItemStack apply(ItemStack stack, Data data) { for (Condition c : conditions) { - if(!c.test(data)) + if (!c.test(data)) return stack; } return baseFunction.apply(stack, data); diff --git a/src/main/java/net/minestom/server/gamedata/loottables/LootTable.java b/src/main/java/net/minestom/server/gamedata/loottables/LootTable.java index 2e9bbf0e5..db39e47fc 100644 --- a/src/main/java/net/minestom/server/gamedata/loottables/LootTable.java +++ b/src/main/java/net/minestom/server/gamedata/loottables/LootTable.java @@ -31,10 +31,10 @@ public class LootTable { } public List generate(Data arguments) { - if(arguments == null) + if (arguments == null) arguments = Data.EMPTY; List output = new LinkedList<>(); - for(Pool p : pools) { + for (Pool p : pools) { p.generate(output, arguments); } return output; @@ -74,18 +74,18 @@ public class LootTable { } public void generate(List output, Data arguments) { - for(Condition c : conditions) { - if(!c.test(arguments)) + for (Condition c : conditions) { + if (!c.test(arguments)) return; } Random rng = new Random(); int luck = arguments.getOrDefault(LUCK_KEY, 0); - int rollCount = rng.nextInt(maxRollCount - minRollCount +1 /*inclusive*/) + minRollCount; - int bonusRollCount = rng.nextInt(bonusMaxRollCount - bonusMinRollCount +1 /*inclusive*/) + bonusMinRollCount; + int rollCount = rng.nextInt(maxRollCount - minRollCount + 1 /*inclusive*/) + minRollCount; + int bonusRollCount = rng.nextInt(bonusMaxRollCount - bonusMinRollCount + 1 /*inclusive*/) + bonusMinRollCount; bonusRollCount *= luck; // TODO: implement luck (quality/weight) weight=floor( weight + (quality * generic.luck)) WeightedRandom weightedRandom = new WeightedRandom<>(entries); - for (int i = 0; i < rollCount+bonusRollCount; i++) { + for (int i = 0; i < rollCount + bonusRollCount; i++) { Entry entry = weightedRandom.get(rng); entry.generateStacks(output, arguments); } @@ -122,8 +122,8 @@ public class LootTable { } public final void generateStacks(List output, Data arguments) { - for(Condition c : conditions) { - if(!c.test(arguments)) + for (Condition c : conditions) { + if (!c.test(arguments)) return; } generate(output, arguments); diff --git a/src/main/java/net/minestom/server/gamedata/loottables/entries/AlternativesEntry.java b/src/main/java/net/minestom/server/gamedata/loottables/entries/AlternativesEntry.java index 47ba1fe79..6ede7cea8 100644 --- a/src/main/java/net/minestom/server/gamedata/loottables/entries/AlternativesEntry.java +++ b/src/main/java/net/minestom/server/gamedata/loottables/entries/AlternativesEntry.java @@ -17,11 +17,11 @@ public class AlternativesEntry extends LootTable.Entry { @Override public void generate(List output, Data arguments) { - for(LootTable.Entry c : children) { + for (LootTable.Entry c : children) { int previousSize = output.size(); c.generateStacks(output, arguments); int newSize = output.size(); - if(newSize != previousSize) { // an entry managed to generate, stop here + if (newSize != previousSize) { // an entry managed to generate, stop here return; } } diff --git a/src/main/java/net/minestom/server/gamedata/loottables/entries/ItemEntry.java b/src/main/java/net/minestom/server/gamedata/loottables/entries/ItemEntry.java index c49eb11bf..9d5b257bc 100644 --- a/src/main/java/net/minestom/server/gamedata/loottables/entries/ItemEntry.java +++ b/src/main/java/net/minestom/server/gamedata/loottables/entries/ItemEntry.java @@ -23,11 +23,11 @@ public class ItemEntry extends LootTable.Entry { @Override public void generate(List output, Data arguments) { - ItemStack stack = new ItemStack(item, (byte)1); + ItemStack stack = ItemStack.of(item); for (LootTableFunction function : functions) { stack = function.apply(stack, arguments); } - if(!stack.isAir()) { + if (!stack.isAir()) { output.add(stack); } } diff --git a/src/main/java/net/minestom/server/gamedata/loottables/entries/SequenceEntry.java b/src/main/java/net/minestom/server/gamedata/loottables/entries/SequenceEntry.java index 48beb921c..f1245e8e3 100644 --- a/src/main/java/net/minestom/server/gamedata/loottables/entries/SequenceEntry.java +++ b/src/main/java/net/minestom/server/gamedata/loottables/entries/SequenceEntry.java @@ -17,11 +17,11 @@ public class SequenceEntry extends LootTable.Entry { @Override public void generate(List output, Data arguments) { - for(LootTable.Entry c : children) { + for (LootTable.Entry c : children) { int previousSize = output.size(); c.generateStacks(output, arguments); int newSize = output.size(); - if(newSize == previousSize) { // an entry failed to generate, stop here + if (newSize == previousSize) { // an entry failed to generate, stop here return; } } diff --git a/src/main/java/net/minestom/server/gamedata/loottables/entries/TagEntry.java b/src/main/java/net/minestom/server/gamedata/loottables/entries/TagEntry.java index 296ea1b86..9dfa7a3ea 100644 --- a/src/main/java/net/minestom/server/gamedata/loottables/entries/TagEntry.java +++ b/src/main/java/net/minestom/server/gamedata/loottables/entries/TagEntry.java @@ -27,19 +27,19 @@ public class TagEntry extends LootTable.Entry { @Override public void generate(List output, Data arguments) { Set values = tag.getValues(); - if(values.isEmpty()) + if (values.isEmpty()) return; Material[] asArrayOfItems = new Material[values.size()]; int ptr = 0; for (NamespaceID id : values) { asArrayOfItems[ptr++] = Registries.getMaterial(id); } - if(expand) { - Material selectedItem = asArrayOfItems[rng.nextInt(asArrayOfItems.length)]; - output.add(new ItemStack(selectedItem, (byte) 1)); + if (expand) { + Material selectedMaterial = asArrayOfItems[rng.nextInt(asArrayOfItems.length)]; + output.add(ItemStack.of(selectedMaterial)); } else { - for(Material item : asArrayOfItems) { - output.add(new ItemStack(item, (byte) 1)); + for (Material material : asArrayOfItems) { + output.add(ItemStack.of(material)); } } } diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index 805f9a352..ec04cf8cb 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -16,13 +16,13 @@ import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.WindowItemsPacket; import net.minestom.server.network.packet.server.play.WindowPropertyPacket; import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.utils.ArrayUtils; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; @@ -79,8 +79,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View this.offset = size; this.itemStacks = new ItemStack[size]; - - ArrayUtils.fill(itemStacks, ItemStack::getAirItem); + Arrays.fill(itemStacks, ItemStack.AIR); } private static byte generateId() { @@ -162,12 +161,10 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View final int totalAmount = itemStackAmount + itemAmount; if (!stackingRule.canApply(itemStack, totalAmount)) { item = itemStackingRule.apply(item, itemStackingRule.getMaxSize()); - - sendSlotRefresh((short) i, item); + setItemStack(i, item); itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); } else { - item.setAmount((byte) totalAmount); - sendSlotRefresh((short) i, item); + setItemStack(i, item.withAmount(totalAmount)); return true; } } else if (item.isAir()) { @@ -182,7 +179,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View public void clear() { // Clear the item array for (int i = 0; i < getSize(); i++) { - setItemStackInternal(i, ItemStack.getAirItem()); + setItemStackInternal(i, ItemStack.AIR); } // Send the cleared inventory to viewers update(); @@ -289,7 +286,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View */ @NotNull public ItemStack getCursorItem(@NotNull Player player) { - return cursorPlayersItem.getOrDefault(player, ItemStack.getAirItem()); + return cursorPlayersItem.getOrDefault(player, ItemStack.AIR); } /** @@ -543,7 +540,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View final boolean outsideDrop = slot == -999; final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset); final ItemStack clicked = outsideDrop ? - ItemStack.getAirItem() : (isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot)); + ItemStack.AIR : (isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot)); final ItemStack cursor = getCursorItem(player); final InventoryClickResult clickResult = clickProcessor.drop(this, player, @@ -574,7 +571,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View final int clickSlot = isInWindow ? slot : PlayerInventoryUtils.convertSlot(slot, offset); final ItemStack clicked = slot != -999 ? (isInWindow ? getItemStack(slot) : playerInventory.getItemStack(clickSlot)) : - ItemStack.getAirItem(); + ItemStack.AIR; final ItemStack cursor = getCursorItem(player); final InventoryClickResult clickResult = clickProcessor.dragging(this, player, diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 1f3e90fb6..92e843bdc 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -16,12 +16,12 @@ import net.minestom.server.item.StackingRule; import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.WindowItemsPacket; -import net.minestom.server.utils.ArrayUtils; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -36,7 +36,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler protected final Player player; protected final ItemStack[] items = new ItemStack[INVENTORY_SIZE]; - private ItemStack cursorItem = ItemStack.getAirItem(); + private ItemStack cursorItem = ItemStack.AIR; private final List inventoryConditions = new CopyOnWriteArrayList<>(); private final InventoryClickProcessor clickProcessor = new InventoryClickProcessor(); @@ -45,8 +45,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler public PlayerInventory(@NotNull Player player) { this.player = player; - - ArrayUtils.fill(items, ItemStack::getAirItem); + Arrays.fill(items, ItemStack.AIR); } @NotNull @@ -110,12 +109,10 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler final int totalAmount = itemStackAmount + itemAmount; if (!stackingRule.canApply(itemStack, totalAmount)) { item = itemStackingRule.apply(item, itemStackingRule.getMaxSize()); - - sendSlotRefresh((short) convertToPacketSlot(i), item); + setItemStack(i, item); itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); } else { - item.setAmount((byte) totalAmount); - sendSlotRefresh((short) convertToPacketSlot(i), item); + setItemStack(i, item.withAmount(totalAmount)); return true; } } else if (item.isAir()) { @@ -130,7 +127,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler public void clear() { // Clear the item array for (int i = 0; i < getSize(); i++) { - setItemStackInternal(i, ItemStack.getAirItem()); + setItemStackInternal(i, ItemStack.AIR); } // Send the cleared inventory to the inventory's owner update(); @@ -418,7 +415,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler public boolean drop(@NotNull Player player, int mode, int slot, int button) { final ItemStack cursor = getCursorItem(); final boolean outsideDrop = slot == -999; - final ItemStack clicked = outsideDrop ? ItemStack.getAirItem() : getItemStack(slot, OFFSET); + final ItemStack clicked = outsideDrop ? ItemStack.AIR : getItemStack(slot, OFFSET); final InventoryClickResult clickResult = clickProcessor.drop(null, player, mode, slot, button, clicked, cursor); @@ -492,7 +489,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler @Override public boolean dragging(@NotNull Player player, int slot, int button) { final ItemStack cursor = getCursorItem(); - final ItemStack clicked = slot != -999 ? getItemStack(slot, OFFSET) : ItemStack.getAirItem(); + final ItemStack clicked = slot != -999 ? getItemStack(slot, OFFSET) : ItemStack.AIR; final InventoryClickResult clickResult = clickProcessor.dragging(null, player, slot, button, diff --git a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java index 949029f78..1cdd837ed 100644 --- a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java +++ b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java @@ -101,19 +101,13 @@ public class InventoryClickProcessor { } else { if (cursor.isAir()) { final int amount = (int) Math.ceil((double) clicked.getAmount() / 2d); - resultCursor = clicked.clone(); - resultCursor = cursorRule.apply(resultCursor, amount); - - resultClicked = clicked.clone(); - resultClicked = clickedRule.apply(resultClicked, clicked.getAmount() / 2); + resultCursor = cursorRule.apply(clicked, amount); + resultClicked = clickedRule.apply(clicked, clicked.getAmount() / 2); } else { if (clicked.isAir()) { final int amount = cursor.getAmount(); - resultCursor = cursor.clone(); - resultCursor = cursorRule.apply(resultCursor, amount - 1); - - resultClicked = cursor.clone(); - resultClicked = clickedRule.apply(resultClicked, 1); + resultCursor = cursorRule.apply(cursor, amount - 1); + resultClicked = clickedRule.apply(cursor, 1); } else { resultCursor = clicked; resultClicked = cursor; @@ -155,11 +149,11 @@ public class InventoryClickProcessor { if (clicked.isAir()) { // Set held item [key] to slot resultClicked = cursor; - resultHeld = ItemStack.getAirItem(); + resultHeld = ItemStack.AIR; } else { if (cursor.isAir()) { // if held item [key] is air then set clicked to held - resultClicked = ItemStack.getAirItem(); + resultClicked = ItemStack.AIR; } else { // Otherwise replace held item and held resultClicked = cursor; @@ -189,7 +183,7 @@ public class InventoryClickProcessor { final StackingRule clickedRule = clicked.getStackingRule(); boolean filled = false; - ItemStack resultClicked = clicked.clone(); + ItemStack resultClicked = clicked; for (InventoryClickLoopHandler loopHandler : loopHandlers) { final Int2IntFunction indexModifier = loopHandler.getIndexModifier(); @@ -242,7 +236,7 @@ public class InventoryClickProcessor { // Switch itemSetter.accept(index, resultClicked); - itemSetter.accept(slot, ItemStack.getAirItem()); + itemSetter.accept(slot, ItemStack.AIR); filled = true; break; } @@ -287,7 +281,7 @@ public class InventoryClickProcessor { int finalCursorAmount = cursorAmount; for (int s : slots) { - final ItemStack draggedItem = cursor.clone(); + final ItemStack draggedItem = cursor; ItemStack slotItem = itemGetter.apply(s); clickResult = startCondition(inventory, player, s, ClickType.DRAGGING, slotItem, cursor); @@ -327,7 +321,7 @@ public class InventoryClickProcessor { if (size > cursorAmount) return null; for (int s : slots) { - ItemStack draggedItem = cursor.clone(); + ItemStack draggedItem = cursor; ItemStack slotItem = itemGetter.apply(s); clickResult = startCondition(inventory, player, s, ClickType.DRAGGING, slotItem, cursor); @@ -377,7 +371,7 @@ public class InventoryClickProcessor { @Nullable public InventoryClickResult doubleClick(@Nullable Inventory inventory, @NotNull Player player, int slot, @NotNull ItemStack cursor, @NotNull InventoryClickLoopHandler... loopHandlers) { - InventoryClickResult clickResult = startCondition(inventory, player, slot, ClickType.START_DOUBLE_CLICK, ItemStack.getAirItem(), cursor); + InventoryClickResult clickResult = startCondition(inventory, player, slot, ClickType.START_DOUBLE_CLICK, ItemStack.AIR, cursor); if (clickResult.isCancel()) { return clickResult; @@ -446,8 +440,8 @@ public class InventoryClickProcessor { final StackingRule clickedRule = clicked.getStackingRule(); final StackingRule cursorRule = cursor.getStackingRule(); - ItemStack resultClicked = clicked.clone(); - ItemStack resultCursor = cursor.clone(); + ItemStack resultClicked = clicked; + ItemStack resultCursor = cursor; if (slot == -999) { @@ -455,7 +449,7 @@ public class InventoryClickProcessor { if (button == 0) { // Left (drop all) final int amount = cursorRule.getAmount(resultCursor); - final ItemStack dropItem = cursorRule.apply(resultCursor.clone(), amount); + final ItemStack dropItem = cursorRule.apply(resultCursor, amount); final boolean dropResult = player.dropItem(dropItem); clickResult.setCancel(!dropResult); if (dropResult) { @@ -463,7 +457,7 @@ public class InventoryClickProcessor { } } else if (button == 1) { // Right (drop 1) - final ItemStack dropItem = cursorRule.apply(resultCursor.clone(), 1); + final ItemStack dropItem = cursorRule.apply(resultCursor, 1); final boolean dropResult = player.dropItem(dropItem); clickResult.setCancel(!dropResult); if (dropResult) { @@ -476,7 +470,7 @@ public class InventoryClickProcessor { } else if (mode == 4) { if (button == 0) { // Drop key Q (drop 1) - final ItemStack dropItem = cursorRule.apply(resultClicked.clone(), 1); + final ItemStack dropItem = cursorRule.apply(resultClicked, 1); final boolean dropResult = player.dropItem(dropItem); clickResult.setCancel(!dropResult); if (dropResult) { @@ -487,7 +481,7 @@ public class InventoryClickProcessor { } else if (button == 1) { // Ctrl + Drop key Q (drop all) final int amount = cursorRule.getAmount(resultClicked); - final ItemStack dropItem = clickedRule.apply(resultClicked.clone(), amount); + final ItemStack dropItem = clickedRule.apply(resultClicked, amount); final boolean dropResult = player.dropItem(dropItem); clickResult.setCancel(!dropResult); if (dropResult) { @@ -517,7 +511,7 @@ public class InventoryClickProcessor { // Call ItemStack#onInventoryClick { - clickResult.getClicked().onInventoryClick(player, clickType, slot, isPlayerInventory); + //clickResult.getClicked().onInventoryClick(player, clickType, slot, isPlayerInventory); } // Reset the didCloseInventory field diff --git a/src/main/java/net/minestom/server/item/Item.java b/src/main/java/net/minestom/server/item/Item.java deleted file mode 100644 index 065481bfa..000000000 --- a/src/main/java/net/minestom/server/item/Item.java +++ /dev/null @@ -1,104 +0,0 @@ -package net.minestom.server.item; - -import net.kyori.adventure.text.Component; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.UUID; -import java.util.function.Consumer; -import java.util.function.IntUnaryOperator; -import java.util.function.UnaryOperator; - -public class Item { - - private final UUID uuid = UUID.randomUUID(); - private final Material material; - private final int amount; - private final ItemMeta meta; - - protected Item(@NotNull Material material, int amount, ItemMeta meta) { - this.material = material; - this.amount = amount; - this.meta = meta; - } - - @Contract(value = "_ -> new", pure = true) - public static @NotNull ItemBuilder builder(@NotNull Material material) { - return new ItemBuilder(material); - } - - @Contract(pure = true) - public @NotNull UUID getUuid() { - return uuid; - } - - @Contract(pure = true) - public @NotNull Material getMaterial() { - return material; - } - - @Contract(value = "_, -> new", pure = true) - public @NotNull Item with(@NotNull Consumer<@NotNull ItemBuilder> builderConsumer) { - var builder = builder(); - builderConsumer.accept(builder); - return builder.build(); - } - - @Contract(pure = true) - public int getAmount() { - return amount; - } - - @Contract(value = "_, -> new", pure = true) - public @NotNull Item withAmount(int amount) { - return builder().amount(amount).build(); - } - - @Contract(value = "_, -> new", pure = true) - public @NotNull Item withAmount(@NotNull IntUnaryOperator intUnaryOperator) { - return withAmount(intUnaryOperator.applyAsInt(amount)); - } - - @Contract(value = "_, _ -> new", pure = true) - public > @NotNull Item withMeta(Class metaType, Consumer metaConsumer) { - return builder().meta(metaType, metaConsumer).build(); - } - - @Contract(pure = true) - public @Nullable Component getDisplayName() { - return meta.getDisplayName(); - } - - @Contract(value = "_, -> new", pure = true) - public @NotNull Item withDisplayName(@Nullable Component displayName) { - return builder().displayName(displayName).build(); - } - - @Contract(value = "_, -> new", pure = true) - public @NotNull Item withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) { - return withDisplayName(componentUnaryOperator.apply(getDisplayName())); - } - - @Contract(pure = true) - public @Nullable List<@NotNull Component> getLore() { - return meta.getLore(); - } - - @Contract(value = "_, -> new", pure = true) - public @NotNull Item withLore(@Nullable List<@NotNull Component> lore) { - return builder().lore(lore).build(); - } - - @Contract(value = "_, -> new", pure = true) - public @NotNull Item withLore(@NotNull UnaryOperator<@Nullable List<@NotNull Component>> loreUnaryOperator) { - return withLore(loreUnaryOperator.apply(getLore())); - } - - @Contract(value = "-> new", pure = true) - protected @NotNull ItemBuilder builder() { - return new ItemBuilder(material, meta.builder()) - .amount(amount); - } -} diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index 33f38fa8a..00b6718e1 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -17,7 +17,7 @@ public class ItemBuilder { protected ItemBuilder(@NotNull Material material, @NotNull ItemMetaBuilder metaBuilder) { this.material = material; - this.amount = 0; + this.amount = 1; this.metaBuilder = metaBuilder; } @@ -63,8 +63,8 @@ public class ItemBuilder { } @Contract(value = "-> new", pure = true) - public @NotNull Item build() { - return new Item(material, amount, metaBuilder.build()); + public @NotNull ItemStack build() { + return new ItemStack(material, amount, metaBuilder.build()); } } diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index cf4c41ba5..a17f843c7 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -1,24 +1,46 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; +import net.minestom.server.item.attribute.ItemAttribute; +import net.minestom.server.utils.NBTUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.function.Consumer; public class ItemMeta implements Cloneable { private final ItemMetaBuilder builder; + + private final int damage; + private final boolean unbreakable; + private final int hideFlag; private final Component displayName; private final List lore; + private final Map enchantmentMap; + private final List attributes; + + private final int customModelData; + + private NBTCompound cache = null; + protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { this.builder = metaBuilder.clone(); + this.damage = 0; + this.unbreakable = false; + this.hideFlag = 0; this.displayName = metaBuilder.displayName; this.lore = Collections.unmodifiableList(metaBuilder.lore); + this.enchantmentMap = Collections.unmodifiableMap(metaBuilder.enchantmentMap); + this.attributes = new ArrayList<>(); + this.customModelData = 0; } @Contract(value = "_, -> new", pure = true) @@ -28,6 +50,18 @@ public class ItemMeta implements Cloneable { return builder.build(); } + public int getDamage() { + return damage; + } + + public boolean isUnbreakable() { + return unbreakable; + } + + public int getHideFlag() { + return hideFlag; + } + @Contract(pure = true) public @Nullable Component getDisplayName() { return displayName; @@ -38,6 +72,25 @@ public class ItemMeta implements Cloneable { return lore; } + public Map getEnchantmentMap() { + return enchantmentMap; + } + + public List getAttributes() { + return attributes; + } + + public int getCustomModelData() { + return customModelData; + } + + public NBTCompound toNBT() { + if (cache == null) { + this.cache = NBTUtils.metaToNBT(this); + } + return cache; + } + protected @NotNull ItemMetaBuilder builder() { return builder.clone(); } diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 301665141..cb815d18c 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -9,7 +9,7 @@ import java.util.*; public abstract class ItemMetaBuilder implements Cloneable { protected Component displayName; - protected List lore; + protected List lore = new ArrayList<>(); protected Map enchantmentMap = new HashMap<>(); protected ItemMetaBuilder() { diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index ca253ec4c..514e99df8 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -1,912 +1,136 @@ package net.minestom.server.item; -import it.unimi.dsi.fastutil.objects.Object2ShortMap; -import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.HoverEvent; -import net.kyori.adventure.text.event.HoverEvent.ShowItem; -import net.kyori.adventure.text.event.HoverEventSource; -import net.minestom.server.MinecraftServer; -import net.minestom.server.chat.JsonMessage; -import net.minestom.server.data.Data; -import net.minestom.server.data.DataContainer; -import net.minestom.server.entity.ItemEntity; -import net.minestom.server.entity.Player; -import net.minestom.server.inventory.Inventory; -import net.minestom.server.inventory.PlayerInventory; -import net.minestom.server.inventory.click.ClickType; -import net.minestom.server.item.attribute.ItemAttribute; -import net.minestom.server.item.metadata.*; import net.minestom.server.item.rule.VanillaStackingRule; -import net.minestom.server.network.packet.server.play.SetSlotPacket; -import net.minestom.server.registry.Registries; -import net.minestom.server.utils.BlockPosition; -import net.minestom.server.utils.Direction; -import net.minestom.server.utils.NBTUtils; -import net.minestom.server.utils.clone.PublicCloneable; -import net.minestom.server.utils.ownership.OwnershipHandler; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import java.util.*; +import java.util.List; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.IntUnaryOperator; import java.util.function.UnaryOperator; -import java.util.stream.Collectors; -// TODO should we cache a ByteBuf of this item for faster packet write +public class ItemStack { -/** - * Represents an item in an inventory ({@link PlayerInventory}, {@link Inventory}) or on the ground ({@link ItemEntity}). - *

- * An item stack cannot be null, you can however use {@link #getAirItem()} instead. - *

- * WARNING: all setters will not update the item automatically, it will need to be refreshed manually. - * Here a non-exhaustive list of what you can do to update the item: - * {@link PlayerInventory#refreshSlot(short)}, {@link Inventory#refreshSlot(short)} or a raw {@link SetSlotPacket}. - */ -public class ItemStack implements DataContainer, PublicCloneable, HoverEventSource { + public static final ItemStack AIR = ItemStack.builder(Material.AIR).build(); - public static final OwnershipHandler DATA_OWNERSHIP = new OwnershipHandler<>(); - public static final String OWNERSHIP_DATA_KEY = "ownership_identifier"; - private static final StackingRule VANILLA_STACKING_RULE = new VanillaStackingRule(64); + private final UUID uuid = UUID.randomUUID(); + private final StackingRule stackingRule = new VanillaStackingRule(64); - private final UUID identifier; + private final Material material; + private final int amount; + private final ItemMeta meta; - private Material material; - - private static StackingRule defaultStackingRule; - private ItemMeta itemMeta; - - private byte amount; - private int damage; - - private Component displayName; - private boolean unbreakable; - private List lore; - - private Object2ShortMap enchantmentMap; - private List attributes; - - private int hideFlag; - private int customModelData; - - private StackingRule stackingRule; - private Data data; - - private Set canDestroy; - private Set canPlaceOn; - - { - if (defaultStackingRule == null) - defaultStackingRule = VANILLA_STACKING_RULE; - this.stackingRule = defaultStackingRule; - } - - public ItemStack(@NotNull Material material, byte amount, int damage) { - this.identifier = DATA_OWNERSHIP.generateIdentifier(); + protected ItemStack(@NotNull Material material, int amount, ItemMeta meta) { this.material = material; this.amount = amount; - this.damage = damage; - this.lore = new ArrayList<>(); - - this.enchantmentMap = new Object2ShortOpenHashMap<>(); - this.attributes = new ArrayList<>(); - - this.canDestroy = new HashSet<>(); - this.canPlaceOn = new HashSet<>(); - - this.itemMeta = findMeta(); + this.meta = meta; } - public ItemStack(@NotNull Material material, byte amount) { - this(material, amount, (short) 0); + @Contract(value = "_ -> new", pure = true) + public static @NotNull ItemBuilder builder(@NotNull Material material) { + return new ItemBuilder(material); } - public ItemStack(@NotNull Material material) { - this(material, (byte) 1, (short) 0); + @Contract(value = "_ -> new", pure = true) + public static @NotNull ItemStack of(@NotNull Material material, int amount) { + return builder(material).amount(amount).build(); } - /** - * Gets a new {@link ItemStack} with the material sets to {@link Material#AIR}. - *

- * Used when you require a "null item". - * - * @return an air item - */ - @NotNull - public static ItemStack getAirItem() { - return new ItemStack(Material.AIR, (byte) 0); + @Contract(value = "_ -> new", pure = true) + public static @NotNull ItemStack of(@NotNull Material material) { + return of(material, 1); } - /** - * Gets the default {@link StackingRule} for newly created {@link ItemStack}. - * - * @return the default stacking rule - */ - @NotNull - public static StackingRule getDefaultStackingRule() { - return defaultStackingRule; + @Contract(pure = true) + public @NotNull UUID getUuid() { + return uuid; } - /** - * Changes the default stacking rule for created item stack. - * - * @param defaultStackingRule the default item stack - * @throws NullPointerException if {@code defaultStackingRule} is null - */ - public static void setDefaultStackingRule(@NotNull StackingRule defaultStackingRule) { - ItemStack.defaultStackingRule = defaultStackingRule; - } - - /** - * Loads an {@link ItemStack} from nbt. - * - * @param nbt the nbt compound containing the item - * @return the parsed item stack - */ - @NotNull - public static ItemStack fromNBT(@NotNull NBTCompound nbt) { - if (!nbt.containsKey("id") || !nbt.containsKey("Count")) - throw new IllegalArgumentException("Invalid item NBT, must at least contain 'id' and 'Count' tags"); - final Material material = Registries.getMaterial(nbt.getString("id")); - final byte count = nbt.getAsByte("Count"); - - ItemStack s = new ItemStack(material, count); - - NBTCompound tag = nbt.getCompound("tag"); - if (tag != null) { - NBTUtils.loadDataIntoItem(s, tag); - } - return s; - } - - /** - * Gets if the item material is {@link Material#AIR}. - * - * @return true if the material is air, false otherwise - */ - public boolean isAir() { - return material == Material.AIR; - } - - /** - * Gets if two items are similar. - * It does not take {@link #getAmount()} and {@link #getStackingRule()} in consideration. - * - * @param itemStack The ItemStack to compare to - * @return true if both items are similar - */ - public boolean isSimilar(@NotNull ItemStack itemStack) { - synchronized (ItemStack.class) { - if (itemStack.getIdentifier().equals(identifier)) { - return true; - } - - final boolean displayNameCheck = Objects.equals(displayName, itemStack.displayName); - final boolean loreCheck = Objects.equals(lore, itemStack.lore); - - final Data itemData = itemStack.getData(); - final boolean dataCheck = (data == null && itemData == null) || - (data != null && data.equals(itemData)); - - final boolean sameMeta = (itemStack.itemMeta == null && itemMeta == null) || - (itemStack.itemMeta != null && itemMeta != null && (itemStack.itemMeta.isSimilar(itemMeta))); - - return itemStack.getMaterial() == material && - displayNameCheck && - loreCheck && - itemStack.isUnbreakable() == unbreakable && - itemStack.getDamage() == damage && - itemStack.enchantmentMap.equals(enchantmentMap) && - itemStack.attributes.equals(attributes) && - itemStack.hideFlag == hideFlag && - sameMeta && - dataCheck && - itemStack.canPlaceOn.equals(canPlaceOn) && - itemStack.canDestroy.equals(canDestroy); - } - } - - @Override - public boolean equals(Object o) { - return o instanceof ItemStack && - isSimilar((ItemStack) o) && ((ItemStack) o).getAmount() == getAmount(); - } - - /** - * Checks if this item can be placed on the block. - * This should be enforced only for adventure mode players. - * - * @param block the block's namespaceID - * @return true if it can be placed, false otherwise - */ - public boolean canPlaceOn(String block) { - return canPlaceOn.contains(block); - } - - /** - * Gets the blocks that this item can be placed on - * - * @return the {@link Set} of blocks - */ - public Set getCanPlaceOn() { - return canPlaceOn; - } - - /** - * Checks if this item is allowed to break the provided block. - * This should be enforced only for adventure mode players. - * - * @param block the block's namespaceID - * @return true if this item can destroy it, otherwise false - */ - public boolean canDestroy(String block) { - return canDestroy.contains(block); - } - - /** - * Gets the blocks that this item can destroy - * - * @return the {@link Set} of blocks - */ - public Set getCanDestroy() { - return canDestroy; - } - - /** - * Gets the item damage (durability). - * - * @return the item damage - */ - public int getDamage() { - return damage; - } - - /** - * Sets the item damage (durability). - * - * @param damage the item damage - */ - public void setDamage(int damage) { - this.damage = damage; - } - - /** - * Gets the item amount. - *

- * WARNING: for amount computation it would be better to use {@link StackingRule#getAmount(ItemStack)} - * to support all stacking implementation. - * - * @return the item amount - */ - public byte getAmount() { - return amount; - } - - /** - * Changes the item amount. - *

- * WARNING: for amount computation it would be better to use {@link StackingRule#getAmount(ItemStack)} - * to support all stacking implementation. - * - * @param amount the new item amount - */ - public void setAmount(byte amount) { - this.amount = amount; - } - - /** - * Gets the special meta object for this item. - *

- * Can be null if not any. - * - * @return the item meta - */ - @Nullable - public ItemMeta getItemMeta() { - return itemMeta; - } - - /** - * Changes the item meta linked to this item. - *

- * WARNING: be sure to have nbt data useful for this item, items should automatically get the appropriate - * item meta. - * - * @param itemMeta the new item meta - */ - public void setItemMeta(@Nullable ItemMeta itemMeta) { - this.itemMeta = itemMeta; - } - - /** - * Gets the item display name. - * - * @return the item display name, can be null if not present - * @deprecated Use {@link #getDisplayName()} - */ - @Deprecated - @Nullable - public JsonMessage getDisplayNameJson() { - return JsonMessage.fromComponent(displayName); - } - - /** - * Gets the item display name. - * - * @return the item display name, can be null if not present - */ - @Nullable - public Component getDisplayName() { - return displayName; - } - - /** - * Sets the item display name. - * - * @param displayName the item display name - * @deprecated Use {@link #setDisplayName(Component)} - */ - @Deprecated - public void setDisplayName(@Nullable JsonMessage displayName) { - this.setDisplayName(displayName == null ? null : displayName.asComponent()); - } - - /** - * Sets the item display name. - * - * @param displayName the item display name - */ - public void setDisplayName(@Nullable Component displayName) { - this.displayName = displayName; - } - - /** - * Gets if the item has a display name. - * - * @return the item display name - */ - public boolean hasDisplayName() { - return displayName != null; - } - - /** - * Gets the item lore. - * - * @return a modifiable list containing the item lore, can be empty if not present - * @deprecated Use {@link #getLore()} - */ - @Deprecated - @NotNull - public List getLoreJson() { - return lore.stream().map(JsonMessage::fromComponent).collect(Collectors.toList()); - } - - /** - * Gets the item lore. - * - * @return a modifiable list containing the item lore, can be empty if not present - */ - @NotNull - public List getLore() { - return lore; - } - - /** - * Sets the item lore. - * - * @param lore the item lore, can be empty to remove - * @deprecated Use {@link #setLore} - */ - @Deprecated - public void setLoreJson(@NotNull List lore) { - this.lore = lore.stream().map(JsonMessage::asComponent).collect(Collectors.toList()); - } - - /** - * Sets the item lore. - * - * @param lore the item lore, can be empty to remove - */ - @NotNull - public void setLore(List lore) { - this.lore = lore; - } - - /** - * Gets if the item has a lore. - * - * @return true if the item has lore, false otherwise - */ - public boolean hasLore() { - return lore != null && !lore.isEmpty(); - } - - /** - * Gets the item enchantment map. - * - * @return an unmodifiable map containing the item enchantments - */ - @NotNull - public Map getEnchantmentMap() { - return Collections.unmodifiableMap(enchantmentMap); - } - - /** - * Sets an enchantment level. - * - * @param enchantment the enchantment type - * @param level the enchantment level - */ - public void setEnchantment(@NotNull Enchantment enchantment, short level) { - if (level < 1) { - removeEnchantment(enchantment); - return; - } - - this.enchantmentMap.put(enchantment, level); - } - - /** - * Removes an enchantment. - * - * @param enchantment the enchantment type - */ - public void removeEnchantment(@NotNull Enchantment enchantment) { - this.enchantmentMap.removeShort(enchantment); - } - - /** - * Gets an enchantment level. - * - * @param enchantment the enchantment type - * @return the stored enchantment level, 0 if not present - */ - public int getEnchantmentLevel(@NotNull Enchantment enchantment) { - return this.enchantmentMap.getOrDefault(enchantment, (short) 0); - } - - /** - * Gets the item attributes. - * - * @return an unmodifiable {@link List} containing the item attributes - */ - @NotNull - public List getAttributes() { - return Collections.unmodifiableList(attributes); - } - - /** - * Gets the {@link ItemAttribute} with the specified internal name. - * - * @param internalName the internal name of the attribute - * @return the {@link ItemAttribute} with the internal name, null if not found - */ - public ItemAttribute getAttribute(@NotNull String internalName) { - for (ItemAttribute itemAttribute : attributes) { - if (itemAttribute.getInternalName().equals(internalName)) - return itemAttribute; - } - return null; - } - - /** - * Adds an attribute to the item. - * - * @param itemAttribute the attribute to add - */ - public void addAttribute(@NotNull ItemAttribute itemAttribute) { - this.attributes.add(itemAttribute); - } - - /** - * Removes an attribute to the item. - * - * @param itemAttribute the attribute to remove - */ - public void removeAttribute(@NotNull ItemAttribute itemAttribute) { - this.attributes.remove(itemAttribute); - } - - /** - * Gets the item hide flag. - * - * @return the item hide flag - */ - public int getHideFlag() { - return hideFlag; - } - - /** - * Changes the item hide flag. This is the integer sent when updating the item hide flag. - * - * @param hideFlag the new item hide flag - */ - public void setHideFlag(int hideFlag) { - this.hideFlag = hideFlag; - } - - /** - * Gets the item custom model data. - * - * @return the item custom model data - */ - public int getCustomModelData() { - return customModelData; - } - - /** - * Changes the item custom model data. - * - * @param customModelData the new item custom data model - */ - public void setCustomModelData(int customModelData) { - this.customModelData = customModelData; - } - - /** - * Adds flags to the item. - * - * @param flags the flags to add - */ - public void addItemFlags(@NotNull ItemFlag... flags) { - for (ItemFlag f : flags) { - this.hideFlag |= getBitModifier(f); - } - } - - /** - * Removes flags from the item. - * - * @param flags the flags to remove - */ - public void removeItemFlags(@NotNull ItemFlag... flags) { - for (ItemFlag f : flags) { - this.hideFlag &= ~getBitModifier(f); - } - } - - /** - * Gets the item flags. - * - * @return an unmodifiable {@link Set} containing the item flags - */ - @NotNull - public Set getItemFlags() { - Set currentFlags = EnumSet.noneOf(ItemFlag.class); - - for (ItemFlag f : ItemFlag.values()) { - if (hasItemFlag(f)) { - currentFlags.add(f); - } - } - - return Collections.unmodifiableSet(currentFlags); - } - - /** - * Gets if the item has an item flag. - * - * @param flag the item flag - * @return true if the item has the flag {@code flag}, false otherwise - */ - public boolean hasItemFlag(@NotNull ItemFlag flag) { - final int bitModifier = getBitModifier(flag); - return (this.hideFlag & bitModifier) == bitModifier; - } - - /** - * Gets if the item is unbreakable. - * - * @return true if the item is unbreakable, false otherwise - */ - public boolean isUnbreakable() { - return unbreakable; - } - - /** - * Makes the item unbreakable. - * - * @param unbreakable true to make the item unbreakable, false otherwise - */ - public void setUnbreakable(boolean unbreakable) { - this.unbreakable = unbreakable; - } - - /** - * Gets the unique identifier of this object. - *

- * This value is non persistent and will be randomized once this item is separated with a right-click, - * when copied and when the server restart. It is used internally by the data ownership system. - * - * @return this item unique identifier - */ - @NotNull - public UUID getIdentifier() { - return identifier; - } - - /** - * Gets the item {@link Material}. - * - * @return the item material - */ - @NotNull - public Material getMaterial() { + @Contract(pure = true) + public @NotNull Material getMaterial() { return material; } - /** - * Changes the item {@link Material}. - * - * @param material the new material - */ - public void setMaterial(@NotNull Material material) { - this.material = material; + @Contract(value = "_, -> new", pure = true) + public @NotNull ItemStack with(@NotNull Consumer<@NotNull ItemBuilder> builderConsumer) { + var builder = builder(); + builderConsumer.accept(builder); + return builder.build(); } - /** - * Gets if the item has any nbt tag. - * - * @return true if the item has nbt tag, false otherwise - */ - public boolean hasNbtTag() { - return hasDisplayName() || - hasLore() || - damage != 0 || - isUnbreakable() || - !enchantmentMap.isEmpty() || - !attributes.isEmpty() || - hideFlag != 0 || - customModelData != 0 || - (itemMeta != null && itemMeta.hasNbt()) || - (data != null && !data.isEmpty()) || - !canDestroy.isEmpty() || - !canPlaceOn.isEmpty(); + @Contract(pure = true) + public int getAmount() { + return amount; } - /** - * @deprecated use {@link #clone()} - */ - @Deprecated - @NotNull - public synchronized ItemStack copy() { - return clone(); + @Contract(value = "_, -> new", pure = true) + public @NotNull ItemStack withAmount(int amount) { + return builder().amount(amount).build(); } - /** - * Clones this item stack. - *

- * Be aware that the identifier ({@link #getIdentifier()}) will change. - * - * @return a cloned item stack with a different identifier - */ - @NotNull - @Override - public ItemStack clone() { - try { - ItemStack itemStack = (ItemStack) super.clone(); - itemStack.setDisplayName(displayName); - itemStack.setUnbreakable(unbreakable); - if (lore != null) { - itemStack.setLore(new ArrayList<>(lore)); - } - if (stackingRule != null) { - itemStack.setStackingRule(stackingRule); - } - - itemStack.enchantmentMap = new Object2ShortOpenHashMap<>(enchantmentMap); - itemStack.attributes = new ArrayList<>(attributes); - - itemStack.hideFlag = hideFlag; - itemStack.customModelData = customModelData; - - itemStack.canPlaceOn = new HashSet<>(canPlaceOn); - itemStack.canDestroy = new HashSet<>(canDestroy); - - if (itemMeta != null) - itemStack.itemMeta = itemMeta.clone(); - - final Data data = getData(); - if (data != null) - itemStack.setData(data.clone()); - - return itemStack; - } catch (CloneNotSupportedException e) { - MinecraftServer.getExceptionManager().handleException(e); - return null; - } + @Contract(value = "_, -> new", pure = true) + public @NotNull ItemStack withAmount(@NotNull IntUnaryOperator intUnaryOperator) { + return withAmount(intUnaryOperator.applyAsInt(amount)); } - @Nullable - @Override - public Data getData() { - return data; + @Contract(value = "_, _ -> new", pure = true) + public > @NotNull ItemStack withMeta(Class metaType, Consumer metaConsumer) { + return builder().meta(metaType, metaConsumer).build(); } - /** - * Sets the data of this item. - * - * @param data the new {@link Data} of this container, null to remove it - */ - @Override - public void setData(@Nullable Data data) { - DATA_OWNERSHIP.saveOwnObject(getIdentifier(), data); - this.data = data; + @Contract(pure = true) + public @Nullable Component getDisplayName() { + return meta.getDisplayName(); } - /** - * Gets the item {@link StackingRule}. - * - * @return the item stacking rule - */ - @NotNull - public StackingRule getStackingRule() { + @Contract(value = "_, -> new", pure = true) + public @NotNull ItemStack withDisplayName(@Nullable Component displayName) { + return builder().displayName(displayName).build(); + } + + @Contract(value = "_, -> new", pure = true) + public @NotNull ItemStack withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) { + return withDisplayName(componentUnaryOperator.apply(getDisplayName())); + } + + @Contract(pure = true) + public @Nullable List<@NotNull Component> getLore() { + return meta.getLore(); + } + + @Contract(value = "_, -> new", pure = true) + public @NotNull ItemStack withLore(@Nullable List<@NotNull Component> lore) { + return builder().lore(lore).build(); + } + + @Contract(value = "_, -> new", pure = true) + public @NotNull ItemStack withLore(@NotNull UnaryOperator<@Nullable List<@NotNull Component>> loreUnaryOperator) { + return withLore(loreUnaryOperator.apply(getLore())); + } + + public @NotNull StackingRule getStackingRule() { return stackingRule; } - /** - * Changes the {@link StackingRule} of the item. - * - * @param stackingRule the new item stacking rule - * @throws NullPointerException if {@code stackingRule} is null - */ - public void setStackingRule(@NotNull StackingRule stackingRule) { - this.stackingRule = stackingRule; + public @NotNull ItemMeta getMeta() { + return meta; } - /** - * Consumes this item by a specific amount. - *

- * Will return null if the amount's amount isn't enough. - * - * @param amount the quantity to consume - * @return the new item with the updated amount, null if the item cannot be consumed by this much - */ - @Nullable - public ItemStack consume(int amount) { - final int currentAmount = stackingRule.getAmount(this); - if (currentAmount < amount) - return null; - return stackingRule.apply(this, currentAmount - amount); + public boolean isSimilar(@NotNull ItemStack itemStack) { + return material.equals(itemStack.material) && + meta.equals(itemStack.meta); } - private byte getBitModifier(@NotNull ItemFlag hideFlag) { - return (byte) (1 << hideFlag.ordinal()); + public boolean isAir() { + return equals(AIR); } - /** - * Finds the {@link ItemMeta} based on the material type. - * - * @return the item meta, null if none found - */ - @Nullable - private ItemMeta findMeta() { - if (material == Material.POTION || - material == Material.LINGERING_POTION || - material == Material.SPLASH_POTION || - material == Material.TIPPED_ARROW) - return new PotionMeta(); - - if (material == Material.FILLED_MAP) - return new MapMeta(); - - if (material == Material.COMPASS) - return new CompassMeta(); - - if (material == Material.ENCHANTED_BOOK) - return new EnchantedBookMeta(); - - if (material == Material.CROSSBOW) - return new CrossbowMeta(); - - if (material == Material.WRITABLE_BOOK) - return new WritableBookMeta(); - - if (material == Material.WRITTEN_BOOK) - return new WrittenBookMeta(); - - if (material == Material.FIREWORK_STAR) - return new FireworkEffectMeta(); - - if (material == Material.FIREWORK_ROCKET) - return new FireworkMeta(); - - if (material == Material.PLAYER_HEAD) - return new PlayerHeadMeta(); - - if (material == Material.LEATHER_HELMET || - material == Material.LEATHER_CHESTPLATE || - material == Material.LEATHER_LEGGINGS || - material == Material.LEATHER_BOOTS) - return new LeatherArmorMeta(); - - return null; - } - - /** - * Creates a {@link NBTCompound} containing the data of this item. - *

- * WARNING: modifying the returned nbt will not affect the item. - * - * @return this item nbt - */ - @NotNull - public NBTCompound toNBT() { - NBTCompound compound = new NBTCompound() - .setByte("Count", amount) - .setString("id", material.getName()); - if (hasNbtTag()) { - NBTCompound additionalTag = new NBTCompound(); - NBTUtils.saveDataIntoNBT(this, additionalTag); - compound.set("tag", additionalTag); - } - return compound; - } - - /** - * WARNING: not implemented yet. - *

- * This is be called each time an item is serialized to be send to a player, - * can be used to customize the display of the item based on player data. - * - * @param player the player - * @return the custom {@link ItemDisplay} for {@code player}, - * null to use the normal item display name & lore - */ - public ItemDisplay getCustomDisplay(Player player) { - throw new UnsupportedOperationException("Not implemented yet"); - } - - @Override - public @NotNull HoverEvent asHoverEvent(@NotNull UnaryOperator op) { - return HoverEvent.showItem(op.apply(ShowItem.of(this.material, this.amount, NBTUtils.asBinaryTagHolder(this.toNBT().getCompound("tag"))))); - } - - // Callback events - - /** - * Called when the player right clicks with this item. - * - * @param player the player who used the item - * @param hand the hand used - */ - public void onRightClick(@NotNull Player player, @NotNull Player.Hand hand) { - } - - /** - * Called when the player left clicks with this item. - * - * @param player the player who used the item - * @param hand the hand used - */ - public void onLeftClick(@NotNull Player player, @NotNull Player.Hand hand) { - } - - /** - * Called when the player right clicks with this item on a block. - * - * @param player the player who used the item - * @param hand the hand used - * @param position the position of the interacted block - * @param blockFace the block face - * @return true if it prevents normal item use (placing blocks for instance) - */ - public boolean onUseOnBlock(@NotNull Player player, @NotNull Player.Hand hand, @NotNull BlockPosition position, @NotNull Direction blockFace) { - return false; - } - - /** - * Called when the player click on this item on an inventory. - *

- * Executed before any events. - * - * @param player the player who clicked on the item - * @param clickType the click type - * @param slot the slot clicked - * @param playerInventory true if the click is in the player inventory - */ - public void onInventoryClick(@NotNull Player player, @NotNull ClickType clickType, int slot, boolean playerInventory) { - + @Contract(value = "-> new", pure = true) + protected @NotNull ItemBuilder builder() { + return new ItemBuilder(material, meta.builder()) + .amount(amount); } } diff --git a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java index 9926a41b3..ff1d3d879 100644 --- a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java @@ -4,7 +4,6 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.registry.Registries; import net.minestom.server.utils.NBTUtils; -import net.minestom.server.utils.clone.CloneUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jglrxavpok.hephaistos.nbt.NBTCompound; @@ -137,7 +136,7 @@ public class CrossbowMeta extends ItemMeta { final NBTCompound tagsCompound = projectileCompound.getCompound("tag"); - ItemStack itemStack = new ItemStack(material, count); + ItemStack itemStack = ItemStack.of(material, count); NBTUtils.loadDataIntoItem(itemStack, tagsCompound); index++; @@ -184,9 +183,9 @@ public class CrossbowMeta extends ItemMeta { public ItemMeta clone() { CrossbowMeta crossbowMeta = (CrossbowMeta) super.clone(); crossbowMeta.triple = triple; - crossbowMeta.projectile1 = CloneUtils.optionalClone(projectile1); - crossbowMeta.projectile2 = CloneUtils.optionalClone(projectile2); - crossbowMeta.projectile3 = CloneUtils.optionalClone(projectile3); + crossbowMeta.projectile1 = projectile1; + crossbowMeta.projectile2 = projectile2; + crossbowMeta.projectile3 = projectile3; crossbowMeta.charged = charged; @@ -195,12 +194,9 @@ public class CrossbowMeta extends ItemMeta { @NotNull private NBTCompound getItemCompound(@NotNull ItemStack itemStack) { - NBTCompound compound = new NBTCompound(); - - compound.setByte("Count", itemStack.getAmount()); + NBTCompound compound = NBTUtils.metaToNBT(itemStack.getMeta()); + compound.setByte("Count", (byte) itemStack.getAmount()); compound.setString("id", itemStack.getMaterial().getName()); - NBTUtils.saveDataIntoNBT(itemStack, compound); - return compound; } } diff --git a/src/main/java/net/minestom/server/item/metadata/ItemMeta.java b/src/main/java/net/minestom/server/item/metadata/ItemMeta.java index 4e200e331..72effbebe 100644 --- a/src/main/java/net/minestom/server/item/metadata/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/ItemMeta.java @@ -1,7 +1,6 @@ package net.minestom.server.item.metadata; import net.minestom.server.MinecraftServer; -import net.minestom.server.item.ItemStack; import net.minestom.server.utils.clone.PublicCloneable; import org.jetbrains.annotations.NotNull; import org.jglrxavpok.hephaistos.nbt.NBTCompound; diff --git a/src/main/java/net/minestom/server/item/metadata/PotionMeta.java b/src/main/java/net/minestom/server/item/metadata/PotionMeta.java index b7ac76db9..6d84324ac 100644 --- a/src/main/java/net/minestom/server/item/metadata/PotionMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/PotionMeta.java @@ -18,7 +18,7 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** - * Item meta for + * ItemStack meta for * {@link net.minestom.server.item.Material#POTION}, * {@link net.minestom.server.item.Material#LINGERING_POTION}, * {@link net.minestom.server.item.Material#SPLASH_POTION}, diff --git a/src/main/java/net/minestom/server/item/rule/VanillaStackingRule.java b/src/main/java/net/minestom/server/item/rule/VanillaStackingRule.java index 04261a7a2..7edbf6a2a 100644 --- a/src/main/java/net/minestom/server/item/rule/VanillaStackingRule.java +++ b/src/main/java/net/minestom/server/item/rule/VanillaStackingRule.java @@ -25,10 +25,9 @@ public class VanillaStackingRule extends StackingRule { @Override public ItemStack apply(@NotNull ItemStack item, int newAmount) { if (newAmount <= 0) - return ItemStack.getAirItem(); + return ItemStack.AIR; - item.setAmount((byte) newAmount); - return item; + return item.withAmount(newAmount); } @Override diff --git a/src/main/java/net/minestom/server/listener/AnimationListener.java b/src/main/java/net/minestom/server/listener/AnimationListener.java index 571f2586a..c40511a3b 100644 --- a/src/main/java/net/minestom/server/listener/AnimationListener.java +++ b/src/main/java/net/minestom/server/listener/AnimationListener.java @@ -10,7 +10,7 @@ public class AnimationListener { public static void animationListener(ClientAnimationPacket packet, Player player) { final Player.Hand hand = packet.hand; final ItemStack itemStack = player.getItemInHand(hand); - itemStack.onLeftClick(player, hand); + //itemStack.onLeftClick(player, hand); PlayerHandAnimationEvent handAnimationEvent = new PlayerHandAnimationEvent(player, hand); player.callCancellableEvent(PlayerHandAnimationEvent.class, handAnimationEvent, () -> { switch (hand) { diff --git a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java index bd51a6775..1a7a6bb13 100644 --- a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java +++ b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java @@ -52,7 +52,8 @@ public class BlockPlacementListener { final ItemStack usedItem = player.getItemInHand(hand); // Interact at block - final boolean cancel = usedItem.onUseOnBlock(player, hand, blockPosition, direction); + // FIXME: onUseOnBlock + final boolean cancel = false;//usedItem.onUseOnBlock(player, hand, blockPosition, direction); PlayerBlockInteractEvent playerBlockInteractEvent = new PlayerBlockInteractEvent(player, blockPosition, hand, blockFace); playerBlockInteractEvent.setCancelled(cancel); playerBlockInteractEvent.setBlockingItemUse(cancel); @@ -85,7 +86,8 @@ public class BlockPlacementListener { canPlaceBlock = false; //Spectators can't place blocks } else if (player.getGameMode() == GameMode.ADVENTURE) { //Check if the block can placed on the block - canPlaceBlock = usedItem.canPlaceOn(instance.getBlock(blockPosition).getName()); + // FIXME: canPlaceOn + canPlaceBlock = true;//usedItem.canPlaceOn(instance.getBlock(blockPosition).getName()); } } @@ -166,11 +168,8 @@ public class BlockPlacementListener { // Block consuming if (playerBlockPlaceEvent.doesConsumeBlock()) { // Consume the block in the player's hand - final ItemStack newUsedItem = usedItem.consume(1); - - if (newUsedItem != null) { - playerInventory.setItemInHand(hand, newUsedItem); - } + final ItemStack newUsedItem = usedItem.getStackingRule().apply(usedItem, usedItem.getAmount() - 1); + playerInventory.setItemInHand(hand, newUsedItem); } } else { refreshChunk = true; diff --git a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java index add48b2a0..1d39f8513 100644 --- a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java @@ -47,11 +47,12 @@ public class PlayerDiggingListener { } else if (player.getGameMode() == GameMode.ADVENTURE) { //Check if the item can break the block with the current item ItemStack itemInMainHand = player.getItemInMainHand(); - if (!itemInMainHand.canDestroy(instance.getBlock(blockPosition).getName())) { + // FIXME: canDestroy + /*if (!itemInMainHand.canDestroy(instance.getBlock(blockPosition).getName())) { sendAcknowledgePacket(player, blockPosition, blockStateId, ClientPlayerDiggingPacket.Status.STARTED_DIGGING, false); return; - } + }*/ } final boolean instantBreak = player.isCreative() || @@ -111,7 +112,7 @@ public class PlayerDiggingListener { } else if (status == ClientPlayerDiggingPacket.Status.DROP_ITEM_STACK) { final ItemStack droppedItemStack = player.getInventory().getItemInMainHand(); - dropItem(player, droppedItemStack, ItemStack.getAirItem()); + dropItem(player, droppedItemStack, ItemStack.AIR); } else if (status == ClientPlayerDiggingPacket.Status.DROP_ITEM) { @@ -123,14 +124,11 @@ public class PlayerDiggingListener { if (handAmount <= dropAmount) { // Drop the whole item without copy - dropItem(player, handItem, ItemStack.getAirItem()); + dropItem(player, handItem, ItemStack.AIR); } else { // Drop a single item, need a copy - ItemStack droppedItemStack2 = handItem.clone(); + ItemStack droppedItemStack2 = stackingRule.apply(handItem, dropAmount); - droppedItemStack2 = stackingRule.apply(droppedItemStack2, dropAmount); - - handItem = handItem.clone(); // Force the copy handItem = stackingRule.apply(handItem, handAmount - dropAmount); dropItem(player, droppedItemStack2, handItem); diff --git a/src/main/java/net/minestom/server/listener/UseItemListener.java b/src/main/java/net/minestom/server/listener/UseItemListener.java index 13f1d9526..8e008ba6d 100644 --- a/src/main/java/net/minestom/server/listener/UseItemListener.java +++ b/src/main/java/net/minestom/server/listener/UseItemListener.java @@ -1,7 +1,6 @@ package net.minestom.server.listener; import net.minestom.server.entity.Player; -import net.minestom.server.event.item.ArmorEquipEvent; import net.minestom.server.event.player.PlayerItemAnimationEvent; import net.minestom.server.event.player.PlayerPreEatEvent; import net.minestom.server.event.player.PlayerUseItemEvent; @@ -16,7 +15,7 @@ public class UseItemListener { final PlayerInventory inventory = player.getInventory(); final Player.Hand hand = packet.hand; ItemStack itemStack = hand == Player.Hand.MAIN ? inventory.getItemInMainHand() : inventory.getItemInOffHand(); - itemStack.onRightClick(player, hand); + //itemStack.onRightClick(player, hand); PlayerUseItemEvent useItemEvent = new PlayerUseItemEvent(player, hand, itemStack); player.callEvent(PlayerUseItemEvent.class, useItemEvent); diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowPacket.java index bc2935457..779ce8bb1 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientClickWindowPacket.java @@ -13,7 +13,7 @@ public class ClientClickWindowPacket extends ClientPlayPacket { public byte button; public short actionNumber; public int mode; - public ItemStack item = ItemStack.getAirItem(); + public ItemStack item = ItemStack.AIR; @Override public void read(@NotNull BinaryReader reader) { diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientCreativeInventoryActionPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientCreativeInventoryActionPacket.java index d70b26db3..2cf718f2f 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientCreativeInventoryActionPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientCreativeInventoryActionPacket.java @@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; public class ClientCreativeInventoryActionPacket extends ClientPlayPacket { public short slot; - public ItemStack item = ItemStack.getAirItem(); + public ItemStack item = ItemStack.AIR; @Override public void read(@NotNull BinaryReader reader) { diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientEditBookPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientEditBookPacket.java index 910bae4aa..c3e662ac8 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientEditBookPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientEditBookPacket.java @@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull; public class ClientEditBookPacket extends ClientPlayPacket { - public ItemStack book = ItemStack.getAirItem(); + public ItemStack book = ItemStack.AIR; public boolean isSigning; public Player.Hand hand = Player.Hand.MAIN; diff --git a/src/main/java/net/minestom/server/network/packet/client/play/ClientNameItemPacket.java b/src/main/java/net/minestom/server/network/packet/client/play/ClientNameItemPacket.java index 180300b18..664b12433 100644 --- a/src/main/java/net/minestom/server/network/packet/client/play/ClientNameItemPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/play/ClientNameItemPacket.java @@ -17,7 +17,7 @@ public class ClientNameItemPacket extends ClientPlayPacket { @Override public void write(@NotNull BinaryWriter writer) { if(itemName.length() > Short.MAX_VALUE) { - throw new IllegalArgumentException("Item name cannot be longer than Short.MAX_VALUE characters!"); + throw new IllegalArgumentException("ItemStack name cannot be longer than Short.MAX_VALUE characters!"); } writer.writeSizedString(itemName); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java index 0f9936ef0..b8b3d5d32 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/AdvancementsPacket.java @@ -2,8 +2,6 @@ package net.minestom.server.network.packet.server.play; import net.kyori.adventure.text.Component; import net.minestom.server.advancements.FrameType; -import net.minestom.server.chat.ColoredText; -import net.minestom.server.chat.JsonMessage; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.ComponentHoldingServerPacket; import net.minestom.server.network.packet.server.ServerPacket; @@ -27,7 +25,8 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket { public String[] identifiersToRemove = new String[0]; public ProgressMapping[] progressMappings = new ProgressMapping[0]; - public AdvancementsPacket() {} + public AdvancementsPacket() { + } @Override public void write(@NotNull BinaryWriter writer) { @@ -151,14 +150,14 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket { @Override public void read(@NotNull BinaryReader reader) { boolean hasParent = reader.readBoolean(); - if(hasParent) { + if (hasParent) { parentIdentifier = reader.readSizedString(Integer.MAX_VALUE); } else { parentIdentifier = null; } boolean hasDisplay = reader.readBoolean(); - if(hasDisplay) { + if (hasDisplay) { displayData = new DisplayData(); displayData.read(reader); } else { @@ -179,7 +178,7 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket { public static class DisplayData implements Writeable, Readable { public Component title = Component.empty(); // Only text public Component description = Component.empty(); // Only text - public ItemStack icon = ItemStack.getAirItem(); + public ItemStack icon = ItemStack.AIR; public FrameType frameType = FrameType.TASK; public int flags; public String backgroundTexture = ""; @@ -207,7 +206,7 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket { icon = reader.readItemStack(); frameType = FrameType.values()[reader.readVarInt()]; flags = reader.readInt(); - if((flags & 0x1) != 0) { + if ((flags & 0x1) != 0) { backgroundTexture = reader.readSizedString(Integer.MAX_VALUE); } else { backgroundTexture = null; @@ -304,7 +303,7 @@ public class AdvancementsPacket implements ComponentHoldingServerPacket { @Override public void read(@NotNull BinaryReader reader) { achieved = reader.readBoolean(); - if(achieved) { + if (achieved) { dateOfAchieving = reader.readLong(); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java index ef99c2800..3768ad4ff 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/DeclareRecipesPacket.java @@ -14,7 +14,8 @@ public class DeclareRecipesPacket implements ServerPacket { public DeclaredRecipe[] recipes = new DeclaredRecipe[0]; - public DeclareRecipesPacket() {} + public DeclareRecipesPacket() { + } @Override public void write(@NotNull BinaryWriter writer) { @@ -68,7 +69,7 @@ public class DeclareRecipesPacket implements ServerPacket { break; default: - throw new UnsupportedOperationException("Unrecognized type: "+type+" (id is "+id+")"); + throw new UnsupportedOperationException("Unrecognized type: " + type + " (id is " + id + ")"); } } } @@ -193,7 +194,7 @@ public class DeclareRecipesPacket implements ServerPacket { width = reader.readVarInt(); height = reader.readVarInt(); group = reader.readSizedString(Integer.MAX_VALUE); - ingredients = new Ingredient[width*height]; + ingredients = new Ingredient[width * height]; for (int i = 0; i < width * height; i++) { ingredients[i] = new Ingredient(); ingredients[i].read(reader); @@ -442,7 +443,7 @@ public class DeclareRecipesPacket implements ServerPacket { public void read(@NotNull BinaryReader reader) { group = reader.readSizedString(Integer.MAX_VALUE); ingredient = new Ingredient(); - ingredient.read( reader); + ingredient.read(reader); result = reader.readItemStack(); } } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java index 3a50c4e77..a2e92abdd 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/EntityEquipmentPacket.java @@ -17,7 +17,8 @@ public class EntityEquipmentPacket implements ServerPacket { public Slot[] slots; public ItemStack[] itemStacks; - public EntityEquipmentPacket() {} + public EntityEquipmentPacket() { + } @Override public void write(@NotNull BinaryWriter writer) { @@ -53,7 +54,7 @@ public class EntityEquipmentPacket implements ServerPacket { boolean hasRemaining = true; List slots = new LinkedList<>(); List stacks = new LinkedList<>(); - while(hasRemaining) { + while (hasRemaining) { byte slotEnum = reader.readByte(); hasRemaining = (slotEnum & 0x80) == 0x80; diff --git a/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java index bd4777537..d4d6676fe 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/SetSlotPacket.java @@ -14,7 +14,7 @@ public class SetSlotPacket implements ServerPacket { public ItemStack itemStack; public SetSlotPacket() { - itemStack = ItemStack.getAirItem(); + itemStack = ItemStack.AIR; } @Override diff --git a/src/main/java/net/minestom/server/network/packet/server/play/TradeListPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/TradeListPacket.java index 9d559616a..0ff36a2f7 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/TradeListPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/TradeListPacket.java @@ -96,7 +96,7 @@ public class TradeListPacket implements ServerPacket { result = reader.readItemStack(); boolean hasSecondItem = reader.readBoolean(); - if(hasSecondItem) { + if (hasSecondItem) { inputItem2 = reader.readItemStack(); } else { inputItem2 = null; diff --git a/src/main/java/net/minestom/server/recipe/ShapedRecipe.java b/src/main/java/net/minestom/server/recipe/ShapedRecipe.java index 529b2142f..0add30148 100644 --- a/src/main/java/net/minestom/server/recipe/ShapedRecipe.java +++ b/src/main/java/net/minestom/server/recipe/ShapedRecipe.java @@ -17,11 +17,11 @@ public abstract class ShapedRecipe extends Recipe { private ItemStack result; protected ShapedRecipe(@NotNull String recipeId, - int width, - int height, - @NotNull String group, - @Nullable List ingredients, - @NotNull ItemStack result) { + int width, + int height, + @NotNull String group, + @Nullable List ingredients, + @NotNull ItemStack result) { super(RecipeType.SHAPED, recipeId); this.width = width; this.height = height; diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java index 3c967c6df..9a23afb68 100644 --- a/src/main/java/net/minestom/server/utils/NBTUtils.java +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -9,18 +9,16 @@ import net.minestom.server.adventure.AdventureSerializer; import net.minestom.server.attribute.Attribute; import net.minestom.server.attribute.AttributeOperation; import net.minestom.server.data.Data; -import net.minestom.server.data.DataType; import net.minestom.server.inventory.Inventory; import net.minestom.server.item.Enchantment; +import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.attribute.AttributeSlot; import net.minestom.server.item.attribute.ItemAttribute; -import net.minestom.server.item.metadata.ItemMeta; import net.minestom.server.registry.Registries; import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryWriter; -import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,7 +28,10 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.StringReader; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; // for lack of a better name public final class NBTUtils { @@ -48,6 +49,7 @@ public final class NBTUtils { /** * Turns an {@link NBTCompound} into an Adventure {@link BinaryTagHolder}. + * * @param tag the tag, if any * @return the binary tag holder, or {@code null} if the tag was null */ @@ -73,7 +75,7 @@ public final class NBTUtils { if (item == Material.AIR) { item = Material.STONE; } - ItemStack stack = new ItemStack(item, tag.getByte("Count")); + ItemStack stack = ItemStack.of(item, tag.getByte("Count")); if (tag.containsKey("tag")) { loadDataIntoItem(stack, tag.getCompound("tag")); } @@ -86,12 +88,11 @@ public final class NBTUtils { final ItemStack stack = inventory.getItemStack(i); NBTCompound nbt = new NBTCompound(); - NBTCompound tag = new NBTCompound(); - saveDataIntoNBT(stack, tag); + NBTCompound tag = metaToNBT(stack.getMeta()); nbt.set("tag", tag); nbt.setByte("Slot", (byte) i); - nbt.setByte("Count", stack.getAmount()); + nbt.setByte("Count", (byte) stack.getAmount()); nbt.setString("id", stack.getMaterial().getName()); list.add(nbt); @@ -113,23 +114,23 @@ public final class NBTUtils { nbt.set(listName, enchantList); } - @Nullable + @NotNull public static ItemStack readItemStack(@NotNull BinaryReader reader) { final boolean present = reader.readBoolean(); if (!present) { - return ItemStack.getAirItem(); + return ItemStack.AIR; } final int id = reader.readVarInt(); if (id == -1) { // Drop mode - return ItemStack.getAirItem(); + return ItemStack.AIR; } final Material material = Material.fromId((short) id); final byte count = reader.readByte(); - ItemStack item = new ItemStack(material, count); + ItemStack item = ItemStack.of(material, count); try { final NBT itemNBT = reader.readTag(); @@ -146,7 +147,7 @@ public final class NBTUtils { @SuppressWarnings("ConstantConditions") public static void loadDataIntoItem(@NotNull ItemStack item, @NotNull NBTCompound nbt) { - if (nbt.containsKey("Damage")) item.setDamage(nbt.getInt("Damage")); + /*if (nbt.containsKey("Damage")) item.setDamage(nbt.getInt("Damage")); if (nbt.containsKey("Unbreakable")) item.setUnbreakable(nbt.getAsByte("Unbreakable") == 1); if (nbt.containsKey("HideFlags")) item.setHideFlag(nbt.getInt("HideFlags")); if (nbt.containsKey("display")) { @@ -257,7 +258,7 @@ public final class NBTUtils { NBTList canPlaceOn = nbt.getList("CanDestroy"); canPlaceOn.forEach(x -> item.getCanDestroy().add(x.getValue())); } - } + }*/ } public static void loadEnchantments(NBTList enchantments, EnchantmentSetter setter) { @@ -273,85 +274,74 @@ public final class NBTUtils { } } - public static void writeItemStack(BinaryWriter packet, ItemStack itemStack) { - if (itemStack == null || itemStack.isAir()) { + public static void writeItemStack(BinaryWriter packet, @NotNull ItemStack itemStack) { + if (itemStack.isAir()) { packet.writeBoolean(false); } else { packet.writeBoolean(true); packet.writeVarInt(itemStack.getMaterial().getId()); - packet.writeByte(itemStack.getAmount()); + packet.writeByte((byte) itemStack.getAmount()); - if (!itemStack.hasNbtTag()) { - packet.writeByte((byte) NBTTypes.TAG_End); // No nbt - return; - } - - NBTCompound itemNBT = new NBTCompound(); - - // Vanilla compound - saveDataIntoNBT(itemStack, itemNBT); - - // End custom model data - packet.writeNBT("", itemNBT); + packet.writeNBT("", itemStack.getMeta().toNBT()); } } - public static void saveDataIntoNBT(@NotNull ItemStack itemStack, @NotNull NBTCompound itemNBT) { + public static NBTCompound metaToNBT(@NotNull ItemMeta itemMeta) { + final NBTCompound itemNBT = new NBTCompound(); + // Unbreakable - if (itemStack.isUnbreakable()) { + if (itemMeta.isUnbreakable()) { itemNBT.setInt("Unbreakable", 1); } - // Start damage + // Damage { - final int damage = itemStack.getDamage(); + final int damage = itemMeta.getDamage(); if (damage > 0) { itemNBT.setInt("Damage", damage); } } - // End damage // Display - final boolean hasDisplayName = itemStack.hasDisplayName(); - final boolean hasLore = itemStack.hasLore(); - - if (hasDisplayName || hasLore) { - NBTCompound displayNBT = new NBTCompound(); - if (hasDisplayName) { - final String name = AdventureSerializer.serialize(itemStack.getDisplayName()); - displayNBT.setString("Name", name); - } - - if (hasLore) { - final List lore = itemStack.getLore(); - - final NBTList loreNBT = new NBTList<>(NBTTypes.TAG_String); - for (Component line : lore) { - loreNBT.add(new NBTString(GsonComponentSerializer.gson().serialize(line))); - } - displayNBT.set("Lore", loreNBT); - } - - itemNBT.set("display", displayNBT); - } - // End display - - // Start enchantment { - final Map enchantmentMap = itemStack.getEnchantmentMap(); - if (!enchantmentMap.isEmpty()) { - writeEnchant(itemNBT, "Enchantments", enchantmentMap); + final var displayName = itemMeta.getDisplayName(); + final var lore = itemMeta.getLore(); + final boolean hasDisplayName = displayName != null; + final boolean hasLore = !lore.isEmpty(); + if (hasDisplayName || hasLore) { + NBTCompound displayNBT = new NBTCompound(); + if (hasDisplayName) { + final String name = AdventureSerializer.serialize(displayName); + displayNBT.setString("Name", name); + } + + if (hasLore) { + final NBTList loreNBT = new NBTList<>(NBTTypes.TAG_String); + for (Component line : lore) { + loreNBT.add(new NBTString(GsonComponentSerializer.gson().serialize(line))); + } + displayNBT.set("Lore", loreNBT); + } + + itemNBT.set("display", displayNBT); + } + } + + // Enchantment + { + final var enchantmentMap = itemMeta.getEnchantmentMap(); + if (!enchantmentMap.isEmpty()) { + NBTUtils.writeEnchant(itemNBT, "Enchantments", enchantmentMap); } } - // End enchantment // Start attribute { - final List itemAttributes = itemStack.getAttributes(); - if (!itemAttributes.isEmpty()) { + final var attributes = itemMeta.getAttributes(); + if (!attributes.isEmpty()) { NBTList attributesNBT = new NBTList<>(NBTTypes.TAG_Compound); - for (ItemAttribute itemAttribute : itemAttributes) { + for (ItemAttribute itemAttribute : attributes) { final UUID uuid = itemAttribute.getUuid(); attributesNBT.add( new NBTCompound() @@ -370,7 +360,7 @@ public final class NBTUtils { // Start hide flags { - final int hideFlag = itemStack.getHideFlag(); + final int hideFlag = itemMeta.getHideFlag(); if (hideFlag != 0) { itemNBT.setInt("HideFlags", hideFlag); } @@ -379,135 +369,14 @@ public final class NBTUtils { // Start custom model data { - final int customModelData = itemStack.getCustomModelData(); + final int customModelData = itemMeta.getCustomModelData(); if (customModelData != 0) { itemNBT.setInt("CustomModelData", customModelData); } } // End custom model data - // Start custom meta - { - final ItemMeta itemMeta = itemStack.getItemMeta(); - if (itemMeta != null) { - itemMeta.write(itemNBT); - } - } - // End custom meta - - // Start ownership - { - final Data data = itemStack.getData(); - if (data != null && !data.isEmpty()) { - final UUID identifier = itemStack.getIdentifier(); - itemNBT.setString(ItemStack.OWNERSHIP_DATA_KEY, identifier.toString()); - } - } - // End ownership - - //CanDestroy - { - Set canDestroy = itemStack.getCanDestroy(); - if (canDestroy.size() > 0) { - NBTList list = new NBTList<>(NBTTypes.TAG_String); - canDestroy.forEach(x -> list.add(new NBTString(x))); - itemNBT.set("CanDestroy", list); - } - } - - //CanDestroy - { - Set canPlaceOn = itemStack.getCanPlaceOn(); - if (canPlaceOn.size() > 0) { - NBTList list = new NBTList<>(NBTTypes.TAG_String); - canPlaceOn.forEach(x -> list.add(new NBTString(x))); - itemNBT.set("CanPlaceOn", list); - } - } - } - - /** - * Converts an object into its {@link NBT} equivalent. - *

- * If {@code type} is not a primitive type or primitive array and {@code supportDataType} is true, - * the data will be encoded with the appropriate {@link DataType} into a byte array. - * - * @param value the value to convert - * @param type the type of the value, used to know which {@link DataType} to use if {@code value} is not a primitive type - * @param supportDataType true to allow using a {@link DataType} to encode {@code value} into a byte array if not a primitive type - * @return the converted value, null if {@code type} is not a primitive type and {@code supportDataType} is false - */ - @Nullable - public static NBT toNBT(@NotNull Object value, @NotNull Class type, boolean supportDataType) { - type = PrimitiveConversion.getObjectClass(type); - if (type.equals(Boolean.class)) { - // No boolean type in NBT - return new NBTByte((byte) (((boolean) value) ? 1 : 0)); - } else if (type.equals(Byte.class)) { - return new NBTByte((byte) value); - } else if (type.equals(Character.class)) { - // No char type in NBT - return new NBTShort((short) value); - } else if (type.equals(Short.class)) { - return new NBTShort((short) value); - } else if (type.equals(Integer.class)) { - return new NBTInt((int) value); - } else if (type.equals(Long.class)) { - return new NBTLong((long) value); - } else if (type.equals(Float.class)) { - return new NBTFloat((float) value); - } else if (type.equals(Double.class)) { - return new NBTDouble((double) value); - } else if (type.equals(String.class)) { - return new NBTString((String) value); - } else if (type.equals(Byte[].class)) { - return new NBTByteArray((byte[]) value); - } else if (type.equals(Integer[].class)) { - return new NBTIntArray((int[]) value); - } else if (type.equals(Long[].class)) { - return new NBTLongArray((long[]) value); - } else { - if (supportDataType) { - // Custom NBT type, try to encode using the data manager - DataType dataType = MinecraftServer.getDataManager().getDataType(type); - Check.notNull(dataType, "The type '" + type + "' is not registered in DataManager and not a primitive type."); - - BinaryWriter writer = new BinaryWriter(); - dataType.encode(writer, value); - - final byte[] encodedValue = writer.toByteArray(); - - return new NBTByteArray(encodedValue); - } else { - return null; - } - } - } - - /** - * Converts a nbt object to its raw value. - *

- * Currently support number, string, byte/int/long array. - * - * @param nbt the nbt tag to convert - * @return the value representation of a tag - * @throws UnsupportedOperationException if the tag type is not supported - */ - @NotNull - public static Object fromNBT(@NotNull NBT nbt) { - if (nbt instanceof NBTNumber) { - return ((NBTNumber) nbt).getValue(); - } else if (nbt instanceof NBTString) { - return ((NBTString) nbt).getValue(); - } else if (nbt instanceof NBTByteArray) { - return ((NBTByteArray) nbt).getValue(); - } else if (nbt instanceof NBTIntArray) { - return ((NBTIntArray) nbt).getValue(); - } else if (nbt instanceof NBTLongArray) { - return ((NBTLongArray) nbt).getValue(); - } - - throw new UnsupportedOperationException("NBT type " + nbt.getClass() + " is not handled properly."); + return itemNBT; } @FunctionalInterface diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryReader.java b/src/main/java/net/minestom/server/utils/binary/BinaryReader.java index 6dfd30f82..a547228b9 100644 --- a/src/main/java/net/minestom/server/utils/binary/BinaryReader.java +++ b/src/main/java/net/minestom/server/utils/binary/BinaryReader.java @@ -20,7 +20,6 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.UUID; -import java.util.function.BiConsumer; import java.util.function.Supplier; /** @@ -197,6 +196,7 @@ public class BinaryReader extends InputStream { /** * Creates a new object from the given supplier and calls its {@link Readable#read(BinaryReader)} method with this reader + * * @param supplier supplier to create new instances of your object * @param * @return the read object @@ -210,6 +210,7 @@ public class BinaryReader extends InputStream { /** * Reads the length of the array to read as a varint, creates the array to contain the readable objects and call * their respective {@link Readable#read(BinaryReader)} methods. + * * @param supplier supplier to create new instances of your object * @param * @return the read objects @@ -245,13 +246,14 @@ public class BinaryReader extends InputStream { * Records the current position, runs the given Runnable, and then returns the bytes between the position before * running the runnable and the position after. * Can be used to extract a subsection of this reader's buffer with complex data + * * @param extractor the extraction code, simply call the reader's read* methods here. */ public byte[] extractBytes(Runnable extractor) { int startingPosition = getBuffer().readerIndex(); extractor.run(); int endingPosition = getBuffer().readerIndex(); - byte[] output = new byte[endingPosition-startingPosition]; + byte[] output = new byte[endingPosition - startingPosition]; getBuffer().getBytes(startingPosition, output); return output; } diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java b/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java index 5282df7e8..0c9f1a90f 100644 --- a/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java +++ b/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java @@ -180,6 +180,7 @@ public class BinaryWriter extends OutputStream { /** * Writes a JsonMessage to the buffer. * Simply a writeSizedString with message.toString() + * * @param message */ public void writeJsonMessage(JsonMessage message) { @@ -277,6 +278,7 @@ public class BinaryWriter extends OutputStream { /** * Writes the given writeable object into this writer. + * * @param writeable the object to write */ public void write(Writeable writeable) { @@ -286,11 +288,12 @@ public class BinaryWriter extends OutputStream { /** * Writes an array of writeable objects to this writer. Will prepend the binary stream with a var int to denote the * length of the array. + * * @param writeables the array of writeables to write */ public void writeArray(Writeable[] writeables) { writeVarInt(writeables.length); - for(Writeable w : writeables) { + for (Writeable w : writeables) { write(w); } } diff --git a/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java b/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java index 0cef0feec..721e89790 100644 --- a/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java +++ b/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java @@ -100,7 +100,7 @@ public class BiomeParticles { @Override public NBTCompound toNbt() { //todo test count might be wrong type - NBTCompound nbtCompound = item.toNBT(); + NBTCompound nbtCompound = item.getMeta().toNBT(); nbtCompound.setString("type", type); return nbtCompound; } diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 974fe977e..a4f9d6ac8 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -27,7 +27,6 @@ import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.Enchantment; -import net.minestom.server.item.Item; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.meta.CompassMeta; @@ -35,7 +34,6 @@ import net.minestom.server.network.ConnectionManager; import net.minestom.server.ping.ResponseDataConsumer; import net.minestom.server.utils.Position; import net.minestom.server.utils.Vector; -import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.world.DimensionType; @@ -73,7 +71,7 @@ public class PlayerInit { .enchantments(Map.of(Enchantment.KNOCKBACK, (short) 5, Enchantment.EFFICIENCY, (short) 10)) .build(); - Item item = Item.builder(Material.COMPASS) + ItemStack itemStack = ItemStack.builder(Material.COMPASS) .amount(5) .meta(compassMeta) .meta(CompassMeta.class, builder -> { @@ -82,7 +80,7 @@ public class PlayerInit { .displayName(Component.text("displayName")) .build(); - item = item.with(itemBuilder -> itemBuilder + itemStack = itemStack.with(itemBuilder -> itemBuilder .amount(10) .meta(CompassMeta.class, builder -> { builder.lodestonePosition(new Position(5, 0, 0)); @@ -224,21 +222,19 @@ public class PlayerInit { globalEventHandler.addEventCallback(PlayerSpawnEvent.class, event -> { final Player player = event.getPlayer(); - player.setGameMode(GameMode.CREATIVE); + player.setGameMode(GameMode.SURVIVAL); player.setPermissionLevel(4); PlayerInventory inventory = player.getInventory(); - ItemStack itemStack = new ItemStack(Material.STONE, (byte) 64); + ItemStack itemStack = ItemStack.of(Material.STONE, 64); inventory.addItemStack(itemStack); { - ItemStack item = new ItemStack(Material.DIAMOND_CHESTPLATE, (byte) 1); + ItemStack item = ItemStack.builder(Material.DIAMOND_CHESTPLATE) + .displayName(Component.text("test")) + .build(); inventory.setChestplate(item); - item.setDisplayName(ColoredText.of("test")); - - inventory.refreshSlot((short) PlayerInventoryUtils.CHESTPLATE_SLOT); - } //player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 32)); diff --git a/src/test/java/readwritepackets/ReadWritePackets.java b/src/test/java/readwritepackets/ReadWritePackets.java index 56c192e77..5f28d8152 100644 --- a/src/test/java/readwritepackets/ReadWritePackets.java +++ b/src/test/java/readwritepackets/ReadWritePackets.java @@ -47,13 +47,13 @@ public class ReadWritePackets { private Collection checkImplementationPresence(Class packetClass) throws IOException { ClassPath cp = ClassPath.from(ClassLoader.getSystemClassLoader()); List allTests = new LinkedList<>(); - for(ClassPath.ClassInfo classInfo : cp.getAllClasses()) { - if(!classInfo.getPackageName().startsWith("net.minestom.server.network.packet")) + for (ClassPath.ClassInfo classInfo : cp.getAllClasses()) { + if (!classInfo.getPackageName().startsWith("net.minestom.server.network.packet")) continue; try { Class clazz = classInfo.load(); - if(packetClass.isAssignableFrom(clazz) && !clazz.isInterface() && ((clazz.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT)) { - allTests.add(DynamicTest.dynamicTest("WriteThenRead "+clazz.getSimpleName(), () -> { + if (packetClass.isAssignableFrom(clazz) && !clazz.isInterface() && ((clazz.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT)) { + allTests.add(DynamicTest.dynamicTest("WriteThenRead " + clazz.getSimpleName(), () -> { // required for managers to be loaded MinecraftServer.init(); @@ -63,14 +63,13 @@ public class ReadWritePackets { T packet; // exceptions - if(clazz.getSimpleName().equals("EntityEquipmentPacket")) { + if (clazz.getSimpleName().equals("EntityEquipmentPacket")) { // requires at least one slot and one item EntityEquipmentPacket p = new EntityEquipmentPacket(); - p.itemStacks = new ItemStack[] { ItemStack.getAirItem() }; - p.slots = new EntityEquipmentPacket.Slot[] { EntityEquipmentPacket.Slot.MAIN_HAND }; + p.itemStacks = new ItemStack[]{ItemStack.AIR}; + p.slots = new EntityEquipmentPacket.Slot[]{EntityEquipmentPacket.Slot.MAIN_HAND}; packet = (T) p; - } - else { + } else { packet = (T) constructor.newInstance(); } From 22be400fb3283eedd75dd0e614a5bca80db8e736 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 18:14:03 +0200 Subject: [PATCH 15/77] Fix replace typo --- .../net/minestom/codegen/entitytypes/EntityTypeContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generators/java/net/minestom/codegen/entitytypes/EntityTypeContainer.java b/src/generators/java/net/minestom/codegen/entitytypes/EntityTypeContainer.java index 9732ef965..cdd2a37b2 100644 --- a/src/generators/java/net/minestom/codegen/entitytypes/EntityTypeContainer.java +++ b/src/generators/java/net/minestom/codegen/entitytypes/EntityTypeContainer.java @@ -33,7 +33,7 @@ public class EntityTypeContainer implements Comparable { String metaClassName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name.getPath()); // special cases switch (metaClassName) { - case "ItemStack": + case "Item": metaClassName = "ItemEntity"; break; case "Tnt": From 7dcc52de57083f4b7666dbd99afdcb71280e5192 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 18:25:20 +0200 Subject: [PATCH 16/77] Support item stacking, cleanup --- .../net/minestom/server/item/ItemMeta.java | 16 +++++++++++++++- .../net/minestom/server/item/ItemStack.java | 4 ++-- .../packet/server/play/ChunkDataPacket.java | 1 - .../net/minestom/server/utils/NBTUtils.java | 18 +++++++----------- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index a17f843c7..06c64bf71 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -84,13 +84,27 @@ public class ItemMeta implements Cloneable { return customModelData; } - public NBTCompound toNBT() { + public @NotNull NBTCompound toNBT() { if (cache == null) { this.cache = NBTUtils.metaToNBT(this); } return cache; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ItemMeta itemMeta = (ItemMeta) o; + return toNBT().equals(itemMeta.toNBT()); + } + + @Override + public int hashCode() { + return toNBT().hashCode(); + } + protected @NotNull ItemMetaBuilder builder() { return builder.clone(); } diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index 514e99df8..ee8cfa692 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -14,7 +14,7 @@ import java.util.function.UnaryOperator; public class ItemStack { - public static final ItemStack AIR = ItemStack.builder(Material.AIR).build(); + public static final ItemStack AIR = ItemStack.of(Material.AIR); private final UUID uuid = UUID.randomUUID(); private final StackingRule stackingRule = new VanillaStackingRule(64); @@ -34,7 +34,7 @@ public class ItemStack { return new ItemBuilder(material); } - @Contract(value = "_ -> new", pure = true) + @Contract(value = "_ ,_ -> new", pure = true) public static @NotNull ItemStack of(@NotNull Material material, int amount) { return builder(material).amount(amount).build(); } diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java index 18d1f6fb6..8a5a206fa 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java @@ -24,7 +24,6 @@ import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.world.biomes.Biome; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBT; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.jglrxavpok.hephaistos.nbt.NBTException; diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java index 9a23afb68..9a7633947 100644 --- a/src/main/java/net/minestom/server/utils/NBTUtils.java +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -6,15 +6,11 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.util.Codec; import net.minestom.server.MinecraftServer; import net.minestom.server.adventure.AdventureSerializer; -import net.minestom.server.attribute.Attribute; -import net.minestom.server.attribute.AttributeOperation; -import net.minestom.server.data.Data; import net.minestom.server.inventory.Inventory; import net.minestom.server.item.Enchantment; import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.minestom.server.item.attribute.AttributeSlot; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.registry.Registries; import net.minestom.server.utils.binary.BinaryReader; @@ -28,8 +24,6 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.UUID; @@ -286,7 +280,7 @@ public final class NBTUtils { } } - public static NBTCompound metaToNBT(@NotNull ItemMeta itemMeta) { + public static @NotNull NBTCompound metaToNBT(@NotNull ItemMeta itemMeta) { final NBTCompound itemNBT = new NBTCompound(); // Unbreakable @@ -302,7 +296,7 @@ public final class NBTUtils { } } - // Display + // Start display { final var displayName = itemMeta.getDisplayName(); final var lore = itemMeta.getLore(); @@ -326,14 +320,16 @@ public final class NBTUtils { itemNBT.set("display", displayNBT); } } + // End display - // Enchantment + // Start enchantment { final var enchantmentMap = itemMeta.getEnchantmentMap(); if (!enchantmentMap.isEmpty()) { NBTUtils.writeEnchant(itemNBT, "Enchantments", enchantmentMap); } } + // End enchantment // Start attribute { @@ -358,14 +354,14 @@ public final class NBTUtils { } // End attribute - // Start hide flags + // Start hide flag { final int hideFlag = itemMeta.getHideFlag(); if (hideFlag != 0) { itemNBT.setInt("HideFlags", hideFlag); } } - // End hide flags + // End hide flag // Start custom model data { From 2b0c525ca29b443f72fe919e822d123f3962458f Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 19:10:46 +0200 Subject: [PATCH 17/77] Implement ItemStack#equals & use a soft reference to store meta cached NBT --- .../net/minestom/server/item/ItemMeta.java | 11 ++++--- .../net/minestom/server/item/ItemStack.java | 31 +++++++++++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 06c64bf71..aa7176f84 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -29,7 +30,7 @@ public class ItemMeta implements Cloneable { private final int customModelData; - private NBTCompound cache = null; + private SoftReference cache; protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { this.builder = metaBuilder.clone(); @@ -85,10 +86,12 @@ public class ItemMeta implements Cloneable { } public @NotNull NBTCompound toNBT() { - if (cache == null) { - this.cache = NBTUtils.metaToNBT(this); + var nbt = cache != null ? cache.get() : null; + if (nbt == null) { + nbt = NBTUtils.metaToNBT(this); + cache = new SoftReference<>(nbt); } - return cache; + return nbt; } @Override diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index ee8cfa692..a0124c31d 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -111,21 +111,48 @@ public class ItemStack { return withLore(loreUnaryOperator.apply(getLore())); } + @Contract(pure = true) public @NotNull StackingRule getStackingRule() { return stackingRule; } + @Contract(pure = true) public @NotNull ItemMeta getMeta() { return meta; } + @Contract(pure = true) + public boolean isAir() { + return equals(AIR); + } + + @Contract(pure = true) public boolean isSimilar(@NotNull ItemStack itemStack) { return material.equals(itemStack.material) && meta.equals(itemStack.meta); } - public boolean isAir() { - return equals(AIR); + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ItemStack itemStack = (ItemStack) o; + if (uuid.equals(itemStack.uuid)) return true; + + if (amount != itemStack.amount) return false; + if (!stackingRule.equals(itemStack.stackingRule)) return false; + if (material != itemStack.material) return false; + return meta.equals(itemStack.meta); + } + + @Override + public int hashCode() { + int result = stackingRule.hashCode(); + result = 31 * result + material.hashCode(); + result = 31 * result + amount; + result = 31 * result + meta.hashCode(); + return result; } @Contract(value = "-> new", pure = true) From 8d8a22f209527dad7658431a8675400ef46191fe Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 22:14:48 +0200 Subject: [PATCH 18/77] Use original NBT when possible --- .../minecraft/ArgumentItemStack.java | 6 +- .../net/minestom/server/item/ItemBuilder.java | 9 +- .../net/minestom/server/item/ItemMeta.java | 23 ++++- .../minestom/server/item/ItemMetaBuilder.java | 45 +++++++++ .../net/minestom/server/item/ItemStack.java | 5 + .../server/item/meta/CompassMeta.java | 35 +++++++ .../server/item/metadata/CrossbowMeta.java | 3 +- .../net/minestom/server/utils/NBTUtils.java | 92 ++++++++++--------- 8 files changed, 165 insertions(+), 53 deletions(-) diff --git a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java index 746343557..84453f644 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/minecraft/ArgumentItemStack.java @@ -47,8 +47,6 @@ public class ArgumentItemStack extends Argument { final String materialName = input.substring(0, nbtIndex); final Material material = Registries.getMaterial(materialName); - ItemStack itemStack = ItemStack.of(material); - final String sNBT = input.substring(nbtIndex).replace("\\\"", "\""); NBTCompound compound; @@ -58,9 +56,7 @@ public class ArgumentItemStack extends Argument { throw new ArgumentSyntaxException("Item NBT is invalid", input, INVALID_NBT); } - NBTUtils.loadDataIntoItem(itemStack, compound); - - return itemStack; + return NBTUtils.loadItem(material, 1, compound); } } diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index 00b6718e1..d31704fe0 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.Consumer; +import java.util.function.UnaryOperator; public class ItemBuilder { @@ -38,8 +39,14 @@ public class ItemBuilder { return this; } + @Contract(value = "_ -> this") + public @NotNull ItemBuilder meta(@NotNull UnaryOperator<@NotNull ItemMetaBuilder> itemMetaConsumer) { + itemMetaConsumer.apply(metaBuilder); + return this; + } + @Contract(value = "_, _ -> this") - public > @NotNull ItemBuilder meta(Class metaType, Consumer itemMetaConsumer) { + public > @NotNull ItemBuilder meta(@NotNull Class metaType, @NotNull Consumer<@NotNull T> itemMetaConsumer) { itemMetaConsumer.accept((T) metaBuilder); return this; } diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index aa7176f84..8d74a3642 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -30,6 +30,7 @@ public class ItemMeta implements Cloneable { private final int customModelData; + private final @Nullable NBTCompound originalNbt; private SoftReference cache; protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { @@ -42,6 +43,9 @@ public class ItemMeta implements Cloneable { this.enchantmentMap = Collections.unmodifiableMap(metaBuilder.enchantmentMap); this.attributes = new ArrayList<>(); this.customModelData = 0; + + // Can be null + this.originalNbt = metaBuilder.originalNBT; } @Contract(value = "_, -> new", pure = true) @@ -69,28 +73,38 @@ public class ItemMeta implements Cloneable { } @Contract(pure = true) - public @Nullable List<@NotNull Component> getLore() { + public @NotNull List<@NotNull Component> getLore() { return lore; } - public Map getEnchantmentMap() { + @Contract(pure = true) + public @NotNull Map getEnchantmentMap() { return enchantmentMap; } - public List getAttributes() { + @Contract(pure = true) + public @NotNull List getAttributes() { return attributes; } + @Contract(pure = true) public int getCustomModelData() { return customModelData; } public @NotNull NBTCompound toNBT() { + if (originalNbt != null) { + // Return the nbt this meta has been created with + return originalNbt; + } + var nbt = cache != null ? cache.get() : null; if (nbt == null) { nbt = NBTUtils.metaToNBT(this); - cache = new SoftReference<>(nbt); + this.builder.write(nbt); + this.cache = new SoftReference<>(nbt); } + return nbt; } @@ -108,6 +122,7 @@ public class ItemMeta implements Cloneable { return toNBT().hashCode(); } + @Contract(value = "-> new", pure = true) protected @NotNull ItemMetaBuilder builder() { return builder.clone(); } diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index cb815d18c..0964c52aa 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -1,20 +1,45 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; +import net.minestom.server.item.attribute.ItemAttribute; +import net.minestom.server.utils.NBTUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.*; public abstract class ItemMetaBuilder implements Cloneable { + protected int damage; + protected boolean unbreakable; + protected int hideFlag; protected Component displayName; protected List lore = new ArrayList<>(); protected Map enchantmentMap = new HashMap<>(); + protected List attributes = new ArrayList<>(); + protected int customModelData; + + protected NBTCompound originalNBT; protected ItemMetaBuilder() { } + public @NotNull ItemMetaBuilder damage(int damage) { + this.damage = damage; + return this; + } + + public @NotNull ItemMetaBuilder unbreakable(boolean unbreakable) { + this.unbreakable = unbreakable; + return this; + } + + public @NotNull ItemMetaBuilder hideFlag(int hideFlag) { + this.hideFlag = hideFlag; + return this; + } + public @NotNull ItemMetaBuilder displayName(@Nullable Component displayName) { this.displayName = displayName; return this; @@ -45,10 +70,30 @@ public abstract class ItemMetaBuilder implements Cloneable { return this; } + public @NotNull ItemMetaBuilder attributes(List attributes) { + this.attributes = attributes; + return this; + } + + public @NotNull ItemMetaBuilder customModelData(int customModelData) { + this.customModelData = customModelData; + return this; + } + public abstract @NotNull ItemMeta build(); + public abstract void read(@NotNull NBTCompound nbtCompound); + + public abstract void write(@NotNull NBTCompound nbtCompound); + protected abstract void deepClone(@NotNull ItemMetaBuilder metaBuilder); + public static @NotNull ItemMetaBuilder fromNBT(@NotNull ItemMetaBuilder metaBuilder, @NotNull NBTCompound nbtCompound) { + NBTUtils.loadDataIntoMeta(metaBuilder, nbtCompound); + metaBuilder.originalNBT = nbtCompound; + return metaBuilder; + } + @Override protected ItemMetaBuilder clone() { try { diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index a0124c31d..d8ecf9954 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -81,6 +81,11 @@ public class ItemStack { return builder().meta(metaType, metaConsumer).build(); } + @Contract(value = "_ -> new", pure = true) + public @NotNull ItemStack withMeta(@NotNull UnaryOperator<@NotNull ItemMetaBuilder> metaOperator) { + return builder().meta(metaOperator).build(); + } + @Contract(pure = true) public @Nullable Component getDisplayName() { return meta.getDisplayName(); diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/meta/CompassMeta.java index 4651f79d5..b68233a34 100644 --- a/src/main/java/net/minestom/server/item/meta/CompassMeta.java +++ b/src/main/java/net/minestom/server/item/meta/CompassMeta.java @@ -7,6 +7,7 @@ import net.minestom.server.item.ItemMetaBuilder; import net.minestom.server.utils.Position; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.List; import java.util.Map; @@ -101,6 +102,40 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider items, @NotNull Inventory destination) { destination.clear(); for (NBTCompound tag : items) { - Material item = Registries.getMaterial(tag.getString("id")); - if (item == Material.AIR) { - item = Material.STONE; + Material material = Registries.getMaterial(tag.getString("id")); + if (material == Material.AIR) { + material = Material.STONE; } - ItemStack stack = ItemStack.of(item, tag.getByte("Count")); + byte count = tag.getByte("Count"); + NBTCompound nbtCompound = null; if (tag.containsKey("tag")) { - loadDataIntoItem(stack, tag.getCompound("tag")); + nbtCompound = tag.getCompound("tag"); } - destination.setItemStack(tag.getByte("Slot"), stack); + ItemStack itemStack = loadItem(material, count, nbtCompound); + destination.setItemStack(tag.getByte("Slot"), itemStack); } } @@ -124,32 +128,44 @@ public final class NBTUtils { final Material material = Material.fromId((short) id); final byte count = reader.readByte(); - ItemStack item = ItemStack.of(material, count); + NBTCompound nbtCompound = null; try { final NBT itemNBT = reader.readTag(); if (itemNBT instanceof NBTCompound) { // can also be a TAG_End if no data - NBTCompound nbt = (NBTCompound) itemNBT; - loadDataIntoItem(item, nbt); + nbtCompound = (NBTCompound) itemNBT; } } catch (IOException | NBTException e) { MinecraftServer.getExceptionManager().handleException(e); } - return item; + return loadItem(material, count, nbtCompound); + } + + public static @NotNull ItemStack loadItem(@NotNull Material material, int count, NBTCompound nbtCompound) { + return ItemStack.builder(material) + .amount(count) + .meta(metaBuilder -> { + if (nbtCompound != null) { + return ItemMetaBuilder.fromNBT(metaBuilder, nbtCompound); + } else { + return metaBuilder; + } + }) + .build(); } @SuppressWarnings("ConstantConditions") - public static void loadDataIntoItem(@NotNull ItemStack item, @NotNull NBTCompound nbt) { - /*if (nbt.containsKey("Damage")) item.setDamage(nbt.getInt("Damage")); - if (nbt.containsKey("Unbreakable")) item.setUnbreakable(nbt.getAsByte("Unbreakable") == 1); - if (nbt.containsKey("HideFlags")) item.setHideFlag(nbt.getInt("HideFlags")); + public static void loadDataIntoMeta(@NotNull ItemMetaBuilder metaBuilder, @NotNull NBTCompound nbt) { + if (nbt.containsKey("Damage")) metaBuilder.damage(nbt.getInt("Damage")); + if (nbt.containsKey("Unbreakable")) metaBuilder.unbreakable(nbt.getAsByte("Unbreakable") == 1); + if (nbt.containsKey("HideFlags")) metaBuilder.hideFlag(nbt.getInt("HideFlags")); if (nbt.containsKey("display")) { final NBTCompound display = nbt.getCompound("display"); if (display.containsKey("Name")) { final String rawName = display.getString("Name"); final Component displayName = GsonComponentSerializer.gson().deserialize(rawName); - item.setDisplayName(displayName); + metaBuilder.displayName(displayName); } if (display.containsKey("Lore")) { NBTList loreList = display.getList("Lore"); @@ -157,19 +173,20 @@ public final class NBTUtils { for (NBTString s : loreList) { lore.add(GsonComponentSerializer.gson().deserialize(s.getValue())); } - item.setLore(lore); + metaBuilder.lore(lore); } } // Enchantments if (nbt.containsKey("Enchantments")) { - loadEnchantments(nbt.getList("Enchantments"), item::setEnchantment); + loadEnchantments(nbt.getList("Enchantments"), metaBuilder::enchantment); } // Attributes if (nbt.containsKey("AttributeModifiers")) { - NBTList attributes = nbt.getList("AttributeModifiers"); - for (NBTCompound attributeNBT : attributes) { + List attributes = new ArrayList<>(); + NBTList nbtAttributes = nbt.getList("AttributeModifiers"); + for (NBTCompound attributeNBT : nbtAttributes) { final UUID uuid; { final int[] uuidArray = attributeNBT.getIntArray("UUID"); @@ -203,44 +220,37 @@ public final class NBTUtils { // Add attribute final ItemAttribute itemAttribute = new ItemAttribute(uuid, name, attribute, attributeOperation, value, attributeSlot); - item.addAttribute(itemAttribute); - } - } - - // Hide flags - { - if (nbt.containsKey("HideFlags")) { - item.setHideFlag(nbt.getInt("HideFlags")); + attributes.add(itemAttribute); } + metaBuilder.attributes(attributes); } // Custom model data { if (nbt.containsKey("CustomModelData")) { - item.setCustomModelData(nbt.getInt("CustomModelData")); + metaBuilder.customModelData(nbt.getInt("CustomModelData")); } } - // Meta specific field - final ItemMeta itemMeta = item.getItemMeta(); - if (itemMeta != null) { - itemMeta.read(nbt); - } + // Meta specific fields + metaBuilder.read(nbt); // Ownership { - if (nbt.containsKey(ItemStack.OWNERSHIP_DATA_KEY)) { + // FIXME: custom data + /*if (nbt.containsKey(ItemStack.OWNERSHIP_DATA_KEY)) { final String identifierString = nbt.getString(ItemStack.OWNERSHIP_DATA_KEY); final UUID identifier = UUID.fromString(identifierString); final Data data = ItemStack.DATA_OWNERSHIP.getOwnObject(identifier); if (data != null) { item.setData(data); } - } + }*/ } //CanPlaceOn - { + // FIXME: PlaceOn/CanDestroy + /*{ if (nbt.containsKey("CanPlaceOn")) { NBTList canPlaceOn = nbt.getList("CanPlaceOn"); canPlaceOn.forEach(x -> item.getCanPlaceOn().add(x.getValue())); @@ -268,7 +278,7 @@ public final class NBTUtils { } } - public static void writeItemStack(BinaryWriter packet, @NotNull ItemStack itemStack) { + public static void writeItemStack(@NotNull BinaryWriter packet, @NotNull ItemStack itemStack) { if (itemStack.isAir()) { packet.writeBoolean(false); } else { From 4a075da3e01ce5a9c731494512cdb83c91548655 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 22:40:24 +0200 Subject: [PATCH 19/77] Ensure that the meta is new when instantiating from NBT --- .../net/minestom/server/item/ItemBuilder.java | 2 +- .../minestom/server/item/ItemMetaBuilder.java | 17 ++++++++++------- .../minestom/server/item/meta/CompassMeta.java | 6 ++++++ .../net/minestom/server/utils/NBTUtils.java | 2 +- src/test/java/demo/PlayerInit.java | 6 +++--- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemBuilder.java index d31704fe0..506107fdd 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemBuilder.java @@ -41,7 +41,7 @@ public class ItemBuilder { @Contract(value = "_ -> this") public @NotNull ItemBuilder meta(@NotNull UnaryOperator<@NotNull ItemMetaBuilder> itemMetaConsumer) { - itemMetaConsumer.apply(metaBuilder); + this.metaBuilder = itemMetaConsumer.apply(metaBuilder); return this; } diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 0964c52aa..844e59c7f 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -3,11 +3,13 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.utils.NBTUtils; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.*; +import java.util.function.Supplier; public abstract class ItemMetaBuilder implements Cloneable { @@ -22,9 +24,6 @@ public abstract class ItemMetaBuilder implements Cloneable { protected NBTCompound originalNBT; - protected ItemMetaBuilder() { - } - public @NotNull ItemMetaBuilder damage(int damage) { this.damage = damage; return this; @@ -88,10 +87,14 @@ public abstract class ItemMetaBuilder implements Cloneable { protected abstract void deepClone(@NotNull ItemMetaBuilder metaBuilder); - public static @NotNull ItemMetaBuilder fromNBT(@NotNull ItemMetaBuilder metaBuilder, @NotNull NBTCompound nbtCompound) { - NBTUtils.loadDataIntoMeta(metaBuilder, nbtCompound); - metaBuilder.originalNBT = nbtCompound; - return metaBuilder; + protected abstract @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier(); + + @Contract(value = "_, _ -> new", pure = true) + public static @NotNull ItemMetaBuilder fromNBT(@NotNull ItemMetaBuilder src, @NotNull NBTCompound nbtCompound) { + ItemMetaBuilder dest = src.getSupplier().get(); + NBTUtils.loadDataIntoMeta(dest, nbtCompound); + dest.originalNBT = nbtCompound; + return dest; } @Override diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/meta/CompassMeta.java index b68233a34..fa7fcdc87 100644 --- a/src/main/java/net/minestom/server/item/meta/CompassMeta.java +++ b/src/main/java/net/minestom/server/item/meta/CompassMeta.java @@ -11,6 +11,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.List; import java.util.Map; +import java.util.function.Supplier; public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider { @@ -143,5 +144,10 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider getSupplier() { + return Builder::new; + } } } diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java index 48e865020..ac86eab65 100644 --- a/src/main/java/net/minestom/server/utils/NBTUtils.java +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -142,7 +142,7 @@ public final class NBTUtils { return loadItem(material, count, nbtCompound); } - public static @NotNull ItemStack loadItem(@NotNull Material material, int count, NBTCompound nbtCompound) { + public static @NotNull ItemStack loadItem(@NotNull Material material, int count, @Nullable NBTCompound nbtCompound) { return ItemStack.builder(material) .amount(count) .meta(metaBuilder -> { diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index a4f9d6ac8..f4ebbf4ce 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -222,19 +222,19 @@ public class PlayerInit { globalEventHandler.addEventCallback(PlayerSpawnEvent.class, event -> { final Player player = event.getPlayer(); - player.setGameMode(GameMode.SURVIVAL); + player.setGameMode(GameMode.CREATIVE); player.setPermissionLevel(4); PlayerInventory inventory = player.getInventory(); ItemStack itemStack = ItemStack.of(Material.STONE, 64); - inventory.addItemStack(itemStack); + //inventory.addItemStack(itemStack); { ItemStack item = ItemStack.builder(Material.DIAMOND_CHESTPLATE) .displayName(Component.text("test")) .build(); - inventory.setChestplate(item); + //inventory.setChestplate(item); } //player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 32)); From 56bba41f68f4ccc11ad8aac6fb12e39e19ca0364 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 22:50:20 +0200 Subject: [PATCH 20/77] Cleanup --- .../server/inventory/EquipmentHandler.java | 27 +++++++------------ .../minestom/server/inventory/Inventory.java | 9 ------- .../server/inventory/InventoryModifier.java | 9 +++---- .../server/inventory/PlayerInventory.java | 23 ++++------------ 4 files changed, 17 insertions(+), 51 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/EquipmentHandler.java b/src/main/java/net/minestom/server/inventory/EquipmentHandler.java index 9c01d75eb..31235ffd4 100644 --- a/src/main/java/net/minestom/server/inventory/EquipmentHandler.java +++ b/src/main/java/net/minestom/server/inventory/EquipmentHandler.java @@ -20,8 +20,7 @@ public interface EquipmentHandler { * * @return the {@link ItemStack} in main hand */ - @NotNull - ItemStack getItemInMainHand(); + @NotNull ItemStack getItemInMainHand(); /** * Changes the main hand {@link ItemStack}. @@ -35,8 +34,7 @@ public interface EquipmentHandler { * * @return the item in off hand */ - @NotNull - ItemStack getItemInOffHand(); + @NotNull ItemStack getItemInOffHand(); /** * Changes the off hand {@link ItemStack}. @@ -51,8 +49,7 @@ public interface EquipmentHandler { * @param hand the Hand to get the {@link ItemStack} from * @return the {@link ItemStack} in {@code hand} */ - @NotNull - default ItemStack getItemInHand(@NotNull Player.Hand hand) { + default @NotNull ItemStack getItemInHand(@NotNull Player.Hand hand) { switch (hand) { case MAIN: return getItemInMainHand(); @@ -85,8 +82,7 @@ public interface EquipmentHandler { * * @return the helmet */ - @NotNull - ItemStack getHelmet(); + @NotNull ItemStack getHelmet(); /** * Changes the helmet. @@ -100,8 +96,7 @@ public interface EquipmentHandler { * * @return the chestplate */ - @NotNull - ItemStack getChestplate(); + @NotNull ItemStack getChestplate(); /** * Changes the chestplate. @@ -115,8 +110,7 @@ public interface EquipmentHandler { * * @return the leggings */ - @NotNull - ItemStack getLeggings(); + @NotNull ItemStack getLeggings(); /** * Changes the leggings. @@ -130,8 +124,7 @@ public interface EquipmentHandler { * * @return the boots */ - @NotNull - ItemStack getBoots(); + @NotNull ItemStack getBoots(); /** * Changes the boots. @@ -146,8 +139,7 @@ public interface EquipmentHandler { * @param slot the equipment to get the item from * @return the equipment {@link ItemStack} */ - @NotNull - default ItemStack getEquipment(@NotNull EntityEquipmentPacket.Slot slot) { + default @NotNull ItemStack getEquipment(@NotNull EntityEquipmentPacket.Slot slot) { switch (slot) { case MAIN_HAND: return getItemInMainHand(); @@ -191,8 +183,7 @@ public interface EquipmentHandler { * @return the packet with the equipments * @throws IllegalStateException if 'this' is not an {@link Entity} */ - @NotNull - default EntityEquipmentPacket getEquipmentsPacket() { + default @NotNull EntityEquipmentPacket getEquipmentsPacket() { Check.stateCondition(!(this instanceof Entity), "Only accessible for Entity"); final Entity entity = (Entity) this; diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index ec04cf8cb..01286835c 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -236,15 +236,6 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View playerConnection.sendPacket(createNewWindowItemsPacket()); } - /** - * Refreshes only a specific slot with the updated item stack data. - * - * @param slot the slot to refresh - */ - public void refreshSlot(short slot) { - sendSlotRefresh(slot, getItemStack(slot)); - } - @NotNull @Override public Set getViewers() { diff --git a/src/main/java/net/minestom/server/inventory/InventoryModifier.java b/src/main/java/net/minestom/server/inventory/InventoryModifier.java index f2d9035b9..aec831624 100644 --- a/src/main/java/net/minestom/server/inventory/InventoryModifier.java +++ b/src/main/java/net/minestom/server/inventory/InventoryModifier.java @@ -41,8 +41,7 @@ public interface InventoryModifier { * @param slot the slot to check * @return the item in the slot {@code slot} */ - @NotNull - ItemStack getItemStack(int slot); + @NotNull ItemStack getItemStack(int slot); /** * Gets all the {@link ItemStack} in the inventory. @@ -52,8 +51,7 @@ public interface InventoryModifier { * * @return an array containing all the inventory's items */ - @NotNull - ItemStack[] getItemStacks(); + @NotNull ItemStack[] getItemStacks(); /** * Gets the size of the inventory. @@ -67,8 +65,7 @@ public interface InventoryModifier { * * @return a modifiable {@link List} containing all the inventory conditions */ - @NotNull - List getInventoryConditions(); + @NotNull List getInventoryConditions(); /** * Adds a new {@link InventoryCondition} to this inventory. diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 92e843bdc..4204ff9fc 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -48,21 +48,18 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler Arrays.fill(items, ItemStack.AIR); } - @NotNull @Override - public ItemStack getItemStack(int slot) { + public @NotNull ItemStack getItemStack(int slot) { return this.items[slot]; } - @NotNull @Override - public ItemStack[] getItemStacks() { + public @NotNull ItemStack[] getItemStacks() { return items.clone(); } - @NotNull @Override - public List getInventoryConditions() { + public @NotNull List getInventoryConditions() { return inventoryConditions; } @@ -215,16 +212,6 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler player.getPlayerConnection().sendPacket(createWindowItemsPacket()); } - /** - * Refreshes only a specific slot with the updated item stack data. - * - * @param slot the slot to refresh - */ - public void refreshSlot(short slot) { - final int packetSlot = convertToPacketSlot(slot); - sendSlotRefresh((short) packetSlot, getItemStack(slot)); - } - /** * Gets the item in player cursor. * @@ -305,7 +292,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler //refreshSlot((short) slot); } - protected void setItemStackInternal(int slot, ItemStack itemStack) { + protected void setItemStackInternal(int slot, @NotNull ItemStack itemStack) { items[slot] = itemStack; } @@ -316,7 +303,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler * @param offset offset (generally 9 to ignore armor and craft slots) * @param itemStack the item stack to set */ - protected void setItemStack(int slot, int offset, ItemStack itemStack) { + protected void setItemStack(int slot, int offset, @NotNull ItemStack itemStack) { final int convertedSlot = convertPlayerInventorySlot(slot, offset); setItemStack(convertedSlot, itemStack); } From 255ccf8ad58af7d1146ddbd1f01bec30a50799a5 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 23:34:40 +0200 Subject: [PATCH 21/77] Remove unused class --- .../net/minestom/server/item/ItemDisplay.java | 76 ------------------- .../listener/BlockPlacementListener.java | 2 - 2 files changed, 78 deletions(-) delete mode 100644 src/main/java/net/minestom/server/item/ItemDisplay.java diff --git a/src/main/java/net/minestom/server/item/ItemDisplay.java b/src/main/java/net/minestom/server/item/ItemDisplay.java deleted file mode 100644 index b88013b33..000000000 --- a/src/main/java/net/minestom/server/item/ItemDisplay.java +++ /dev/null @@ -1,76 +0,0 @@ -package net.minestom.server.item; - -import com.google.gson.JsonNull; -import com.google.gson.stream.JsonReader; -import net.kyori.adventure.text.Component; -import net.minestom.server.chat.JsonMessage; - -import java.util.stream.Stream; - -public class ItemDisplay { - - private Component displayName; - private Component[] lore; - - /** - * @deprecated Use {@link #ItemDisplay(Component, Component[])} - */ - @Deprecated - public ItemDisplay(JsonMessage displayName, JsonMessage[] lore) { - this.displayName = displayName.asComponent(); - this.lore = new Component[lore.length]; - - for (int i = 0; i < lore.length; i++) { - this.lore[i] = lore[i].asComponent(); - } - } - - public ItemDisplay(Component displayName, Component[] lore) { - this.displayName = displayName; - this.lore = lore; - } - - /** - * Gets the item display name. - * - * @return the item display name - * @deprecated Use {@link #getDisplayName()} - */ - @Deprecated - public JsonMessage getDisplayNameJson() { - return JsonMessage.fromComponent(displayName); - } - - /** - * Gets the item lore. - * - * @return the item lore - * @deprecated Use {@link #getLore()} - */ - @Deprecated - public JsonMessage[] getLoreJson() { - JsonMessage[] loreOld = new JsonMessage[lore.length]; - for (int i = 0; i < lore.length; i++) { - loreOld[i] = JsonMessage.fromComponent(lore[i]); - } - return loreOld; - } - - /** - * Gets the item display name. - * - * @return the item display name - */ - public Component getDisplayName() { - return displayName; - } - - /** - * Gets the item lore. - * - * @return the item lore - */ - public Component[] getLore() { - return lore; - } -} diff --git a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java index 1a7a6bb13..f6eb3bfc3 100644 --- a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java +++ b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java @@ -195,8 +195,6 @@ public class BlockPlacementListener { if (refreshChunk) { chunk.sendChunkSectionUpdate(ChunkUtils.getSectionAt(blockPosition.getY()), player); } - - player.getInventory().refreshSlot(player.getHeldSlot()); } } From d3fb364a7afd2914ea71406198fb57caef7fa5b2 Mon Sep 17 00:00:00 2001 From: themode Date: Fri, 2 Apr 2021 23:41:06 +0200 Subject: [PATCH 22/77] Better use of ItemStack#of --- .../java/net/minestom/server/advancements/Advancement.java | 4 ++-- .../server/entity/metadata/item/ItemContainingMeta.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minestom/server/advancements/Advancement.java b/src/main/java/net/minestom/server/advancements/Advancement.java index 2610d0876..6b9310e70 100644 --- a/src/main/java/net/minestom/server/advancements/Advancement.java +++ b/src/main/java/net/minestom/server/advancements/Advancement.java @@ -60,7 +60,7 @@ public class Advancement { public Advancement(@NotNull JsonMessage title, @NotNull JsonMessage description, @NotNull Material icon, @NotNull FrameType frameType, float x, float y) { - this(title, description, ItemStack.of(icon, 1), frameType, x, y); + this(title, description, ItemStack.of(icon), frameType, x, y); } public Advancement(@NotNull Component title, Component description, @@ -77,7 +77,7 @@ public class Advancement { public Advancement(@NotNull Component title, @NotNull Component description, @NotNull Material icon, @NotNull FrameType frameType, float x, float y) { - this(title, description, ItemStack.of(icon, 1), frameType, x, y); + this(title, description, ItemStack.of(icon), frameType, x, y); } /** diff --git a/src/main/java/net/minestom/server/entity/metadata/item/ItemContainingMeta.java b/src/main/java/net/minestom/server/entity/metadata/item/ItemContainingMeta.java index ac3066584..9fbb9c0a7 100644 --- a/src/main/java/net/minestom/server/entity/metadata/item/ItemContainingMeta.java +++ b/src/main/java/net/minestom/server/entity/metadata/item/ItemContainingMeta.java @@ -13,7 +13,7 @@ class ItemContainingMeta extends EntityMeta { protected ItemContainingMeta(@NotNull Entity entity, @NotNull Metadata metadata, @NotNull Material defaultItemMaterial) { super(entity, metadata); - this.defaultItem = ItemStack.of(defaultItemMaterial, 1); + this.defaultItem = ItemStack.of(defaultItemMaterial); } @NotNull From 9abbef35ae6582c7c3dbfd60ea0881ec83d4cadb Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 00:03:36 +0200 Subject: [PATCH 23/77] Reduce code duplication --- .../minestom/server/inventory/Inventory.java | 33 ++++--------- .../server/inventory/InventoryModifier.java | 47 ++++++++++++++++++- .../server/inventory/PlayerInventory.java | 36 +++++--------- .../net/minestom/server/item/ItemStack.java | 2 +- 4 files changed, 66 insertions(+), 52 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index 01286835c..3d7dce6cd 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -10,7 +10,6 @@ import net.minestom.server.inventory.click.InventoryClickProcessor; import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; -import net.minestom.server.item.StackingRule; import net.minestom.server.network.packet.server.play.OpenWindowPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.WindowItemsPacket; @@ -149,30 +148,14 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View @Override public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { - final StackingRule stackingRule = itemStack.getStackingRule(); - for (int i = 0; i < getSize(); i++) { - ItemStack item = getItemStack(i); - final StackingRule itemStackingRule = item.getStackingRule(); - if (itemStackingRule.canBeStacked(itemStack, item)) { - final int itemAmount = itemStackingRule.getAmount(item); - if (itemAmount == stackingRule.getMaxSize()) - continue; - final int itemStackAmount = itemStackingRule.getAmount(itemStack); - final int totalAmount = itemStackAmount + itemAmount; - if (!stackingRule.canApply(itemStack, totalAmount)) { - item = itemStackingRule.apply(item, itemStackingRule.getMaxSize()); - setItemStack(i, item); - itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); - } else { - setItemStack(i, item.withAmount(totalAmount)); - return true; - } - } else if (item.isAir()) { - setItemStack(i, itemStack); - return true; - } - } - return false; + // Make the method synchronized + return InventoryModifier.super.addItemStack(itemStack); + } + + @Override + public synchronized boolean addItemStack(@NotNull ItemStack itemStack, int startSlot, int endSlot) { + // Make the method synchronized + return InventoryModifier.super.addItemStack(itemStack, startSlot, endSlot); } @Override diff --git a/src/main/java/net/minestom/server/inventory/InventoryModifier.java b/src/main/java/net/minestom/server/inventory/InventoryModifier.java index aec831624..7b90a63e5 100644 --- a/src/main/java/net/minestom/server/inventory/InventoryModifier.java +++ b/src/main/java/net/minestom/server/inventory/InventoryModifier.java @@ -1,7 +1,10 @@ package net.minestom.server.inventory; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; +import net.minestom.server.item.StackingRule; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; @@ -28,7 +31,49 @@ public interface InventoryModifier { * @param itemStack the item to add * @return true if the item has been successfully fully added, false otherwise */ - boolean addItemStack(@NotNull ItemStack itemStack); + default boolean addItemStack(@NotNull ItemStack itemStack) { + return addItemStack(itemStack, 0, getSize()); + } + + default boolean addItemStack(@NotNull ItemStack itemStack, int startSlot, int endSlot) { + Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); + + final StackingRule stackingRule = itemStack.getStackingRule(); + for (int i = startSlot; i < endSlot; i++) { + ItemStack inventoryItem = getItemStack(i); + if (stackingRule.canBeStacked(itemStack, inventoryItem)) { + final int itemAmount = stackingRule.getAmount(inventoryItem); + if (itemAmount == stackingRule.getMaxSize()) + continue; + final int itemStackAmount = stackingRule.getAmount(itemStack); + final int totalAmount = itemStackAmount + itemAmount; + if (!stackingRule.canApply(itemStack, totalAmount)) { + // Slot cannot accept the whole item, reduce amount to 'itemStack' + itemChangesMap.put(i, stackingRule.apply(inventoryItem, stackingRule.getMaxSize())); + itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); + } else { + // Slot can accept the whole item + itemChangesMap.put(i, inventoryItem.withAmount(totalAmount)); + itemStack = ItemStack.AIR; + break; + } + } else if (inventoryItem.isAir()) { + // Fill the slot + itemChangesMap.put(i, itemStack); + itemStack = ItemStack.AIR; + break; + } + } + + if (itemStack.isAir()) { + // Item can be fully placed inside the inventory, do so + itemChangesMap.forEach(this::setItemStack); + return true; + } else { + // Inventory cannot accept the item fully + return false; + } + } /** * Clears the inventory and send relevant update to the viewer(s). diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 4204ff9fc..75bbcdbd6 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -12,7 +12,6 @@ import net.minestom.server.inventory.click.InventoryClickProcessor; import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; -import net.minestom.server.item.StackingRule; import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.WindowItemsPacket; @@ -93,31 +92,18 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler return false; itemStack = addItemStackEvent.getItemStack(); + return InventoryModifier.super.addItemStack(itemStack, 0, getSize() - 10); + } - final StackingRule stackingRule = itemStack.getStackingRule(); - for (int i = 0; i < items.length - 10; i++) { - ItemStack item = items[i]; - final StackingRule itemStackingRule = item.getStackingRule(); - if (itemStackingRule.canBeStacked(itemStack, item)) { - final int itemAmount = itemStackingRule.getAmount(item); - if (itemAmount == stackingRule.getMaxSize()) - continue; - final int itemStackAmount = itemStackingRule.getAmount(itemStack); - final int totalAmount = itemStackAmount + itemAmount; - if (!stackingRule.canApply(itemStack, totalAmount)) { - item = itemStackingRule.apply(item, itemStackingRule.getMaxSize()); - setItemStack(i, item); - itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); - } else { - setItemStack(i, item.withAmount(totalAmount)); - return true; - } - } else if (item.isAir()) { - safeItemInsert(i, itemStack); - return true; - } - } - return false; + @Override + public synchronized boolean addItemStack(@NotNull ItemStack itemStack, int startSlot, int endSlot) { + PlayerAddItemStackEvent addItemStackEvent = new PlayerAddItemStackEvent(player, itemStack); + player.callEvent(PlayerAddItemStackEvent.class, addItemStackEvent); + if (addItemStackEvent.isCancelled()) + return false; + + itemStack = addItemStackEvent.getItemStack(); + return InventoryModifier.super.addItemStack(itemStack, startSlot, endSlot); } @Override diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index d8ecf9954..a8a2dd7fe 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -128,7 +128,7 @@ public class ItemStack { @Contract(pure = true) public boolean isAir() { - return equals(AIR); + return material.equals(Material.AIR); } @Contract(pure = true) From 0382b1adfe53570acff35c4017fd9c55deabd93f Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 00:09:13 +0200 Subject: [PATCH 24/77] ItemMetaBuilder annotations --- .../minestom/server/item/ItemMetaBuilder.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 844e59c7f..3cca989cb 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -24,61 +24,73 @@ public abstract class ItemMetaBuilder implements Cloneable { protected NBTCompound originalNBT; + @Contract("_ -> this") public @NotNull ItemMetaBuilder damage(int damage) { this.damage = damage; return this; } + @Contract("_ -> this") public @NotNull ItemMetaBuilder unbreakable(boolean unbreakable) { this.unbreakable = unbreakable; return this; } + @Contract("_ -> this") public @NotNull ItemMetaBuilder hideFlag(int hideFlag) { this.hideFlag = hideFlag; return this; } + @Contract("_ -> this") public @NotNull ItemMetaBuilder displayName(@Nullable Component displayName) { this.displayName = displayName; return this; } - public @NotNull ItemMetaBuilder lore(List<@NotNull Component> lore) { + @Contract("_ -> this") + public @NotNull ItemMetaBuilder lore(@NotNull List<@NotNull Component> lore) { this.lore = lore; return this; } + @Contract("_ -> this") public @NotNull ItemMetaBuilder lore(Component... lore) { lore(Arrays.asList(lore)); return this; } + @Contract("_ -> this") public @NotNull ItemMetaBuilder enchantments(@NotNull Map enchantments) { this.enchantmentMap.putAll(enchantments); return this; } + @Contract("_, _ -> this") public @NotNull ItemMetaBuilder enchantment(@NotNull Enchantment enchantment, short level) { this.enchantmentMap.put(enchantment, level); return this; } + @Contract("-> this") public @NotNull ItemMetaBuilder clearEnchantment() { this.enchantmentMap.clear(); return this; } - public @NotNull ItemMetaBuilder attributes(List attributes) { + @Contract("_ -> this") + public @NotNull ItemMetaBuilder attributes(@NotNull List<@NotNull ItemAttribute> attributes) { this.attributes = attributes; return this; } + @Contract("_ -> this") public @NotNull ItemMetaBuilder customModelData(int customModelData) { this.customModelData = customModelData; return this; } + @Contract("-> new") public abstract @NotNull ItemMeta build(); public abstract void read(@NotNull NBTCompound nbtCompound); From 785e002a501fd22877eea1ec42c4e903c274649d Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 00:21:23 +0200 Subject: [PATCH 25/77] Improve documentation --- .../net/minestom/server/item/ItemMeta.java | 3 ++ .../net/minestom/server/item/ItemStack.java | 15 ++++-- .../minestom/server/item/StackingRule.java | 7 +-- .../server/item/meta/CompassMeta.java | 54 +++---------------- src/test/java/demo/PlayerInit.java | 3 -- 5 files changed, 26 insertions(+), 56 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 8d74a3642..d26eefd92 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -55,14 +55,17 @@ public class ItemMeta implements Cloneable { return builder.build(); } + @Contract(pure = true) public int getDamage() { return damage; } + @Contract(pure = true) public boolean isUnbreakable() { return unbreakable; } + @Contract(pure = true) public int getHideFlag() { return hideFlag; } diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index a8a2dd7fe..844b4bd7a 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -12,9 +12,18 @@ import java.util.function.Consumer; import java.util.function.IntUnaryOperator; import java.util.function.UnaryOperator; +/** + * Represents an immutable item to be placed inside {@link net.minestom.server.inventory.PlayerInventory}, + * {@link net.minestom.server.inventory.Inventory} or even on the ground {@link net.minestom.server.entity.ItemEntity}. + *

+ * An item stack cannot be null, {@link ItemStack#AIR} should be used instead. + */ public class ItemStack { - public static final ItemStack AIR = ItemStack.of(Material.AIR); + /** + * Constant AIR item. Should be used instead of 'null'. + */ + public static final @NotNull ItemStack AIR = ItemStack.of(Material.AIR); private final UUID uuid = UUID.randomUUID(); private final StackingRule stackingRule = new VanillaStackingRule(64); @@ -23,7 +32,7 @@ public class ItemStack { private final int amount; private final ItemMeta meta; - protected ItemStack(@NotNull Material material, int amount, ItemMeta meta) { + protected ItemStack(@NotNull Material material, int amount, @NotNull ItemMeta meta) { this.material = material; this.amount = amount; this.meta = meta; @@ -102,7 +111,7 @@ public class ItemStack { } @Contract(pure = true) - public @Nullable List<@NotNull Component> getLore() { + public @NotNull List<@NotNull Component> getLore() { return meta.getLore(); } diff --git a/src/main/java/net/minestom/server/item/StackingRule.java b/src/main/java/net/minestom/server/item/StackingRule.java index 707a79016..cf6bcbbab 100644 --- a/src/main/java/net/minestom/server/item/StackingRule.java +++ b/src/main/java/net/minestom/server/item/StackingRule.java @@ -1,5 +1,6 @@ package net.minestom.server.item; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; /** @@ -40,10 +41,10 @@ public abstract class StackingRule { * * @param item the {@link ItemStack} to applies the size to * @param newAmount the new item size - * @return the new {@link ItemStack} with the new amount + * @return a new {@link ItemStack item} with the specified amount */ - @NotNull - public abstract ItemStack apply(@NotNull ItemStack item, int newAmount); + @Contract("_, _ -> new") + public abstract @NotNull ItemStack apply(@NotNull ItemStack item, int newAmount); /** * Used to determine the current stack size of an {@link ItemStack}. diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/meta/CompassMeta.java index fa7fcdc87..0007e2475 100644 --- a/src/main/java/net/minestom/server/item/meta/CompassMeta.java +++ b/src/main/java/net/minestom/server/item/meta/CompassMeta.java @@ -1,7 +1,5 @@ package net.minestom.server.item.meta; -import net.kyori.adventure.text.Component; -import net.minestom.server.item.Enchantment; import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemMetaBuilder; import net.minestom.server.utils.Position; @@ -9,8 +7,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import java.util.List; -import java.util.Map; import java.util.function.Supplier; public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider { @@ -20,7 +16,9 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider lore) { - super.lore(lore); - return this; - - } - - @Override - public @NotNull Builder lore(Component... lore) { - super.lore(lore); - return this; - } - - @Override - public @NotNull Builder enchantments(@NotNull Map enchantments) { - super.enchantments(enchantments); - return this; - - } - - @Override - public @NotNull Builder enchantment(@NotNull Enchantment enchantment, short level) { - super.enchantment(enchantment, level); - return this; - } - - @Override - public @NotNull Builder clearEnchantment() { - super.clearEnchantment(); - return this; - } - @Override public @NotNull CompassMeta build() { return new CompassMeta(this, lodestoneTracked, lodestoneDimension, lodestonePosition); diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index f4ebbf4ce..9e11a83a5 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -26,7 +26,6 @@ import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.PlayerInventory; -import net.minestom.server.item.Enchantment; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.meta.CompassMeta; @@ -38,7 +37,6 @@ import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.world.DimensionType; import java.util.Collection; -import java.util.Map; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -68,7 +66,6 @@ public class PlayerInit { { CompassMeta compassMeta = new CompassMeta.Builder() .lodestonePosition(new Position(0, 0, 0)) - .enchantments(Map.of(Enchantment.KNOCKBACK, (short) 5, Enchantment.EFFICIENCY, (short) 10)) .build(); ItemStack itemStack = ItemStack.builder(Material.COMPASS) From 0478b696f4fc7ac4dab6de16ac37e220a0deeb61 Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 03:43:13 +0200 Subject: [PATCH 26/77] Inventory code cleanup --- .../minestom/server/inventory/Inventory.java | 35 ++----------------- .../server/inventory/PlayerInventory.java | 31 +++++++--------- 2 files changed, 15 insertions(+), 51 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index 3d7dce6cd..794db85d6 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -161,9 +161,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View @Override public void clear() { // Clear the item array - for (int i = 0; i < getSize(); i++) { - setItemStackInternal(i, ItemStack.AIR); - } + Arrays.fill(itemStacks, ItemStack.AIR); // Send the cleared inventory to viewers update(); } @@ -295,7 +293,7 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View * @param itemStack the item to insert */ private synchronized void safeItemInsert(int slot, @NotNull ItemStack itemStack) { - setItemStackInternal(slot, itemStack); + this.itemStacks[slot] = itemStack; SetSlotPacket setSlotPacket = new SetSlotPacket(); setSlotPacket.windowId = getWindowId(); setSlotPacket.slot = (short) slot; @@ -303,19 +301,6 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View sendPacketToViewers(setSlotPacket); } - /** - * Inserts an item into the inventory without notifying viewers. - *

- * This will also warn the inventory that the cached window items packet is - * not up-to-date. - * - * @param slot the internal slot - * @param itemStack the item to insert - */ - protected void setItemStackInternal(int slot, @NotNull ItemStack itemStack) { - itemStacks[slot] = itemStack; - } - /** * Creates a complete new {@link WindowItemsPacket}. * @@ -604,22 +589,6 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View return !clickResult.isCancel(); } - /** - * Refresh a slot for all viewers - *

- * WARNING: this does not update the items in the inventory, this is only visual - * - * @param slot the packet slot - * @param itemStack the item stack to set at the slot - */ - private void sendSlotRefresh(short slot, ItemStack itemStack) { - SetSlotPacket setSlotPacket = new SetSlotPacket(); - setSlotPacket.windowId = getWindowId(); - setSlotPacket.slot = slot; - setSlotPacket.itemStack = itemStack; - sendPacketToViewers(setSlotPacket); - } - /** * Used to update the inventory for a specific player in order to fix his cancelled actions * diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 75bbcdbd6..714fa3ea6 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -34,7 +34,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler public static final int INVENTORY_SIZE = 46; protected final Player player; - protected final ItemStack[] items = new ItemStack[INVENTORY_SIZE]; + protected final ItemStack[] itemStacks = new ItemStack[INVENTORY_SIZE]; private ItemStack cursorItem = ItemStack.AIR; private final List inventoryConditions = new CopyOnWriteArrayList<>(); @@ -44,17 +44,17 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler public PlayerInventory(@NotNull Player player) { this.player = player; - Arrays.fill(items, ItemStack.AIR); + Arrays.fill(itemStacks, ItemStack.AIR); } @Override public @NotNull ItemStack getItemStack(int slot) { - return this.items[slot]; + return this.itemStacks[slot]; } @Override public @NotNull ItemStack[] getItemStacks() { - return items.clone(); + return itemStacks.clone(); } @Override @@ -109,9 +109,8 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler @Override public void clear() { // Clear the item array - for (int i = 0; i < getSize(); i++) { - setItemStackInternal(i, ItemStack.AIR); - } + Arrays.fill(itemStacks, ItemStack.AIR); + // Send the cleared inventory to the inventory's owner update(); @@ -265,7 +264,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler } } - this.items[slot] = itemStack; + this.itemStacks[slot] = itemStack; // Sync equipment if (equipmentSlot != null) { @@ -278,10 +277,6 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler //refreshSlot((short) slot); } - protected void setItemStackInternal(int slot, @NotNull ItemStack itemStack) { - items[slot] = itemStack; - } - /** * Sets an item from a packet slot. * @@ -303,7 +298,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler */ protected ItemStack getItemStack(int slot, int offset) { final int convertedSlot = convertPlayerInventorySlot(slot, offset); - return this.items[convertedSlot]; + return this.itemStacks[convertedSlot]; } /** @@ -329,9 +324,9 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler private WindowItemsPacket createWindowItemsPacket() { ItemStack[] convertedSlots = new ItemStack[INVENTORY_SIZE]; - for (int i = 0; i < items.length; i++) { + for (int i = 0; i < itemStacks.length; i++) { final int slot = convertToPacketSlot(i); - convertedSlots[slot] = items[i]; + convertedSlots[slot] = itemStacks[i]; } WindowItemsPacket windowItemsPacket = new WindowItemsPacket(); @@ -411,7 +406,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler final boolean hotBarClick = convertToPacketSlot(slot) < 9; final InventoryClickResult clickResult = clickProcessor.shiftClick(null, player, slot, clicked, cursor, - new InventoryClickLoopHandler(0, items.length, 1, + new InventoryClickLoopHandler(0, itemStacks.length, 1, i -> { if (hotBarClick) { return i < 9 ? i + 9 : i - 9; @@ -486,9 +481,9 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler final ItemStack cursor = getCursorItem(); final InventoryClickResult clickResult = clickProcessor.doubleClick(null, player, slot, cursor, - new InventoryClickLoopHandler(0, items.length, 1, + new InventoryClickLoopHandler(0, itemStacks.length, 1, i -> i < 9 ? i + 9 : i - 9, - index -> items[index], + index -> itemStacks[index], this::setItemStack)); if (clickResult == null) From d1c10243a84598ae6b33457ab612ebaa8706eeca Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 04:07:27 +0200 Subject: [PATCH 27/77] ItemMeta doesnt need to be cloneable --- src/main/java/net/minestom/server/item/ItemMeta.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index d26eefd92..189a2be4c 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -15,7 +15,7 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; -public class ItemMeta implements Cloneable { +public class ItemMeta { private final ItemMetaBuilder builder; From f52e10c2b223bc0b975a1761876f99d4a08cb8ff Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 15:01:36 +0200 Subject: [PATCH 28/77] Added InventoryModifier#replaceItemStack --- .../java/net/minestom/server/inventory/Inventory.java | 9 ++++++++- .../minestom/server/inventory/InventoryModifier.java | 6 ++++++ .../minestom/server/inventory/PlayerInventory.java | 11 +++++++++-- src/test/java/demo/PlayerInit.java | 3 ++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index 794db85d6..f3baf2fc3 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -29,6 +29,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.UnaryOperator; /** * Represents an inventory which can be viewed by a collection of {@link Player}. @@ -159,7 +160,13 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View } @Override - public void clear() { + public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { + // Make the method synchronized + InventoryModifier.super.replaceItemStack(slot, operator); + } + + @Override + public synchronized void clear() { // Clear the item array Arrays.fill(itemStacks, ItemStack.AIR); // Send the cleared inventory to viewers diff --git a/src/main/java/net/minestom/server/inventory/InventoryModifier.java b/src/main/java/net/minestom/server/inventory/InventoryModifier.java index 7b90a63e5..0a52f59d4 100644 --- a/src/main/java/net/minestom/server/inventory/InventoryModifier.java +++ b/src/main/java/net/minestom/server/inventory/InventoryModifier.java @@ -9,6 +9,7 @@ import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.function.UnaryOperator; /** * Represents an inventory where items can be modified/retrieved. @@ -75,6 +76,11 @@ public interface InventoryModifier { } } + default void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { + var currentItem = getItemStack(slot); + setItemStack(slot, operator.apply(currentItem)); + } + /** * Clears the inventory and send relevant update to the viewer(s). */ diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 714fa3ea6..d5a79ff4b 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -23,6 +23,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.UnaryOperator; import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*; @@ -73,7 +74,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler } @Override - public void setItemStack(int slot, @NotNull ItemStack itemStack) { + public synchronized void setItemStack(int slot, @NotNull ItemStack itemStack) { PlayerSetItemStackEvent setItemStackEvent = new PlayerSetItemStackEvent(player, slot, itemStack); player.callEvent(PlayerSetItemStackEvent.class, setItemStackEvent); if (setItemStackEvent.isCancelled()) @@ -107,7 +108,13 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler } @Override - public void clear() { + public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { + // Make the method synchronized + InventoryModifier.super.replaceItemStack(slot, operator); + } + + @Override + public synchronized void clear() { // Clear the item array Arrays.fill(itemStacks, ItemStack.AIR); diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 9e11a83a5..e318f2065 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -225,7 +225,8 @@ public class PlayerInit { PlayerInventory inventory = player.getInventory(); ItemStack itemStack = ItemStack.of(Material.STONE, 64); - //inventory.addItemStack(itemStack); + inventory.addItemStack(itemStack); + inventory.replaceItemStack(0, i -> i.withAmount(32)); { ItemStack item = ItemStack.builder(Material.DIAMOND_CHESTPLATE) From 4741c932a0902bb0d8e71b1a017283f280fb99c7 Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 15:45:46 +0200 Subject: [PATCH 29/77] Add ItemTag --- .../item/{ItemFlag.java => ItemHideFlag.java} | 6 ++-- .../net/minestom/server/item/ItemMeta.java | 11 +++++- .../minestom/server/item/ItemMetaBuilder.java | 16 +++++++++ .../net/minestom/server/item/ItemTag.java | 36 +++++++++++++++++++ src/test/java/demo/PlayerInit.java | 9 +++-- 5 files changed, 69 insertions(+), 9 deletions(-) rename src/main/java/net/minestom/server/item/{ItemFlag.java => ItemHideFlag.java} (66%) create mode 100644 src/main/java/net/minestom/server/item/ItemTag.java diff --git a/src/main/java/net/minestom/server/item/ItemFlag.java b/src/main/java/net/minestom/server/item/ItemHideFlag.java similarity index 66% rename from src/main/java/net/minestom/server/item/ItemFlag.java rename to src/main/java/net/minestom/server/item/ItemHideFlag.java index c4a3d55de..5d05cbb28 100644 --- a/src/main/java/net/minestom/server/item/ItemFlag.java +++ b/src/main/java/net/minestom/server/item/ItemHideFlag.java @@ -1,9 +1,9 @@ package net.minestom.server.item; /** - * Represents a flag which can be applied to an {@link ItemStack} using {@link ItemStack#addItemFlags(ItemFlag...)}. + * Represents a hide flag which can be applied to an {@link ItemStack} using {@link ItemMetaBuilder#hideFlag(int)}. */ -public enum ItemFlag { +public enum ItemHideFlag { HIDE_ENCHANTS(1), HIDE_ATTRIBUTES(2), HIDE_UNBREAKABLE(4), @@ -13,7 +13,7 @@ public enum ItemFlag { private final int bitFieldPart; - ItemFlag(int bit) { + ItemHideFlag(int bit) { this.bitFieldPart = bit; } diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 189a2be4c..e562da595 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -95,6 +95,15 @@ public class ItemMeta { return customModelData; } + @Contract("_, null -> null; _, !null -> !null") + public T getOrDefault(@NotNull ItemTag tag, @Nullable T defaultValue) { + return tag.read(toNBT()); + } + + public @Nullable T get(@NotNull ItemTag tag) { + return tag.read(toNBT()); + } + public @NotNull NBTCompound toNBT() { if (originalNbt != null) { // Return the nbt this meta has been created with @@ -127,6 +136,6 @@ public class ItemMeta { @Contract(value = "-> new", pure = true) protected @NotNull ItemMetaBuilder builder() { - return builder.clone(); + return ItemMetaBuilder.fromNBT(builder, toNBT()); } } diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 3cca989cb..ed1a56f77 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -90,6 +90,22 @@ public abstract class ItemMetaBuilder implements Cloneable { return this; } + public @NotNull ItemMetaBuilder set(@NotNull ItemTag tag, @Nullable T value) { + if (originalNBT != null) { + // Item is from nbt + if (value != null) { + tag.write(originalNBT, value); + } else { + this.originalNBT.removeTag(tag.getKey()); + } + return this; + } else { + // Create item meta based on nbt + var currentNbt = build().toNBT(); + return fromNBT(this, currentNbt).set(tag, value); + } + } + @Contract("-> new") public abstract @NotNull ItemMeta build(); diff --git a/src/main/java/net/minestom/server/item/ItemTag.java b/src/main/java/net/minestom/server/item/ItemTag.java new file mode 100644 index 000000000..a0a19f28f --- /dev/null +++ b/src/main/java/net/minestom/server/item/ItemTag.java @@ -0,0 +1,36 @@ +package net.minestom.server.item; + +import org.jetbrains.annotations.NotNull; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; + +public abstract class ItemTag { + + private final String key; + + private ItemTag(@NotNull String key) { + this.key = key; + } + + public @NotNull String getKey() { + return key; + } + + protected abstract T read(@NotNull NBTCompound nbtCompound); + + protected abstract void write(@NotNull NBTCompound nbtCompound, @NotNull T value); + + public static @NotNull ItemTag Integer(@NotNull String key) { + return new ItemTag<>(key) { + @Override + protected Integer read(@NotNull NBTCompound nbtCompound) { + return nbtCompound.getInt(key); + } + + @Override + protected void write(@NotNull NBTCompound nbtCompound, @NotNull Integer value) { + nbtCompound.setInt(key, value); + } + }; + } + +} diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index e318f2065..022b5d45f 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -27,6 +27,7 @@ import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; +import net.minestom.server.item.ItemTag; import net.minestom.server.item.Material; import net.minestom.server.item.meta.CompassMeta; import net.minestom.server.network.ConnectionManager; @@ -69,12 +70,10 @@ public class PlayerInit { .build(); ItemStack itemStack = ItemStack.builder(Material.COMPASS) - .amount(5) - .meta(compassMeta) .meta(CompassMeta.class, builder -> { builder.lodestonePosition(new Position(0, 0, 0)); + builder.set(ItemTag.Integer("int"), 25); }) - .displayName(Component.text("displayName")) .build(); itemStack = itemStack.with(itemBuilder -> itemBuilder @@ -225,8 +224,8 @@ public class PlayerInit { PlayerInventory inventory = player.getInventory(); ItemStack itemStack = ItemStack.of(Material.STONE, 64); - inventory.addItemStack(itemStack); - inventory.replaceItemStack(0, i -> i.withAmount(32)); + inventory.addItemStack(itemStack.withMeta(metaBuilder -> metaBuilder.set(ItemTag.Integer("int"), 25))); + //inventory.replaceItemStack(0, i -> i.withAmount(32)); { ItemStack item = ItemStack.builder(Material.DIAMOND_CHESTPLATE) From c8fbf47bd9c660bea19b11b7c5a2abfc1e7680d3 Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 15:50:34 +0200 Subject: [PATCH 30/77] Impl ItemMeta#getOrDefault --- src/main/java/net/minestom/server/item/ItemMeta.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index e562da595..dc116fc93 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -95,9 +95,14 @@ public class ItemMeta { return customModelData; } - @Contract("_, null -> null; _, !null -> !null") public T getOrDefault(@NotNull ItemTag tag, @Nullable T defaultValue) { - return tag.read(toNBT()); + var nbt = toNBT(); + var key = tag.getKey(); + if (nbt.containsKey(key)) { + return tag.read(toNBT()); + } else { + return defaultValue; + } } public @Nullable T get(@NotNull ItemTag tag) { From 89b35a056967e1d24b4c82fce6adb56217a39be1 Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 16:03:03 +0200 Subject: [PATCH 31/77] Cleanup ItemTag --- .../net/minestom/server/item/ItemTag.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemTag.java b/src/main/java/net/minestom/server/item/ItemTag.java index a0a19f28f..4ad673136 100644 --- a/src/main/java/net/minestom/server/item/ItemTag.java +++ b/src/main/java/net/minestom/server/item/ItemTag.java @@ -3,34 +3,39 @@ package net.minestom.server.item; import org.jetbrains.annotations.NotNull; import org.jglrxavpok.hephaistos.nbt.NBTCompound; -public abstract class ItemTag { +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class ItemTag { private final String key; + private final Function readFunction; + private final BiConsumer writeConsumer; - private ItemTag(@NotNull String key) { + private ItemTag(@NotNull String key, + @NotNull Function readFunction, + @NotNull BiConsumer writeConsumer) { this.key = key; + this.readFunction = readFunction; + this.writeConsumer = writeConsumer; } public @NotNull String getKey() { return key; } - protected abstract T read(@NotNull NBTCompound nbtCompound); + protected T read(@NotNull NBTCompound nbtCompound) { + return readFunction.apply(nbtCompound); + } - protected abstract void write(@NotNull NBTCompound nbtCompound, @NotNull T value); + protected void write(@NotNull NBTCompound nbtCompound, @NotNull T value) { + this.writeConsumer.accept(nbtCompound, value); + } public static @NotNull ItemTag Integer(@NotNull String key) { - return new ItemTag<>(key) { - @Override - protected Integer read(@NotNull NBTCompound nbtCompound) { - return nbtCompound.getInt(key); - } - - @Override - protected void write(@NotNull NBTCompound nbtCompound, @NotNull Integer value) { - nbtCompound.setInt(key, value); - } - }; + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getInt(key), + (nbtCompound, integer) -> nbtCompound.setInt(key, integer)); } } From e4936b4a530ce023243ba34a61e9213208a46974 Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 17:14:00 +0200 Subject: [PATCH 32/77] Added almost all item tags --- .../net/minestom/server/item/ItemTag.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/main/java/net/minestom/server/item/ItemTag.java b/src/main/java/net/minestom/server/item/ItemTag.java index 4ad673136..ad5350042 100644 --- a/src/main/java/net/minestom/server/item/ItemTag.java +++ b/src/main/java/net/minestom/server/item/ItemTag.java @@ -32,10 +32,66 @@ public class ItemTag { this.writeConsumer.accept(nbtCompound, value); } + public static @NotNull ItemTag Byte(@NotNull String key) { + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getByte(key), + (nbtCompound, value) -> nbtCompound.setByte(key, value)); + } + + public static @NotNull ItemTag Short(@NotNull String key) { + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getShort(key), + (nbtCompound, value) -> nbtCompound.setShort(key, value)); + } + public static @NotNull ItemTag Integer(@NotNull String key) { return new ItemTag<>(key, nbtCompound -> nbtCompound.getInt(key), (nbtCompound, integer) -> nbtCompound.setInt(key, integer)); } + public static @NotNull ItemTag Long(@NotNull String key) { + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getLong(key), + (nbtCompound, value) -> nbtCompound.setLong(key, value)); + } + + public static @NotNull ItemTag Float(@NotNull String key) { + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getFloat(key), + (nbtCompound, value) -> nbtCompound.setFloat(key, value)); + } + + public static @NotNull ItemTag Double(@NotNull String key) { + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getDouble(key), + (nbtCompound, value) -> nbtCompound.setDouble(key, value)); + } + + public static @NotNull ItemTag ByteArray(@NotNull String key) { + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getByteArray(key), + (nbtCompound, value) -> nbtCompound.setByteArray(key, value)); + } + + public static @NotNull ItemTag String(@NotNull String key) { + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getString(key), + (nbtCompound, value) -> nbtCompound.setString(key, value)); + } + + // TODO List/Compound + + public static @NotNull ItemTag IntArray(@NotNull String key) { + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getIntArray(key), + (nbtCompound, value) -> nbtCompound.setIntArray(key, value)); + } + + public static @NotNull ItemTag LongArray(@NotNull String key) { + return new ItemTag<>(key, + nbtCompound -> nbtCompound.getLongArray(key), + (nbtCompound, value) -> nbtCompound.setLongArray(key, value)); + } + } From dfa7d712c2477a6b333faeede2aefd8f74a5cc07 Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 19:08:07 +0200 Subject: [PATCH 33/77] Initial ItemStore support --- .../net/minestom/server/item/ItemStack.java | 22 ++++++--- ...ItemBuilder.java => ItemStackBuilder.java} | 38 ++++++++++----- .../net/minestom/server/item/ItemStore.java | 30 ++++++++++++ .../server/item/ItemStoreBuilder.java | 46 +++++++++++++++++++ src/test/java/demo/PlayerInit.java | 9 +++- 5 files changed, 126 insertions(+), 19 deletions(-) rename src/main/java/net/minestom/server/item/{ItemBuilder.java => ItemStackBuilder.java} (53%) create mode 100644 src/main/java/net/minestom/server/item/ItemStore.java create mode 100644 src/main/java/net/minestom/server/item/ItemStoreBuilder.java diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index 844b4bd7a..d71e8abcc 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -32,15 +32,20 @@ public class ItemStack { private final int amount; private final ItemMeta meta; - protected ItemStack(@NotNull Material material, int amount, @NotNull ItemMeta meta) { + private final ItemStore store; + + protected ItemStack(@NotNull Material material, int amount, + @NotNull ItemMeta meta, + @NotNull ItemStore store) { this.material = material; this.amount = amount; this.meta = meta; + this.store = store; } @Contract(value = "_ -> new", pure = true) - public static @NotNull ItemBuilder builder(@NotNull Material material) { - return new ItemBuilder(material); + public static @NotNull ItemStackBuilder builder(@NotNull Material material) { + return new ItemStackBuilder(material); } @Contract(value = "_ ,_ -> new", pure = true) @@ -64,7 +69,7 @@ public class ItemStack { } @Contract(value = "_, -> new", pure = true) - public @NotNull ItemStack with(@NotNull Consumer<@NotNull ItemBuilder> builderConsumer) { + public @NotNull ItemStack with(@NotNull Consumer<@NotNull ItemStackBuilder> builderConsumer) { var builder = builder(); builderConsumer.accept(builder); return builder.build(); @@ -135,6 +140,11 @@ public class ItemStack { return meta; } + @Contract(pure = true) + public @NotNull ItemStore getStore() { + return store; + } + @Contract(pure = true) public boolean isAir() { return material.equals(Material.AIR); @@ -170,8 +180,8 @@ public class ItemStack { } @Contract(value = "-> new", pure = true) - protected @NotNull ItemBuilder builder() { - return new ItemBuilder(material, meta.builder()) + protected @NotNull ItemStackBuilder builder() { + return new ItemStackBuilder(material, meta.builder(), store.builder()) .amount(amount); } } diff --git a/src/main/java/net/minestom/server/item/ItemBuilder.java b/src/main/java/net/minestom/server/item/ItemStackBuilder.java similarity index 53% rename from src/main/java/net/minestom/server/item/ItemBuilder.java rename to src/main/java/net/minestom/server/item/ItemStackBuilder.java index 506107fdd..ed8ec655d 100644 --- a/src/main/java/net/minestom/server/item/ItemBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemStackBuilder.java @@ -10,68 +10,82 @@ import java.util.List; import java.util.function.Consumer; import java.util.function.UnaryOperator; -public class ItemBuilder { +public class ItemStackBuilder { private final Material material; private int amount; protected ItemMetaBuilder metaBuilder; + protected ItemStoreBuilder storeBuilder; - protected ItemBuilder(@NotNull Material material, @NotNull ItemMetaBuilder metaBuilder) { + protected ItemStackBuilder(@NotNull Material material, @NotNull ItemMetaBuilder metaBuilder, @NotNull ItemStoreBuilder storeBuilder) { this.material = material; this.amount = 1; this.metaBuilder = metaBuilder; + this.storeBuilder = storeBuilder; } - protected ItemBuilder(@NotNull Material material) { + protected ItemStackBuilder(@NotNull Material material) { // TODO: meta depends on material - this(material, new CompassMeta.Builder()); + this(material, new CompassMeta.Builder(), new ItemStoreBuilder()); } @Contract(value = "_ -> this") - public @NotNull ItemBuilder amount(int amount) { + public @NotNull ItemStackBuilder amount(int amount) { this.amount = amount; return this; } @Contract(value = "_ -> this") - public @NotNull ItemBuilder meta(@NotNull ItemMeta itemMeta) { + public @NotNull ItemStackBuilder meta(@NotNull ItemMeta itemMeta) { this.metaBuilder = itemMeta.builder(); return this; } @Contract(value = "_ -> this") - public @NotNull ItemBuilder meta(@NotNull UnaryOperator<@NotNull ItemMetaBuilder> itemMetaConsumer) { + public @NotNull ItemStackBuilder meta(@NotNull UnaryOperator<@NotNull ItemMetaBuilder> itemMetaConsumer) { this.metaBuilder = itemMetaConsumer.apply(metaBuilder); return this; } @Contract(value = "_, _ -> this") - public > @NotNull ItemBuilder meta(@NotNull Class metaType, @NotNull Consumer<@NotNull T> itemMetaConsumer) { + public > @NotNull ItemStackBuilder meta(@NotNull Class metaType, @NotNull Consumer<@NotNull T> itemMetaConsumer) { itemMetaConsumer.accept((T) metaBuilder); return this; } @Contract(value = "_ -> this") - public @NotNull ItemBuilder displayName(@Nullable Component displayName) { + public @NotNull ItemStackBuilder displayName(@Nullable Component displayName) { this.metaBuilder.displayName(displayName); return this; } @Contract(value = "_ -> this") - public @NotNull ItemBuilder lore(List<@NotNull Component> lore) { + public @NotNull ItemStackBuilder lore(List<@NotNull Component> lore) { this.metaBuilder.lore(lore); return this; } @Contract(value = "_ -> this") - public @NotNull ItemBuilder lore(Component... lore) { + public @NotNull ItemStackBuilder lore(Component... lore) { this.metaBuilder.lore(lore); return this; } + @Contract(value = "_ -> this") + public @NotNull ItemStackBuilder store(@NotNull ItemStore store) { + this.storeBuilder = store.builder(); + return this; + } + + @Contract(value = "_ -> this") + public @NotNull ItemStackBuilder store(@NotNull Consumer<@NotNull ItemStoreBuilder> consumer) { + consumer.accept(storeBuilder); + return this; + } + @Contract(value = "-> new", pure = true) public @NotNull ItemStack build() { - return new ItemStack(material, amount, metaBuilder.build()); + return new ItemStack(material, amount, metaBuilder.build(), storeBuilder.build()); } } diff --git a/src/main/java/net/minestom/server/item/ItemStore.java b/src/main/java/net/minestom/server/item/ItemStore.java new file mode 100644 index 000000000..8dd82769a --- /dev/null +++ b/src/main/java/net/minestom/server/item/ItemStore.java @@ -0,0 +1,30 @@ +package net.minestom.server.item; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ItemStore { + + private final Map> entryMap; + + protected ItemStore(@NotNull Map> entryMap) { + this.entryMap = Collections.unmodifiableMap(entryMap); + } + + public T get(@NotNull String key) { + if (entryMap.containsKey(key)) { + return (T) entryMap.get(key).value; + } + return null; + } + + @Contract(value = "-> new", pure = true) + protected @NotNull ItemStoreBuilder builder() { + return new ItemStoreBuilder(new ConcurrentHashMap<>(entryMap)); + } + +} diff --git a/src/main/java/net/minestom/server/item/ItemStoreBuilder.java b/src/main/java/net/minestom/server/item/ItemStoreBuilder.java new file mode 100644 index 000000000..6f516be2b --- /dev/null +++ b/src/main/java/net/minestom/server/item/ItemStoreBuilder.java @@ -0,0 +1,46 @@ +package net.minestom.server.item; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ItemStoreBuilder { + + private final Map> entryMap; + + protected ItemStoreBuilder(@NotNull Map> entryMap) { + this.entryMap = entryMap; + } + + protected ItemStoreBuilder() { + this(new ConcurrentHashMap<>()); + } + + public void set(@NotNull String key, T value, MergingRule mergingRule) { + this.entryMap.put(key, new Entry<>(value, mergingRule)); + } + + @Contract(value = "-> new", pure = true) + public @NotNull ItemStore build() { + return new ItemStore(new HashMap<>(entryMap)); + } + + public interface MergingRule { + @Nullable T apply(@NotNull T value1, @NotNull T value2); + } + + protected static class Entry { + protected final T value; + protected final MergingRule mergingRule; + + private Entry(@NotNull T value, @NotNull MergingRule mergingRule) { + this.value = value; + this.mergingRule = mergingRule; + } + } + +} diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 022b5d45f..b82d1931b 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -27,6 +27,7 @@ import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; +import net.minestom.server.item.ItemStore; import net.minestom.server.item.ItemTag; import net.minestom.server.item.Material; import net.minestom.server.item.meta.CompassMeta; @@ -74,8 +75,14 @@ public class PlayerInit { builder.lodestonePosition(new Position(0, 0, 0)); builder.set(ItemTag.Integer("int"), 25); }) + .store(store -> { + store.set("key", 5, Integer::sum); + }) .build(); + ItemStore store = itemStack.getStore(); + System.out.println("value: " + store.get("key")); + itemStack = itemStack.with(itemBuilder -> itemBuilder .amount(10) .meta(CompassMeta.class, builder -> { @@ -225,7 +232,7 @@ public class PlayerInit { PlayerInventory inventory = player.getInventory(); ItemStack itemStack = ItemStack.of(Material.STONE, 64); inventory.addItemStack(itemStack.withMeta(metaBuilder -> metaBuilder.set(ItemTag.Integer("int"), 25))); - //inventory.replaceItemStack(0, i -> i.withAmount(32)); + inventory.replaceItemStack(0, i -> i.withAmount(32)); { ItemStack item = ItemStack.builder(Material.DIAMOND_CHESTPLATE) From ca413654533e7683bf22452d1604428541c6797c Mon Sep 17 00:00:00 2001 From: themode Date: Sat, 3 Apr 2021 19:35:03 +0200 Subject: [PATCH 34/77] Added some useful store methods --- .../net/minestom/server/item/ItemStack.java | 10 ++++++++++ src/test/java/demo/PlayerInit.java | 17 +++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index d71e8abcc..f3936dea8 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -100,6 +100,16 @@ public class ItemStack { return builder().meta(metaOperator).build(); } + @Contract(value = "_, -> new", pure = true) + public @NotNull ItemStack withStore(@NotNull ItemStore store) { + return builder().store(store).build(); + } + + @Contract(value = "_ -> new", pure = true) + public @NotNull ItemStack withStore(@NotNull Consumer<@NotNull ItemStoreBuilder> metaOperator) { + return builder().store(metaOperator).build(); + } + @Contract(pure = true) public @Nullable Component getDisplayName() { return meta.getDisplayName(); diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index b82d1931b..b98f79bd1 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -80,9 +80,6 @@ public class PlayerInit { }) .build(); - ItemStore store = itemStack.getStore(); - System.out.println("value: " + store.get("key")); - itemStack = itemStack.with(itemBuilder -> itemBuilder .amount(10) .meta(CompassMeta.class, builder -> { @@ -230,9 +227,16 @@ public class PlayerInit { player.setPermissionLevel(4); PlayerInventory inventory = player.getInventory(); - ItemStack itemStack = ItemStack.of(Material.STONE, 64); - inventory.addItemStack(itemStack.withMeta(metaBuilder -> metaBuilder.set(ItemTag.Integer("int"), 25))); - inventory.replaceItemStack(0, i -> i.withAmount(32)); + ItemStack itemStack = ItemStack.builder(Material.STONE) + .amount(64) + .store(store -> { + store.set("key", 5, Integer::sum); + }) + .build(); + + itemStack = itemStack.withStore(storeBuilder -> storeBuilder.set("key2", 25, Integer::sum)); + + inventory.addItemStack(itemStack); { ItemStack item = ItemStack.builder(Material.DIAMOND_CHESTPLATE) @@ -251,6 +255,7 @@ public class PlayerInit { globalEventHandler.addEventCallback(PlayerUseItemEvent.class, useEvent -> { final Player player = useEvent.getPlayer(); + System.out.println("test: " + player.getItemInMainHand().getStore().get("key2")); player.sendMessage("Using item in air: " + useEvent.getItemStack().getMaterial()); }); From fdfd20e255d8039f1bc3bd56640e70ec7e151fbc Mon Sep 17 00:00:00 2001 From: Konstantin Shandurenko Date: Sun, 4 Apr 2021 03:56:44 +0300 Subject: [PATCH 35/77] InventoryModifier to AbstractInventory and additional methods for inventories --- .../minestom/demo/largeframebuffers/Demo.java | 8 +- .../fakeplayer/FakePlayerController.java | 8 +- .../server/inventory/AbstractInventory.java | 316 ++++++++++++++++++ .../minestom/server/inventory/Inventory.java | 15 +- .../server/inventory/InventoryModifier.java | 145 -------- .../server/inventory/PlayerInventory.java | 24 +- .../condition/InventoryCondition.java | 4 +- .../minestom/server/item/meta/MapMeta.java | 278 +++++++++++++++ .../server/item/metadata/ItemMeta.java | 1 + .../server/item/metadata/MapMeta.java | 2 - 10 files changed, 621 insertions(+), 180 deletions(-) create mode 100644 src/main/java/net/minestom/server/inventory/AbstractInventory.java delete mode 100644 src/main/java/net/minestom/server/inventory/InventoryModifier.java create mode 100644 src/main/java/net/minestom/server/item/meta/MapMeta.java diff --git a/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java b/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java index 2516082d7..2fb89afc3 100644 --- a/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java +++ b/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java @@ -6,8 +6,9 @@ import net.minestom.server.entity.GameMode; import net.minestom.server.entity.type.decoration.EntityItemFrame; import net.minestom.server.instance.Instance; import net.minestom.server.instance.InstanceManager; +import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.minestom.server.item.metadata.MapMeta; +import net.minestom.server.item.meta.MapMeta; import net.minestom.server.map.Framebuffer; import net.minestom.server.map.LargeFramebuffer; import net.minestom.server.map.MapColors; @@ -67,8 +68,9 @@ public class Demo { private static void createFrame(Instance instance, int id, int x, int y, int z) { EntityItemFrame itemFrame = new EntityItemFrame(new Position(x, y, z), EntityItemFrame.ItemFrameOrientation.NORTH); itemFrame.getPosition().setYaw(180f); - ItemStack map = new ItemStack(Material.FILLED_MAP, (byte) 1); - map.setItemMeta(new MapMeta(id)); + ItemStack map = ItemStack.builder(Material.FILLED_MAP) + .meta(new MapMeta.Builder().mapId(id).build()) + .build(); itemFrame.setItemStack(map); itemFrame.setInstance(instance); itemFrame.setCustomNameVisible(true); diff --git a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java index 08444fa19..6a9e8eeb2 100644 --- a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java +++ b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java @@ -4,7 +4,7 @@ import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; import net.minestom.server.instance.block.BlockFace; import net.minestom.server.inventory.Inventory; -import net.minestom.server.inventory.InventoryModifier; +import net.minestom.server.inventory.AbstractInventory; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.client.ClientPlayPacket; @@ -48,12 +48,12 @@ public class FakePlayerController { */ public void clickWindow(boolean playerInventory, short slot, byte button, short action, int mode) { Inventory inventory = playerInventory ? null : fakePlayer.getOpenInventory(); - InventoryModifier inventoryModifier = inventory == null ? fakePlayer.getInventory() : inventory; - playerInventory = inventoryModifier instanceof PlayerInventory; + AbstractInventory abstractInventory = inventory == null ? fakePlayer.getInventory() : inventory; + playerInventory = abstractInventory instanceof PlayerInventory; slot = playerInventory ? (short) PlayerInventoryUtils.convertToPacketSlot(slot) : slot; - ItemStack itemStack = inventoryModifier.getItemStack(slot); + ItemStack itemStack = abstractInventory.getItemStack(slot); ClientClickWindowPacket clickWindowPacket = new ClientClickWindowPacket(); clickWindowPacket.windowId = playerInventory ? 0 : inventory.getWindowId(); diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java new file mode 100644 index 000000000..88abcb383 --- /dev/null +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -0,0 +1,316 @@ +package net.minestom.server.inventory; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minestom.server.inventory.condition.InventoryCondition; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.StackingRule; +import net.minestom.server.utils.validate.Check; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.UnaryOperator; + +/** + * Represents an inventory where items can be modified/retrieved. + */ +public abstract class AbstractInventory { + + /** + * Sets an {@link ItemStack} at the specified slot and send relevant update to the viewer(s). + * + * @param slot the slot to set the item + * @param itemStack the item to set + */ + public abstract void setItemStack(int slot, @NotNull ItemStack itemStack); + + protected abstract void safeItemInsert(int slot, @NotNull ItemStack itemStack); + + /** + * Adds an {@link ItemStack} to the inventory and sends relevant update to the viewer(s). + *

+ * Even the item cannot be fully added, the amount of {@code itemStack} will be updated. + * + * @param itemStack the item to add + * @return true if the item has been successfully fully added, false otherwise + */ + public boolean addItemStack(@NotNull ItemStack itemStack) { + Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); + + final StackingRule stackingRule = itemStack.getStackingRule(); + for (int i = 0; i < getInnerSize(); i++) { + ItemStack inventoryItem = getItemStack(i); + if (inventoryItem.isAir()) { + continue; + } + if (stackingRule.canBeStacked(itemStack, inventoryItem)) { + final int itemAmount = stackingRule.getAmount(inventoryItem); + if (itemAmount == stackingRule.getMaxSize()) + continue; + final int itemStackAmount = stackingRule.getAmount(itemStack); + final int totalAmount = itemStackAmount + itemAmount; + if (!stackingRule.canApply(itemStack, totalAmount)) { + // Slot cannot accept the whole item, reduce amount to 'itemStack' + itemChangesMap.put(i, stackingRule.apply(inventoryItem, stackingRule.getMaxSize())); + itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); + } else { + // Slot can accept the whole item + itemChangesMap.put(i, inventoryItem.withAmount(totalAmount)); + itemStack = ItemStack.AIR; + break; + } + } + } + for (int i = 0; i < getInnerSize(); i++) { + ItemStack inventoryItem = getItemStack(i); + if (!inventoryItem.isAir()) { + continue; + } + // Fill the slot + itemChangesMap.put(i, itemStack); + itemStack = ItemStack.AIR; + break; + } + + if (itemStack.isAir()) { + // Item can be fully placed inside the inventory, do so + itemChangesMap.forEach(this::safeItemInsert); + return true; + } else { + // Inventory cannot accept the item fully + return false; + } + } + + /** + * Adds {@link ItemStack}s to the inventory and sends relevant updates to the viewer(s). + *

+ * Even items cannot be fully added, the amount of {@code itemStack}s will be updated. + * + * @param itemStacks items to add + * @return list of itemstacks that could not be successfully fully added, empty list otherwise + */ + public List addItemStacks(@NotNull List itemStacks) { + List result = new ArrayList<>(); + itemStacks.forEach(itemStack -> { + if (!addItemStack(itemStack)) { + result.add(itemStack); + } + }); + return result; + } + + /** + * Checks whether {@link ItemStack} can be fully added to the inventory. + * + * @param itemStack the item to be checked + * @return true if the item can be fully added to the inventory, false otherwise + */ + public boolean canAddItemStack(@NotNull ItemStack itemStack) { + final StackingRule stackingRule = itemStack.getStackingRule(); + int amountLeft = itemStack.getAmount(); + for (int i = 0; i < getInnerSize(); i++) { + ItemStack inventoryItem = getItemStack(i); + if (stackingRule.canBeStacked(itemStack, inventoryItem)) { + final int itemAmount = stackingRule.getAmount(inventoryItem); + if (itemAmount == stackingRule.getMaxSize()) + continue; + if (!stackingRule.canApply(itemStack, amountLeft + itemAmount)) { + // Slot cannot accept the whole item, reduce amount to 'itemStack' + amountLeft -= stackingRule.getMaxSize() - itemAmount; + } else { + return true; + } + } else if (inventoryItem.isAir()) { + return true; + } + } + return false; + } + + /** + * Checks whether {@link ItemStack}s can be fully added to the inventory. + * + * @param itemStacks items to be checked + * @return true if all the items can be fully added to the inventory, false otherwise + */ + public boolean canAddItemStacks(@NotNull List itemStacks) { + return itemStacks.stream().allMatch(this::canAddItemStack); + } + + /** + * Takes an {@link ItemStack} from the inventory and sends relevant update to the viewer(s). + *

+ * Even the item cannot be fully taken, the amount of {@code itemStack} will be updated. + * + * @param itemStack the item to take + * @return true if the item has been successfully fully taken, false otherwise + */ + public boolean takeItemStack(@NotNull ItemStack itemStack) { + Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); + + final StackingRule stackingRule = itemStack.getStackingRule(); + for (int i = 0; i < getInnerSize(); i++) { + ItemStack inventoryItem = getItemStack(i); + if (inventoryItem.isAir()) { + continue; + } + if (stackingRule.canBeStacked(itemStack, inventoryItem)) { + final int itemAmount = stackingRule.getAmount(inventoryItem); + final int itemStackAmount = stackingRule.getAmount(itemStack); + if (itemStackAmount < itemAmount) { + itemChangesMap.put(i, stackingRule.apply(inventoryItem, itemAmount - itemStackAmount)); + itemStack = ItemStack.AIR; + break; + } + itemChangesMap.put(i, ItemStack.AIR); + itemStack = itemStack.withAmount(amount -> amount - itemAmount); + if (itemStack.getAmount() == 0) { + itemStack = ItemStack.AIR; + break; + } + } + } + + if (itemStack.isAir()) { + // Item can be fully taken from the inventory, do so + itemChangesMap.forEach(this::safeItemInsert); + return true; + } else { + return false; + } + } + + /** + * Takes {@link ItemStack}s from the inventory and sends relevant updates to the viewer(s). + *

+ * Even items cannot be fully taken, the amount of {@code itemStack}s will be updated. + * + * @param itemStacks items to take + * @return list of itemstacks that could not be successfully fully taken, empty list otherwise + */ + public List takeItemStacks(@NotNull List itemStacks) { + List result = new ArrayList<>(); + itemStacks.forEach(itemStack -> { + if (!takeItemStack(itemStack)) { + result.add(itemStack); + } + }); + return result; + } + + /** + * Checks whether {@link ItemStack} can be fully taken from the inventory. + * + * @param itemStack the item to be checked + * @return true if the item can be fully taken from the inventory, false otherwise + */ + public boolean canTakeItemStack(@NotNull ItemStack itemStack) { + final StackingRule stackingRule = itemStack.getStackingRule(); + for (int i = 0; i < getInnerSize(); i++) { + ItemStack inventoryItem = getItemStack(i); + if (inventoryItem.isAir()) { + continue; + } + if (stackingRule.canBeStacked(itemStack, inventoryItem)) { + final int itemAmount = stackingRule.getAmount(inventoryItem); + final int itemStackAmount = stackingRule.getAmount(itemStack); + if (itemStackAmount <= itemAmount) { + return true; + } + itemStack = itemStack.withAmount(amount -> amount - itemAmount); + } + } + return false; + } + + /** + * Checks whether {@link ItemStack}s can be fully taken from the inventory. + * + * @param itemStacks items to be checked + * @return true if all the items can be fully taken from the inventory, false otherwise + */ + public boolean canTakeItemStacks(@NotNull List itemStacks) { + return itemStacks.stream().allMatch(this::canTakeItemStack); + } + + public void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { + var currentItem = getItemStack(slot); + setItemStack(slot, operator.apply(currentItem)); + } + + /** + * Clears the inventory and send relevant update to the viewer(s). + */ + public abstract void clear(); + + /** + * Gets the {@link ItemStack} at the specified slot. + * + * @param slot the slot to check + * @return the item in the slot {@code slot} + */ + @NotNull + public abstract ItemStack getItemStack(int slot); + + /** + * Gets all the {@link ItemStack} in the inventory. + *

+ * Be aware that the returned array does not need to be the original one, + * meaning that modifying it directly may not work. + * + * @return an array containing all the inventory's items + */ + @NotNull + public abstract ItemStack[] getItemStacks(); + + /** + * Gets the size of the inventory. + * + * @return the inventory's size + */ + public abstract int getSize(); + + /** + * Gets the size of the "inner inventory" (which includes only "usable" slots). + * + * @return inner inventory's size + */ + public int getInnerSize() { + return getSize(); + } + + /** + * Gets all the {@link InventoryCondition} of this inventory. + * + * @return a modifiable {@link List} containing all the inventory conditions + */ + @NotNull + public abstract List getInventoryConditions(); + + /** + * Adds a new {@link InventoryCondition} to this inventory. + * + * @param inventoryCondition the inventory condition to add + */ + public abstract void addInventoryCondition(@NotNull InventoryCondition inventoryCondition); + + /** + * Places all the items of {@code itemStacks} into the internal array. + * + * @param itemStacks the array to copy the content from + * @throws IllegalArgumentException if the size of the array is not equal to {@link #getSize()} + * @throws NullPointerException if {@code itemStacks} contains one null element or more + */ + public void copyContents(@NotNull ItemStack[] itemStacks) { + Check.argCondition(itemStacks.length != getSize(), + "The size of the array has to be of the same size as the inventory: " + getSize()); + + for (int i = 0; i < itemStacks.length; i++) { + final ItemStack itemStack = itemStacks[i]; + Check.notNull(itemStack, "The item array cannot contain any null element!"); + setItemStack(i, itemStack); + } + } +} diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index f3baf2fc3..0bb92d6e9 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -37,7 +37,7 @@ import java.util.function.UnaryOperator; * You can create one with {@link Inventory#Inventory(InventoryType, String)} or by making your own subclass. * It can then be opened using {@link Player#openInventory(Inventory)}. */ -public class Inventory implements InventoryModifier, InventoryClickHandler, Viewable, DataContainer { +public class Inventory extends AbstractInventory implements InventoryClickHandler, Viewable, DataContainer { // incremented each time an inventory is created (used in the window packets) private static final AtomicInteger LAST_INVENTORY_ID = new AtomicInteger(); @@ -150,19 +150,13 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View @Override public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { // Make the method synchronized - return InventoryModifier.super.addItemStack(itemStack); - } - - @Override - public synchronized boolean addItemStack(@NotNull ItemStack itemStack, int startSlot, int endSlot) { - // Make the method synchronized - return InventoryModifier.super.addItemStack(itemStack, startSlot, endSlot); + return super.addItemStack(itemStack); } @Override public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { // Make the method synchronized - InventoryModifier.super.replaceItemStack(slot, operator); + super.replaceItemStack(slot, operator); } @Override @@ -299,7 +293,8 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View * @param slot the internal slot id * @param itemStack the item to insert */ - private synchronized void safeItemInsert(int slot, @NotNull ItemStack itemStack) { + @Override + protected synchronized void safeItemInsert(int slot, @NotNull ItemStack itemStack) { this.itemStacks[slot] = itemStack; SetSlotPacket setSlotPacket = new SetSlotPacket(); setSlotPacket.windowId = getWindowId(); diff --git a/src/main/java/net/minestom/server/inventory/InventoryModifier.java b/src/main/java/net/minestom/server/inventory/InventoryModifier.java deleted file mode 100644 index 0a52f59d4..000000000 --- a/src/main/java/net/minestom/server/inventory/InventoryModifier.java +++ /dev/null @@ -1,145 +0,0 @@ -package net.minestom.server.inventory; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import net.minestom.server.inventory.condition.InventoryCondition; -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.StackingRule; -import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.function.UnaryOperator; - -/** - * Represents an inventory where items can be modified/retrieved. - */ -public interface InventoryModifier { - - /** - * Sets an {@link ItemStack} at the specified slot and send relevant update to the viewer(s). - * - * @param slot the slot to set the item - * @param itemStack the item to set - */ - void setItemStack(int slot, @NotNull ItemStack itemStack); - - /** - * Adds an {@link ItemStack} to the inventory and send relevant update to the viewer(s). - *

- * Even the item cannot be fully added, the amount of {@code itemStack} will be updated. - * - * @param itemStack the item to add - * @return true if the item has been successfully fully added, false otherwise - */ - default boolean addItemStack(@NotNull ItemStack itemStack) { - return addItemStack(itemStack, 0, getSize()); - } - - default boolean addItemStack(@NotNull ItemStack itemStack, int startSlot, int endSlot) { - Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); - - final StackingRule stackingRule = itemStack.getStackingRule(); - for (int i = startSlot; i < endSlot; i++) { - ItemStack inventoryItem = getItemStack(i); - if (stackingRule.canBeStacked(itemStack, inventoryItem)) { - final int itemAmount = stackingRule.getAmount(inventoryItem); - if (itemAmount == stackingRule.getMaxSize()) - continue; - final int itemStackAmount = stackingRule.getAmount(itemStack); - final int totalAmount = itemStackAmount + itemAmount; - if (!stackingRule.canApply(itemStack, totalAmount)) { - // Slot cannot accept the whole item, reduce amount to 'itemStack' - itemChangesMap.put(i, stackingRule.apply(inventoryItem, stackingRule.getMaxSize())); - itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); - } else { - // Slot can accept the whole item - itemChangesMap.put(i, inventoryItem.withAmount(totalAmount)); - itemStack = ItemStack.AIR; - break; - } - } else if (inventoryItem.isAir()) { - // Fill the slot - itemChangesMap.put(i, itemStack); - itemStack = ItemStack.AIR; - break; - } - } - - if (itemStack.isAir()) { - // Item can be fully placed inside the inventory, do so - itemChangesMap.forEach(this::setItemStack); - return true; - } else { - // Inventory cannot accept the item fully - return false; - } - } - - default void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { - var currentItem = getItemStack(slot); - setItemStack(slot, operator.apply(currentItem)); - } - - /** - * Clears the inventory and send relevant update to the viewer(s). - */ - void clear(); - - /** - * Gets the {@link ItemStack} at the specified slot. - * - * @param slot the slot to check - * @return the item in the slot {@code slot} - */ - @NotNull ItemStack getItemStack(int slot); - - /** - * Gets all the {@link ItemStack} in the inventory. - *

- * Be aware that the returned array does not need to be the original one, - * meaning that modifying it directly may not work. - * - * @return an array containing all the inventory's items - */ - @NotNull ItemStack[] getItemStacks(); - - /** - * Gets the size of the inventory. - * - * @return the inventory's size - */ - int getSize(); - - /** - * Gets all the {@link InventoryCondition} of this inventory. - * - * @return a modifiable {@link List} containing all the inventory conditions - */ - @NotNull List getInventoryConditions(); - - /** - * Adds a new {@link InventoryCondition} to this inventory. - * - * @param inventoryCondition the inventory condition to add - */ - void addInventoryCondition(@NotNull InventoryCondition inventoryCondition); - - /** - * Places all the items of {@code itemStacks} into the internal array. - * - * @param itemStacks the array to copy the content from - * @throws IllegalArgumentException if the size of the array is not equal to {@link #getSize()} - * @throws NullPointerException if {@code itemStacks} contains one null element or more - */ - default void copyContents(@NotNull ItemStack[] itemStacks) { - Check.argCondition(itemStacks.length != getSize(), - "The size of the array has to be of the same size as the inventory: " + getSize()); - - for (int i = 0; i < itemStacks.length; i++) { - final ItemStack itemStack = itemStacks[i]; - Check.notNull(itemStack, "The item array cannot contain any null element!"); - setItemStack(i, itemStack); - } - } -} diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index d5a79ff4b..72ef75e96 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -30,9 +30,10 @@ import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*; /** * Represents the inventory of a {@link Player}, retrieved with {@link Player#getInventory()}. */ -public class PlayerInventory implements InventoryModifier, InventoryClickHandler, EquipmentHandler, DataContainer { +public class PlayerInventory extends AbstractInventory implements InventoryClickHandler, EquipmentHandler, DataContainer { public static final int INVENTORY_SIZE = 46; + public static final int INNER_INVENTORY_SIZE = 36; protected final Player player; protected final ItemStack[] itemStacks = new ItemStack[INVENTORY_SIZE]; @@ -93,24 +94,13 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler return false; itemStack = addItemStackEvent.getItemStack(); - return InventoryModifier.super.addItemStack(itemStack, 0, getSize() - 10); - } - - @Override - public synchronized boolean addItemStack(@NotNull ItemStack itemStack, int startSlot, int endSlot) { - PlayerAddItemStackEvent addItemStackEvent = new PlayerAddItemStackEvent(player, itemStack); - player.callEvent(PlayerAddItemStackEvent.class, addItemStackEvent); - if (addItemStackEvent.isCancelled()) - return false; - - itemStack = addItemStackEvent.getItemStack(); - return InventoryModifier.super.addItemStack(itemStack, startSlot, endSlot); + return super.addItemStack(itemStack); } @Override public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { // Make the method synchronized - InventoryModifier.super.replaceItemStack(slot, operator); + super.replaceItemStack(slot, operator); } @Override @@ -130,6 +120,11 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler return INVENTORY_SIZE; } + @Override + public int getInnerSize() { + return INNER_INVENTORY_SIZE; + } + @NotNull @Override public ItemStack getItemInMainHand() { @@ -237,6 +232,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler * @throws IllegalArgumentException if the slot {@code slot} does not exist * @throws NullPointerException if {@code itemStack} is null */ + @Override protected synchronized void safeItemInsert(int slot, @NotNull ItemStack itemStack) { Check.argCondition(!MathUtils.isBetween(slot, 0, getSize()), "The slot " + slot + " does not exist for player"); diff --git a/src/main/java/net/minestom/server/inventory/condition/InventoryCondition.java b/src/main/java/net/minestom/server/inventory/condition/InventoryCondition.java index 5a5ace268..121adade1 100644 --- a/src/main/java/net/minestom/server/inventory/condition/InventoryCondition.java +++ b/src/main/java/net/minestom/server/inventory/condition/InventoryCondition.java @@ -1,11 +1,11 @@ package net.minestom.server.inventory.condition; import net.minestom.server.entity.Player; -import net.minestom.server.inventory.InventoryModifier; +import net.minestom.server.inventory.AbstractInventory; import net.minestom.server.inventory.click.ClickType; /** - * Can be added to any {@link InventoryModifier} + * Can be added to any {@link AbstractInventory} * using {@link net.minestom.server.inventory.Inventory#addInventoryCondition(InventoryCondition)} * or {@link net.minestom.server.inventory.PlayerInventory#addInventoryCondition(InventoryCondition)} * in order to listen to any issued clicks. diff --git a/src/main/java/net/minestom/server/item/meta/MapMeta.java b/src/main/java/net/minestom/server/item/meta/MapMeta.java new file mode 100644 index 000000000..e67d05e8e --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/MapMeta.java @@ -0,0 +1,278 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.MinecraftServer; +import net.minestom.server.chat.ChatColor; +import net.minestom.server.color.Color; +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import net.minestom.server.utils.clone.PublicCloneable; +import org.jetbrains.annotations.NotNull; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import org.jglrxavpok.hephaistos.nbt.NBTList; +import org.jglrxavpok.hephaistos.nbt.NBTTypes; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Supplier; + +public class MapMeta extends ItemMeta { + + private final int mapId; + private final int mapScaleDirection; + private final List decorations; + private final Color mapColor; + + protected MapMeta(ItemMetaBuilder metaBuilder, + int mapId, + int mapScaleDirection, + @NotNull List decorations, + @NotNull Color mapColor) { + super(metaBuilder); + this.mapId = mapId; + this.mapScaleDirection = mapScaleDirection; + this.decorations = decorations; + this.mapColor = mapColor; + } + + /** + * Gets the map id. + * + * @return the map id + */ + public int getMapId() { + return mapId; + } + + /** + * Gets the map scale direction. + * + * @return the map scale direction + */ + public int getMapScaleDirection() { + return mapScaleDirection; + } + + /** + * Gets the map decorations. + * + * @return a modifiable list containing all the map decorations + */ + public List getDecorations() { + return decorations; + } + + /** + * Gets the map color. + * + * @return the map color + * @deprecated Use {@link #getMapColor()} + */ + @Deprecated + public ChatColor getLegacyMapColor() { + return this.mapColor.asLegacyChatColor(); + } + + /** + * Gets the map color. + * + * @return the map color + */ + public @NotNull Color getMapColor() { + return this.mapColor; + } + + public static class Builder extends ItemMetaBuilder { + + private int mapId; + private int mapScaleDirection = 1; + private List decorations = new CopyOnWriteArrayList<>(); + private Color mapColor = new Color(0, 0, 0); + + public Builder mapId(int value) { + this.mapId = value; + return this; + } + + public Builder mapScaleDirection(int value) { + this.mapScaleDirection = value; + return this; + } + + public Builder decorations(List value) { + this.decorations = value; + return this; + } + + public Builder mapColor(Color value) { + this.mapColor = value; + return this; + } + + @Override + public @NotNull ItemMeta build() { + return new MapMeta(this, mapId, mapScaleDirection, decorations, mapColor); + } + + @Override + public void read(@NotNull NBTCompound compound) { + if (compound.containsKey("map")) { + this.mapId = compound.getAsInt("map"); + } + + if (compound.containsKey("map_scale_direction")) { + this.mapScaleDirection = compound.getAsInt("map_scale_direction"); + } + + if (compound.containsKey("Decorations")) { + final NBTList decorationsList = compound.getList("Decorations"); + for (NBTCompound decorationCompound : decorationsList) { + final String id = decorationCompound.getString("id"); + final byte type = decorationCompound.getAsByte("type"); + byte x = 0; + + if (decorationCompound.containsKey("x")) { + x = decorationCompound.getAsByte("x"); + } + + byte z = 0; + if (decorationCompound.containsKey("z")) { + z = decorationCompound.getAsByte("z"); + } + + double rotation = 0.0; + if (decorationCompound.containsKey("rot")) { + rotation = decorationCompound.getAsDouble("rot"); + } + + this.decorations.add(new MapDecoration(id, type, x, z, rotation)); + } + } + + if (compound.containsKey("display")) { + final NBTCompound displayCompound = compound.getCompound("display"); + if (displayCompound.containsKey("MapColor")) { + this.mapColor = new Color(displayCompound.getAsInt("MapColor")); + } + } + } + + @Override + public void write(@NotNull NBTCompound compound) { + compound.setInt("map", mapId); + + compound.setInt("map_scale_direction", mapScaleDirection); + + if (!decorations.isEmpty()) { + NBTList decorationsList = new NBTList<>(NBTTypes.TAG_Compound); + for (MapDecoration decoration : decorations) { + NBTCompound decorationCompound = new NBTCompound(); + decorationCompound.setString("id", decoration.getId()); + decorationCompound.setByte("type", decoration.getType()); + decorationCompound.setByte("x", decoration.getX()); + decorationCompound.setByte("z", decoration.getZ()); + decorationCompound.setDouble("rot", decoration.getRotation()); + + decorationsList.add(decorationCompound); + } + compound.set("Decorations", decorationsList); + } + + { + NBTCompound displayCompound; + if (compound.containsKey("display")) { + displayCompound = compound.getCompound("display"); + } else { + displayCompound = new NBTCompound(); + } + displayCompound.setInt("MapColor", mapColor.asRGB()); + } + } + + @Override + protected void deepClone(@NotNull ItemMetaBuilder metaBuilder) { + var mapBuilder = (MapMeta.Builder) metaBuilder; + mapBuilder.mapId = mapId; + mapBuilder.mapScaleDirection = mapScaleDirection; + mapBuilder.decorations = decorations; + mapBuilder.mapColor = mapColor; + } + + @Override + protected @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier() { + return Builder::new; + } + } + + public static class MapDecoration implements PublicCloneable { + private final String id; + private final byte type; + private final byte x, z; + private final double rotation; + + public MapDecoration(@NotNull String id, byte type, byte x, byte z, double rotation) { + this.id = id; + this.type = type; + this.x = x; + this.z = z; + this.rotation = rotation; + } + + /** + * Gets the arbitrary decoration id. + * + * @return the decoration id + */ + public String getId() { + return id; + } + + /** + * Gets the decoration type. + * + * @return the decoration type + * @see Map icons + */ + public byte getType() { + return type; + } + + /** + * Gets the X position of the decoration. + * + * @return the X position + */ + public byte getX() { + return x; + } + + /** + * Gets the Z position of the decoration. + * + * @return the Z position + */ + public byte getZ() { + return z; + } + + /** + * Gets the rotation of the symbol (0;360). + * + * @return the rotation of the symbol + */ + public double getRotation() { + return rotation; + } + + @NotNull + @Override + public MapDecoration clone() { + try { + return (MapDecoration) super.clone(); + } catch (CloneNotSupportedException e) { + MinecraftServer.getExceptionManager().handleException(e); + throw new IllegalStateException("Something weird happened"); + } + } + } + +} diff --git a/src/main/java/net/minestom/server/item/metadata/ItemMeta.java b/src/main/java/net/minestom/server/item/metadata/ItemMeta.java index 72effbebe..4e200e331 100644 --- a/src/main/java/net/minestom/server/item/metadata/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/ItemMeta.java @@ -1,6 +1,7 @@ package net.minestom.server.item.metadata; import net.minestom.server.MinecraftServer; +import net.minestom.server.item.ItemStack; import net.minestom.server.utils.clone.PublicCloneable; import org.jetbrains.annotations.NotNull; import org.jglrxavpok.hephaistos.nbt.NBTCompound; diff --git a/src/main/java/net/minestom/server/item/metadata/MapMeta.java b/src/main/java/net/minestom/server/item/metadata/MapMeta.java index f29e25e97..7fef87752 100644 --- a/src/main/java/net/minestom/server/item/metadata/MapMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/MapMeta.java @@ -1,10 +1,8 @@ package net.minestom.server.item.metadata; -import net.kyori.adventure.text.format.TextColor; import net.minestom.server.MinecraftServer; import net.minestom.server.chat.ChatColor; import net.minestom.server.color.Color; -import net.minestom.server.color.DyeColor; import net.minestom.server.utils.clone.CloneUtils; import net.minestom.server.utils.clone.PublicCloneable; import org.jetbrains.annotations.NotNull; From 51d290cae9a7c114d9fc55fe530b39aee347808d Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 4 Apr 2021 03:36:31 +0200 Subject: [PATCH 36/77] Share more data between PlayerInventory & Inventory Signed-off-by: TheMode --- .../server/inventory/AbstractInventory.java | 69 ++++++++++++-- .../minestom/server/inventory/Inventory.java | 92 +------------------ .../server/inventory/PlayerInventory.java | 67 ++------------ 3 files changed, 70 insertions(+), 158 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 88abcb383..f0d1c1b34 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -2,20 +2,43 @@ package net.minestom.server.inventory; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minestom.server.data.Data; +import net.minestom.server.data.DataContainer; +import net.minestom.server.inventory.click.InventoryClickProcessor; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; import net.minestom.server.item.StackingRule; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.UnaryOperator; /** * Represents an inventory where items can be modified/retrieved. */ -public abstract class AbstractInventory { +public abstract class AbstractInventory implements DataContainer { + + private final int size; + protected final ItemStack[] itemStacks; + + // list of conditions/callbacks assigned to this inventory + protected final List inventoryConditions = new CopyOnWriteArrayList<>(); + // the click processor which process all the clicks in the inventory + protected final InventoryClickProcessor clickProcessor = new InventoryClickProcessor(); + + private Data data; + + protected AbstractInventory(int size) { + this.size = size; + this.itemStacks = new ItemStack[getSize()]; + + Arrays.fill(itemStacks, ItemStack.AIR); + } /** * Sets an {@link ItemStack} at the specified slot and send relevant update to the viewer(s). @@ -35,7 +58,7 @@ public abstract class AbstractInventory { * @param itemStack the item to add * @return true if the item has been successfully fully added, false otherwise */ - public boolean addItemStack(@NotNull ItemStack itemStack) { + public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); final StackingRule stackingRule = itemStack.getStackingRule(); @@ -235,7 +258,7 @@ public abstract class AbstractInventory { return itemStacks.stream().allMatch(this::canTakeItemStack); } - public void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { + public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { var currentItem = getItemStack(slot); setItemStack(slot, operator.apply(currentItem)); } @@ -243,7 +266,14 @@ public abstract class AbstractInventory { /** * Clears the inventory and send relevant update to the viewer(s). */ - public abstract void clear(); + public synchronized void clear() { + // Clear the item array + Arrays.fill(itemStacks, ItemStack.AIR); + // Send the cleared inventory to viewers + update(); + } + + public abstract void update(); /** * Gets the {@link ItemStack} at the specified slot. @@ -252,7 +282,9 @@ public abstract class AbstractInventory { * @return the item in the slot {@code slot} */ @NotNull - public abstract ItemStack getItemStack(int slot); + public ItemStack getItemStack(int slot) { + return itemStacks[slot]; + } /** * Gets all the {@link ItemStack} in the inventory. @@ -263,14 +295,18 @@ public abstract class AbstractInventory { * @return an array containing all the inventory's items */ @NotNull - public abstract ItemStack[] getItemStacks(); + public ItemStack[] getItemStacks() { + return itemStacks.clone(); + } /** * Gets the size of the inventory. * * @return the inventory's size */ - public abstract int getSize(); + public int getSize() { + return size; + } /** * Gets the size of the "inner inventory" (which includes only "usable" slots). @@ -287,14 +323,18 @@ public abstract class AbstractInventory { * @return a modifiable {@link List} containing all the inventory conditions */ @NotNull - public abstract List getInventoryConditions(); + public List getInventoryConditions() { + return inventoryConditions; + } /** * Adds a new {@link InventoryCondition} to this inventory. * * @param inventoryCondition the inventory condition to add */ - public abstract void addInventoryCondition(@NotNull InventoryCondition inventoryCondition); + public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) { + this.inventoryConditions.add(inventoryCondition); + } /** * Places all the items of {@code itemStacks} into the internal array. @@ -313,4 +353,15 @@ public abstract class AbstractInventory { setItemStack(i, itemStack); } } + + @Nullable + @Override + public Data getData() { + return data; + } + + @Override + public void setData(@Nullable Data data) { + this.data = data; + } } diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index 0bb92d6e9..c66dae445 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -1,14 +1,10 @@ package net.minestom.server.inventory; import net.minestom.server.Viewable; -import net.minestom.server.data.Data; -import net.minestom.server.data.DataContainer; import net.minestom.server.entity.Player; import net.minestom.server.inventory.click.ClickType; import net.minestom.server.inventory.click.InventoryClickLoopHandler; -import net.minestom.server.inventory.click.InventoryClickProcessor; import net.minestom.server.inventory.click.InventoryClickResult; -import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.play.OpenWindowPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket; @@ -19,17 +15,12 @@ import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Collections; -import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.UnaryOperator; /** * Represents an inventory which can be viewed by a collection of {@link Player}. @@ -37,7 +28,7 @@ import java.util.function.UnaryOperator; * You can create one with {@link Inventory#Inventory(InventoryType, String)} or by making your own subclass. * It can then be opened using {@link Player#openInventory(Inventory)}. */ -public class Inventory extends AbstractInventory implements InventoryClickHandler, Viewable, DataContainer { +public class Inventory extends AbstractInventory implements InventoryClickHandler, Viewable { // incremented each time an inventory is created (used in the window packets) private static final AtomicInteger LAST_INVENTORY_ID = new AtomicInteger(); @@ -49,37 +40,21 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle // the title of this inventory) private String title; - // the size based on the inventory type - private final int size; - private final int offset; - // the items in this inventory - private final ItemStack[] itemStacks; // the players currently viewing this inventory private final Set viewers = new CopyOnWriteArraySet<>(); private final Set unmodifiableViewers = Collections.unmodifiableSet(viewers); // (player -> cursor item) map, used by the click listeners private final ConcurrentHashMap cursorPlayersItem = new ConcurrentHashMap<>(); - // list of conditions/callbacks assigned to this inventory - private final List inventoryConditions = new CopyOnWriteArrayList<>(); - // the click processor which process all the clicks in the inventory - private final InventoryClickProcessor clickProcessor = new InventoryClickProcessor(); - - private Data data; - public Inventory(@NotNull InventoryType inventoryType, @NotNull String title) { + super(inventoryType.getSize()); this.id = generateId(); this.inventoryType = inventoryType; this.title = title; - this.size = inventoryType.getSize(); - - this.offset = size; - - this.itemStacks = new ItemStack[size]; - Arrays.fill(itemStacks, ItemStack.AIR); + this.offset = getSize(); } private static byte generateId() { @@ -147,58 +122,10 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle safeItemInsert(slot, itemStack); } - @Override - public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { - // Make the method synchronized - return super.addItemStack(itemStack); - } - - @Override - public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { - // Make the method synchronized - super.replaceItemStack(slot, operator); - } - - @Override - public synchronized void clear() { - // Clear the item array - Arrays.fill(itemStacks, ItemStack.AIR); - // Send the cleared inventory to viewers - update(); - } - - - @NotNull - @Override - public ItemStack getItemStack(int slot) { - return itemStacks[slot]; - } - - @NotNull - @Override - public ItemStack[] getItemStacks() { - return itemStacks.clone(); - } - - @Override - public int getSize() { - return size; - } - - @NotNull - @Override - public List getInventoryConditions() { - return inventoryConditions; - } - - @Override - public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) { - this.inventoryConditions.add(inventoryCondition); - } - /** * Refreshes the inventory for all viewers. */ + @Override public void update() { sendPacketToViewers(createNewWindowItemsPacket()); } @@ -604,15 +531,4 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle update(player); } } - - @Nullable - @Override - public Data getData() { - return data; - } - - @Override - public void setData(@Nullable Data data) { - this.data = data; - } } diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 72ef75e96..7586d7a6e 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -1,14 +1,11 @@ package net.minestom.server.inventory; -import net.minestom.server.data.Data; -import net.minestom.server.data.DataContainer; import net.minestom.server.entity.Player; import net.minestom.server.event.item.ArmorEquipEvent; import net.minestom.server.event.player.PlayerAddItemStackEvent; import net.minestom.server.event.player.PlayerSetItemStackEvent; import net.minestom.server.inventory.click.ClickType; import net.minestom.server.inventory.click.InventoryClickLoopHandler; -import net.minestom.server.inventory.click.InventoryClickProcessor; import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; @@ -18,60 +15,34 @@ import net.minestom.server.network.packet.server.play.WindowItemsPacket; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.UnaryOperator; import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*; /** * Represents the inventory of a {@link Player}, retrieved with {@link Player#getInventory()}. */ -public class PlayerInventory extends AbstractInventory implements InventoryClickHandler, EquipmentHandler, DataContainer { +public class PlayerInventory extends AbstractInventory implements InventoryClickHandler, EquipmentHandler { public static final int INVENTORY_SIZE = 46; public static final int INNER_INVENTORY_SIZE = 36; protected final Player player; - protected final ItemStack[] itemStacks = new ItemStack[INVENTORY_SIZE]; private ItemStack cursorItem = ItemStack.AIR; - private final List inventoryConditions = new CopyOnWriteArrayList<>(); - private final InventoryClickProcessor clickProcessor = new InventoryClickProcessor(); - - private Data data; - public PlayerInventory(@NotNull Player player) { + super(INVENTORY_SIZE); this.player = player; - Arrays.fill(itemStacks, ItemStack.AIR); - } - - @Override - public @NotNull ItemStack getItemStack(int slot) { - return this.itemStacks[slot]; - } - - @Override - public @NotNull ItemStack[] getItemStacks() { - return itemStacks.clone(); - } - - @Override - public @NotNull List getInventoryConditions() { - return inventoryConditions; } @Override public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) { + // fix packet slot to inventory slot conversion InventoryCondition condition = (p, slot, clickType, inventoryConditionResult) -> { final int convertedSlot = convertPlayerInventorySlot(slot, OFFSET); inventoryCondition.accept(p, convertedSlot, clickType, inventoryConditionResult); }; - this.inventoryConditions.add(condition); + super.addInventoryCondition(condition); } @Override @@ -97,29 +68,13 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick return super.addItemStack(itemStack); } - @Override - public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { - // Make the method synchronized - super.replaceItemStack(slot, operator); - } - @Override public synchronized void clear() { - // Clear the item array - Arrays.fill(itemStacks, ItemStack.AIR); - - // Send the cleared inventory to the inventory's owner - update(); - + super.clear(); // Update equipments this.player.sendPacketToViewersAndSelf(player.getEquipmentsPacket()); } - @Override - public int getSize() { - return INVENTORY_SIZE; - } - @Override public int getInnerSize() { return INNER_INVENTORY_SIZE; @@ -195,6 +150,7 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick * Refreshes the player inventory by sending a {@link WindowItemsPacket} containing all. * the inventory items */ + @Override public void update() { player.getPlayerConnection().sendPacket(createWindowItemsPacket()); } @@ -499,15 +455,4 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick return !clickResult.isCancel(); } - - @Nullable - @Override - public Data getData() { - return data; - } - - @Override - public void setData(@Nullable Data data) { - this.data = data; - } } From 6218d2a78ed65d2bcad24ac1e98a2808026fc7d7 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 4 Apr 2021 03:37:57 +0200 Subject: [PATCH 37/77] All inventories should implement InventoryClickHandler Signed-off-by: TheMode --- .../java/net/minestom/server/inventory/AbstractInventory.java | 2 +- src/main/java/net/minestom/server/inventory/Inventory.java | 2 +- .../java/net/minestom/server/inventory/PlayerInventory.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index f0d1c1b34..26e0028a5 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -21,7 +21,7 @@ import java.util.function.UnaryOperator; /** * Represents an inventory where items can be modified/retrieved. */ -public abstract class AbstractInventory implements DataContainer { +public abstract class AbstractInventory implements InventoryClickHandler, DataContainer { private final int size; protected final ItemStack[] itemStacks; diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index c66dae445..77db21870 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -28,7 +28,7 @@ import java.util.concurrent.atomic.AtomicInteger; * You can create one with {@link Inventory#Inventory(InventoryType, String)} or by making your own subclass. * It can then be opened using {@link Player#openInventory(Inventory)}. */ -public class Inventory extends AbstractInventory implements InventoryClickHandler, Viewable { +public class Inventory extends AbstractInventory implements Viewable { // incremented each time an inventory is created (used in the window packets) private static final AtomicInteger LAST_INVENTORY_ID = new AtomicInteger(); diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 7586d7a6e..1cfc7aa37 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -21,7 +21,7 @@ import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*; /** * Represents the inventory of a {@link Player}, retrieved with {@link Player#getInventory()}. */ -public class PlayerInventory extends AbstractInventory implements InventoryClickHandler, EquipmentHandler { +public class PlayerInventory extends AbstractInventory implements EquipmentHandler { public static final int INVENTORY_SIZE = 46; public static final int INNER_INVENTORY_SIZE = 36; From 992f7feb7707aa1bd59a61d4261d25b929206df0 Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 14:19:51 +0200 Subject: [PATCH 38/77] Added ItemMetaBuilder#hideFlag with varargs --- .../java/net/minestom/server/item/ItemMetaBuilder.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index ed1a56f77..8e9e0daf5 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -42,6 +42,15 @@ public abstract class ItemMetaBuilder implements Cloneable { return this; } + @Contract("_ -> this") + public @NotNull ItemMetaBuilder hideFlag(@NotNull ItemHideFlag... hideFlags) { + int result = 0; + for (ItemHideFlag hideFlag : hideFlags) { + result |= hideFlag.getBitFieldPart(); + } + return hideFlag(result); + } + @Contract("_ -> this") public @NotNull ItemMetaBuilder displayName(@Nullable Component displayName) { this.displayName = displayName; From d6b6d41f4182de77ce7bbe148c66969c1ec439cb Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 15:33:53 +0200 Subject: [PATCH 39/77] Fix Inventory not using a Component as title --- .../server/data/type/InventoryData.java | 5 +++-- .../minestom/server/inventory/Inventory.java | 19 ++++++++++++++----- .../packet/server/play/OpenWindowPacket.java | 16 ++++++++-------- src/test/java/demo/PlayerInit.java | 6 ++++-- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/minestom/server/data/type/InventoryData.java b/src/main/java/net/minestom/server/data/type/InventoryData.java index f8df92439..c5a9a212c 100644 --- a/src/main/java/net/minestom/server/data/type/InventoryData.java +++ b/src/main/java/net/minestom/server/data/type/InventoryData.java @@ -1,5 +1,6 @@ package net.minestom.server.data.type; +import net.kyori.adventure.text.Component; import net.minestom.server.data.DataType; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; @@ -15,7 +16,7 @@ public class InventoryData extends DataType { final int size = inventoryType.getSize(); // Inventory title & type - writer.writeSizedString(value.getTitle()); + writer.writeComponent(value.getTitle()); writer.writeSizedString(inventoryType.name()); // Write all item stacks @@ -27,7 +28,7 @@ public class InventoryData extends DataType { @NotNull @Override public Inventory decode(@NotNull BinaryReader reader) { - final String title = reader.readSizedString(Integer.MAX_VALUE); + final Component title = reader.readComponent(Integer.MAX_VALUE); final InventoryType inventoryType = InventoryType.valueOf(reader.readSizedString(Integer.MAX_VALUE)); final int size = inventoryType.getSize(); diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index 77db21870..409eb38a4 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -1,5 +1,6 @@ package net.minestom.server.inventory; +import net.kyori.adventure.text.Component; import net.minestom.server.Viewable; import net.minestom.server.entity.Player; import net.minestom.server.inventory.click.ClickType; @@ -37,8 +38,8 @@ public class Inventory extends AbstractInventory implements Viewable { private final byte id; // the type of this inventory private final InventoryType inventoryType; - // the title of this inventory) - private String title; + // the title of this inventory + private Component title; private final int offset; @@ -48,7 +49,7 @@ public class Inventory extends AbstractInventory implements Viewable { // (player -> cursor item) map, used by the click listeners private final ConcurrentHashMap cursorPlayersItem = new ConcurrentHashMap<>(); - public Inventory(@NotNull InventoryType inventoryType, @NotNull String title) { + public Inventory(@NotNull InventoryType inventoryType, @NotNull Component title) { super(inventoryType.getSize()); this.id = generateId(); this.inventoryType = inventoryType; @@ -57,6 +58,14 @@ public class Inventory extends AbstractInventory implements Viewable { this.offset = getSize(); } + /** + * @deprecated use {@link Inventory#Inventory(InventoryType, Component)} + */ + @Deprecated + public Inventory(@NotNull InventoryType inventoryType, @NotNull String title) { + this(inventoryType, Component.text(title)); + } + private static byte generateId() { byte newInventoryId = (byte) LAST_INVENTORY_ID.incrementAndGet(); if (newInventoryId == Byte.MAX_VALUE) @@ -80,7 +89,7 @@ public class Inventory extends AbstractInventory implements Viewable { * @return the inventory title */ @NotNull - public String getTitle() { + public Component getTitle() { return title; } @@ -89,7 +98,7 @@ public class Inventory extends AbstractInventory implements Viewable { * * @param title the new inventory title */ - public void setTitle(@NotNull String title) { + public void setTitle(@NotNull Component title) { this.title = title; OpenWindowPacket packet = new OpenWindowPacket(title); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java index 94e361fa0..20c3eb619 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/OpenWindowPacket.java @@ -1,7 +1,6 @@ package net.minestom.server.network.packet.server.play; -import net.minestom.server.chat.ColoredText; -import net.minestom.server.chat.JsonMessage; +import net.kyori.adventure.text.Component; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.binary.BinaryReader; @@ -12,26 +11,27 @@ public class OpenWindowPacket implements ServerPacket { public int windowId; public int windowType; - public JsonMessage title = ColoredText.of(""); + public Component title = Component.text(""); - public OpenWindowPacket() {} + public OpenWindowPacket() { + } - public OpenWindowPacket(String title) { - this.title = ColoredText.of(title); + public OpenWindowPacket(Component title) { + this.title = title; } @Override public void write(@NotNull BinaryWriter writer) { writer.writeVarInt(windowId); writer.writeVarInt(windowType); - writer.writeJsonMessage(title); + writer.writeComponent(title); } @Override public void read(@NotNull BinaryReader reader) { windowId = reader.readVarInt(); windowType = reader.readVarInt(); - title = reader.readJsonMessage(Integer.MAX_VALUE); + title = reader.readComponent(Integer.MAX_VALUE); } @Override diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index b98f79bd1..73c9f5efc 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -57,13 +57,13 @@ public class PlayerInit { instanceContainer.enableAutoChunkLoad(true); instanceContainer.setChunkGenerator(chunkGeneratorDemo); - inventory = new Inventory(InventoryType.CHEST_1_ROW, "Test inventory"); + inventory = new Inventory(InventoryType.CHEST_1_ROW, Component.text("Test inventory")); /*inventory.addInventoryCondition((p, slot, clickType, inventoryConditionResult) -> { p.sendMessage("click type inventory: " + clickType); System.out.println("slot inv: " + slot)0; inventoryConditionResult.setCancel(slot == 3); });*/ - //inventory.setItemStack(3, new ItemStack(Material.DIAMOND, (byte) 34)); + inventory.setItemStack(3, ItemStack.of(Material.DIAMOND, 34)); { CompassMeta compassMeta = new CompassMeta.Builder() @@ -245,6 +245,8 @@ public class PlayerInit { //inventory.setChestplate(item); } + player.openInventory(PlayerInit.inventory); + //player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 32)); }); From ea58d0f693d0b06d97b720f701ce9abfe9bea4bd Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 15:41:05 +0200 Subject: [PATCH 40/77] Fix StackingRule not being used inside to retrieve item count --- .../server/inventory/AbstractInventory.java | 4 ++-- .../inventory/click/InventoryClickProcessor.java | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 26e0028a5..e335385a9 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -132,7 +132,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo */ public boolean canAddItemStack(@NotNull ItemStack itemStack) { final StackingRule stackingRule = itemStack.getStackingRule(); - int amountLeft = itemStack.getAmount(); + int amountLeft = stackingRule.getAmount(itemStack); for (int i = 0; i < getInnerSize(); i++) { ItemStack inventoryItem = getItemStack(i); if (stackingRule.canBeStacked(itemStack, inventoryItem)) { @@ -189,7 +189,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo } itemChangesMap.put(i, ItemStack.AIR); itemStack = itemStack.withAmount(amount -> amount - itemAmount); - if (itemStack.getAmount() == 0) { + if (stackingRule.getAmount(itemStack) == 0) { itemStack = ItemStack.AIR; break; } diff --git a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java index 1cdd837ed..1ee45f568 100644 --- a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java +++ b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java @@ -91,7 +91,7 @@ public class InventoryClickProcessor { ItemStack resultClicked; if (clickedRule.canBeStacked(clicked, cursor)) { - final int amount = clicked.getAmount() + 1; + final int amount = clickedRule.getAmount(clicked) + 1; if (!clickedRule.canApply(clicked, amount)) { return clickResult; } else { @@ -100,12 +100,12 @@ public class InventoryClickProcessor { } } else { if (cursor.isAir()) { - final int amount = (int) Math.ceil((double) clicked.getAmount() / 2d); + final int amount = (int) Math.ceil((double) clickedRule.getAmount(clicked) / 2d); resultCursor = cursorRule.apply(clicked, amount); - resultClicked = clickedRule.apply(clicked, clicked.getAmount() / 2); + resultClicked = clickedRule.apply(clicked, clickedRule.getAmount(clicked) / 2); } else { if (clicked.isAir()) { - final int amount = cursor.getAmount(); + final int amount = cursorRule.getAmount(cursor); resultCursor = cursorRule.apply(cursor, amount - 1); resultClicked = clickedRule.apply(cursor, 1); } else { @@ -287,10 +287,11 @@ public class InventoryClickProcessor { clickResult = startCondition(inventory, player, s, ClickType.DRAGGING, slotItem, cursor); if (clickResult.isCancel()) break; + StackingRule slotItemRule = slotItem.getStackingRule(); final int maxSize = stackingRule.getMaxSize(); if (stackingRule.canBeStacked(draggedItem, slotItem)) { - final int amount = slotItem.getAmount() + slotSize; + final int amount = slotItemRule.getAmount(slotItem) + slotSize; if (stackingRule.canApply(slotItem, amount)) { slotItem = stackingRule.apply(slotItem, amount); finalCursorAmount -= slotSize; @@ -328,8 +329,9 @@ public class InventoryClickProcessor { if (clickResult.isCancel()) break; + StackingRule slotItemRule = slotItem.getStackingRule(); if (stackingRule.canBeStacked(draggedItem, slotItem)) { - final int amount = slotItem.getAmount() + 1; + final int amount = slotItemRule.getAmount(slotItem) + 1; if (stackingRule.canApply(slotItem, amount)) { slotItem = stackingRule.apply(slotItem, amount); itemSetter.accept(s, slotItem); From 68de2b19805305f3657e11c80abf31b8c1c4acc7 Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 15:44:09 +0200 Subject: [PATCH 41/77] Cleanup --- .../server/inventory/click/InventoryClickProcessor.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java index 1ee45f568..afc1881ad 100644 --- a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java +++ b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java @@ -281,7 +281,6 @@ public class InventoryClickProcessor { int finalCursorAmount = cursorAmount; for (int s : slots) { - final ItemStack draggedItem = cursor; ItemStack slotItem = itemGetter.apply(s); clickResult = startCondition(inventory, player, s, ClickType.DRAGGING, slotItem, cursor); @@ -290,7 +289,7 @@ public class InventoryClickProcessor { StackingRule slotItemRule = slotItem.getStackingRule(); final int maxSize = stackingRule.getMaxSize(); - if (stackingRule.canBeStacked(draggedItem, slotItem)) { + if (stackingRule.canBeStacked(cursor, slotItem)) { final int amount = slotItemRule.getAmount(slotItem) + slotSize; if (stackingRule.canApply(slotItem, amount)) { slotItem = stackingRule.apply(slotItem, amount); @@ -301,7 +300,7 @@ public class InventoryClickProcessor { finalCursorAmount -= removedAmount; } } else if (slotItem.isAir()) { - slotItem = stackingRule.apply(draggedItem, slotSize); + slotItem = stackingRule.apply(cursor, slotSize); finalCursorAmount -= slotSize; } itemSetter.accept(s, slotItem); From 005d70e3a6e3a57a42d4687c0701b2d7f712042b Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 17:54:05 +0200 Subject: [PATCH 42/77] Annotation + ItemStoreBuilder should be more like a builder --- src/main/java/net/minestom/server/item/ItemStack.java | 4 ++-- src/main/java/net/minestom/server/item/ItemStoreBuilder.java | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index f3936dea8..f236f019e 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -106,8 +106,8 @@ public class ItemStack { } @Contract(value = "_ -> new", pure = true) - public @NotNull ItemStack withStore(@NotNull Consumer<@NotNull ItemStoreBuilder> metaOperator) { - return builder().store(metaOperator).build(); + public @NotNull ItemStack withStore(@NotNull Consumer<@NotNull ItemStoreBuilder> storeConsumer) { + return builder().store(storeConsumer).build(); } @Contract(pure = true) diff --git a/src/main/java/net/minestom/server/item/ItemStoreBuilder.java b/src/main/java/net/minestom/server/item/ItemStoreBuilder.java index 6f516be2b..e1c430e7f 100644 --- a/src/main/java/net/minestom/server/item/ItemStoreBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemStoreBuilder.java @@ -20,8 +20,10 @@ public class ItemStoreBuilder { this(new ConcurrentHashMap<>()); } - public void set(@NotNull String key, T value, MergingRule mergingRule) { + @Contract(value = "_, _, _ -> this") + public @NotNull ItemStoreBuilder set(@NotNull String key, T value, MergingRule mergingRule) { this.entryMap.put(key, new Entry<>(value, mergingRule)); + return this; } @Contract(value = "-> new", pure = true) From 88c2e826045556956d79339a2de44eb8c3b2d18d Mon Sep 17 00:00:00 2001 From: Konstantin Shandurenko Date: Sun, 4 Apr 2021 19:15:34 +0300 Subject: [PATCH 43/77] AbstractInventory: more StackingRule#apply usages instead of ItemStack#withAmount --- .../minestom/server/inventory/AbstractInventory.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index e335385a9..9ec49f577 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -79,7 +79,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); } else { // Slot can accept the whole item - itemChangesMap.put(i, inventoryItem.withAmount(totalAmount)); + itemChangesMap.put(i, stackingRule.apply(inventoryItem, totalAmount)); itemStack = ItemStack.AIR; break; } @@ -172,7 +172,6 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo */ public boolean takeItemStack(@NotNull ItemStack itemStack) { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); - final StackingRule stackingRule = itemStack.getStackingRule(); for (int i = 0; i < getInnerSize(); i++) { ItemStack inventoryItem = getItemStack(i); @@ -188,7 +187,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo break; } itemChangesMap.put(i, ItemStack.AIR); - itemStack = itemStack.withAmount(amount -> amount - itemAmount); + itemStack = stackingRule.apply(itemStack, itemStackAmount - itemAmount); if (stackingRule.getAmount(itemStack) == 0) { itemStack = ItemStack.AIR; break; @@ -231,6 +230,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo */ public boolean canTakeItemStack(@NotNull ItemStack itemStack) { final StackingRule stackingRule = itemStack.getStackingRule(); + int amountLeft = stackingRule.getAmount(itemStack); for (int i = 0; i < getInnerSize(); i++) { ItemStack inventoryItem = getItemStack(i); if (inventoryItem.isAir()) { @@ -238,11 +238,10 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo } if (stackingRule.canBeStacked(itemStack, inventoryItem)) { final int itemAmount = stackingRule.getAmount(inventoryItem); - final int itemStackAmount = stackingRule.getAmount(itemStack); - if (itemStackAmount <= itemAmount) { + if (amountLeft <= itemAmount) { return true; } - itemStack = itemStack.withAmount(amount -> amount - itemAmount); + amountLeft -= itemAmount; } } return false; From d1d973018e5c0b933540c4b6dcab148b946629a1 Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 20:49:21 +0200 Subject: [PATCH 44/77] Lore is non-null --- .../java/net/minestom/server/inventory/AbstractInventory.java | 3 +-- src/main/java/net/minestom/server/item/ItemStack.java | 4 ++-- src/main/java/net/minestom/server/item/ItemStackBuilder.java | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 9ec49f577..149b13a94 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -353,9 +353,8 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo } } - @Nullable @Override - public Data getData() { + public @Nullable Data getData() { return data; } diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index f236f019e..72a19d244 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -131,12 +131,12 @@ public class ItemStack { } @Contract(value = "_, -> new", pure = true) - public @NotNull ItemStack withLore(@Nullable List<@NotNull Component> lore) { + public @NotNull ItemStack withLore(@NotNull List<@NotNull Component> lore) { return builder().lore(lore).build(); } @Contract(value = "_, -> new", pure = true) - public @NotNull ItemStack withLore(@NotNull UnaryOperator<@Nullable List<@NotNull Component>> loreUnaryOperator) { + public @NotNull ItemStack withLore(@NotNull UnaryOperator<@NotNull List<@NotNull Component>> loreUnaryOperator) { return withLore(loreUnaryOperator.apply(getLore())); } diff --git a/src/main/java/net/minestom/server/item/ItemStackBuilder.java b/src/main/java/net/minestom/server/item/ItemStackBuilder.java index ed8ec655d..f85a4581d 100644 --- a/src/main/java/net/minestom/server/item/ItemStackBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemStackBuilder.java @@ -60,7 +60,7 @@ public class ItemStackBuilder { } @Contract(value = "_ -> this") - public @NotNull ItemStackBuilder lore(List<@NotNull Component> lore) { + public @NotNull ItemStackBuilder lore(@NotNull List<@NotNull Component> lore) { this.metaBuilder.lore(lore); return this; } From d34d3a2b501a754e31928b957b4c3c5f1c02a293 Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 20:50:06 +0200 Subject: [PATCH 45/77] Add comment about ItemMetaBuilder#clone --- src/main/java/net/minestom/server/item/ItemMetaBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 8e9e0daf5..49516ab37 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -144,6 +144,7 @@ public abstract class ItemMetaBuilder implements Cloneable { deepClone(builder); return builder; } catch (CloneNotSupportedException e) { + // Should never happen, because ItemMetaBuilder implements Cloneable e.printStackTrace(); throw new UnsupportedOperationException("Weird thing happened"); } From 5a5531723ccaa213d25b24001952ccfd382655ed Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 21:34:48 +0200 Subject: [PATCH 46/77] Fix original nbt overwriting modified meta --- .../java/net/minestom/server/item/ItemMeta.java | 13 +++---------- .../minestom/server/item/metadata/CrossbowMeta.java | 2 +- .../java/net/minestom/server/utils/NBTUtils.java | 12 +++++++----- src/test/java/demo/PlayerInit.java | 13 +++++++------ 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index dc116fc93..1755d6f42 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -9,10 +9,7 @@ import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.lang.ref.SoftReference; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Consumer; public class ItemMeta { @@ -110,14 +107,10 @@ public class ItemMeta { } public @NotNull NBTCompound toNBT() { - if (originalNbt != null) { - // Return the nbt this meta has been created with - return originalNbt; - } - var nbt = cache != null ? cache.get() : null; if (nbt == null) { - nbt = NBTUtils.metaToNBT(this); + nbt = Objects.requireNonNullElseGet(originalNbt, NBTCompound::new); + NBTUtils.writeMetaNBT(this, nbt); this.builder.write(nbt); this.cache = new SoftReference<>(nbt); } diff --git a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java index aa65c49d1..0d64585c6 100644 --- a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java @@ -193,7 +193,7 @@ public class CrossbowMeta extends ItemMeta { @NotNull private NBTCompound getItemCompound(@NotNull ItemStack itemStack) { - NBTCompound compound = NBTUtils.metaToNBT(itemStack.getMeta()); + NBTCompound compound = NBTUtils.getMetaNBT(itemStack.getMeta()); compound.setByte("Count", (byte) itemStack.getAmount()); compound.setString("id", itemStack.getMaterial().getName()); return compound; diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java index ac86eab65..23048a591 100644 --- a/src/main/java/net/minestom/server/utils/NBTUtils.java +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -86,7 +86,7 @@ public final class NBTUtils { final ItemStack stack = inventory.getItemStack(i); NBTCompound nbt = new NBTCompound(); - NBTCompound tag = metaToNBT(stack.getMeta()); + NBTCompound tag = getMetaNBT(stack.getMeta()); nbt.set("tag", tag); nbt.setByte("Slot", (byte) i); @@ -290,9 +290,7 @@ public final class NBTUtils { } } - public static @NotNull NBTCompound metaToNBT(@NotNull ItemMeta itemMeta) { - final NBTCompound itemNBT = new NBTCompound(); - + public static void writeMetaNBT(@NotNull ItemMeta itemMeta, @NotNull NBTCompound itemNBT) { // Unbreakable if (itemMeta.isUnbreakable()) { itemNBT.setInt("Unbreakable", 1); @@ -381,8 +379,12 @@ public final class NBTUtils { } } // End custom model data + } - return itemNBT; + public static @NotNull NBTCompound getMetaNBT(@NotNull ItemMeta itemMeta) { + var nbt = new NBTCompound(); + writeMetaNBT(itemMeta, nbt); + return nbt; } @FunctionalInterface diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 73c9f5efc..f066d5072 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -27,7 +27,6 @@ import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; -import net.minestom.server.item.ItemStore; import net.minestom.server.item.ItemTag; import net.minestom.server.item.Material; import net.minestom.server.item.meta.CompassMeta; @@ -38,6 +37,7 @@ import net.minestom.server.utils.Vector; import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.world.DimensionType; +import java.util.ArrayList; import java.util.Collection; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -241,13 +241,14 @@ public class PlayerInit { { ItemStack item = ItemStack.builder(Material.DIAMOND_CHESTPLATE) .displayName(Component.text("test")) + .lore(Component.text("lore")) .build(); - //inventory.setChestplate(item); + inventory.setChestplate(item.withLore(components -> { + var list = new ArrayList<>(components); + list.add(Component.text("hey")); + return list; + })); } - - player.openInventory(PlayerInit.inventory); - - //player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 32)); }); globalEventHandler.addEventCallback(PlayerBlockBreakEvent.class, event -> { From 81f2127a9dc801ab7ba522ed98027cf6633a3e7c Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 21:48:11 +0200 Subject: [PATCH 47/77] Annotation style --- .../server/inventory/AbstractInventory.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 149b13a94..10d167eab 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -114,7 +114,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param itemStacks items to add * @return list of itemstacks that could not be successfully fully added, empty list otherwise */ - public List addItemStacks(@NotNull List itemStacks) { + public @NotNull List addItemStacks(@NotNull List itemStacks) { List result = new ArrayList<>(); itemStacks.forEach(itemStack -> { if (!addItemStack(itemStack)) { @@ -212,7 +212,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param itemStacks items to take * @return list of itemstacks that could not be successfully fully taken, empty list otherwise */ - public List takeItemStacks(@NotNull List itemStacks) { + public @NotNull List takeItemStacks(@NotNull List itemStacks) { List result = new ArrayList<>(); itemStacks.forEach(itemStack -> { if (!takeItemStack(itemStack)) { @@ -280,8 +280,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param slot the slot to check * @return the item in the slot {@code slot} */ - @NotNull - public ItemStack getItemStack(int slot) { + public @NotNull ItemStack getItemStack(int slot) { return itemStacks[slot]; } @@ -293,8 +292,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * * @return an array containing all the inventory's items */ - @NotNull - public ItemStack[] getItemStacks() { + public @NotNull ItemStack[] getItemStacks() { return itemStacks.clone(); } @@ -321,8 +319,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * * @return a modifiable {@link List} containing all the inventory conditions */ - @NotNull - public List getInventoryConditions() { + public @NotNull List getInventoryConditions() { return inventoryConditions; } From 15c0e64703fd791ad56f706d673707447fc549a4 Mon Sep 17 00:00:00 2001 From: themode Date: Sun, 4 Apr 2021 22:53:08 +0200 Subject: [PATCH 48/77] Fix AbstractInventory#addItemStack comment --- .../net/minestom/server/inventory/AbstractInventory.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 10d167eab..7885be34c 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -53,10 +53,10 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo /** * Adds an {@link ItemStack} to the inventory and sends relevant update to the viewer(s). *

- * Even the item cannot be fully added, the amount of {@code itemStack} will be updated. + * Does nothing if the item cannot be fully added. * * @param itemStack the item to add - * @return true if the item has been successfully fully added, false otherwise + * @return true if the item has been successfully added, false otherwise */ public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); @@ -109,10 +109,10 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo /** * Adds {@link ItemStack}s to the inventory and sends relevant updates to the viewer(s). *

- * Even items cannot be fully added, the amount of {@code itemStack}s will be updated. + * Does nothing if the item cannot be fully added. * * @param itemStacks items to add - * @return list of itemstacks that could not be successfully fully added, empty list otherwise + * @return list of items that could not be successfully added, empty list otherwise */ public @NotNull List addItemStacks(@NotNull List itemStacks) { List result = new ArrayList<>(); From e4a26df2b6445a0b0051362fa7179c0e16d8a90d Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 9 Apr 2021 23:16:57 +0200 Subject: [PATCH 49/77] Rename ItemMeta#nbt, remove unnecessary cache --- .../minestom/server/chat/ChatHoverEvent.java | 2 +- .../net/minestom/server/item/ItemMeta.java | 53 +++++++++---------- .../minestom/server/item/ItemMetaBuilder.java | 11 ++-- .../server/item/meta/CompassMeta.java | 8 --- .../minestom/server/item/meta/MapMeta.java | 9 ---- .../net/minestom/server/utils/NBTUtils.java | 2 +- .../server/world/biomes/BiomeParticles.java | 2 +- src/test/java/demo/PlayerInit.java | 9 ++-- 8 files changed, 35 insertions(+), 61 deletions(-) diff --git a/src/main/java/net/minestom/server/chat/ChatHoverEvent.java b/src/main/java/net/minestom/server/chat/ChatHoverEvent.java index 162447c38..a1e4dbd00 100644 --- a/src/main/java/net/minestom/server/chat/ChatHoverEvent.java +++ b/src/main/java/net/minestom/server/chat/ChatHoverEvent.java @@ -93,7 +93,7 @@ public class ChatHoverEvent { JsonObject obj = GsonComponentSerializer.gson().serializer().toJsonTree(Component.empty().hoverEvent(event)).getAsJsonObject(); obj = obj.get("hoverEvent").getAsJsonObject().get("contents").getAsJsonObject(); - NBTCompound compound = itemStack.getMeta().toNBT(); + NBTCompound compound = itemStack.getMeta().nbt(); obj.add("tag", new JsonPrimitive(compound.toSNBT())); return new ChatHoverEvent("show_item", obj); diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 1755d6f42..f155a1135 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -8,14 +8,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import java.lang.ref.SoftReference; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; public class ItemMeta { - private final ItemMetaBuilder builder; - private final int damage; private final boolean unbreakable; private final int hideFlag; @@ -27,22 +27,26 @@ public class ItemMeta { private final int customModelData; - private final @Nullable NBTCompound originalNbt; - private SoftReference cache; + private final NBTCompound nbt; + private final ItemMetaBuilder emptyBuilder; protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { - this.builder = metaBuilder.clone(); - this.damage = 0; - this.unbreakable = false; - this.hideFlag = 0; + this.damage = metaBuilder.damage; + this.unbreakable = metaBuilder.unbreakable; + this.hideFlag = metaBuilder.hideFlag; this.displayName = metaBuilder.displayName; this.lore = Collections.unmodifiableList(metaBuilder.lore); this.enchantmentMap = Collections.unmodifiableMap(metaBuilder.enchantmentMap); - this.attributes = new ArrayList<>(); - this.customModelData = 0; + this.attributes = Collections.unmodifiableList(metaBuilder.attributes); + this.customModelData = metaBuilder.customModelData; - // Can be null - this.originalNbt = metaBuilder.originalNBT; + // nbt + { + this.nbt = Objects.requireNonNullElseGet(metaBuilder.originalNBT, NBTCompound::new); + NBTUtils.writeMetaNBT(this, nbt); + + this.emptyBuilder = metaBuilder.getSupplier().get(); + } } @Contract(value = "_, -> new", pure = true) @@ -93,28 +97,19 @@ public class ItemMeta { } public T getOrDefault(@NotNull ItemTag tag, @Nullable T defaultValue) { - var nbt = toNBT(); var key = tag.getKey(); if (nbt.containsKey(key)) { - return tag.read(toNBT()); + return tag.read(nbt); } else { return defaultValue; } } public @Nullable T get(@NotNull ItemTag tag) { - return tag.read(toNBT()); + return tag.read(nbt); } - public @NotNull NBTCompound toNBT() { - var nbt = cache != null ? cache.get() : null; - if (nbt == null) { - nbt = Objects.requireNonNullElseGet(originalNbt, NBTCompound::new); - NBTUtils.writeMetaNBT(this, nbt); - this.builder.write(nbt); - this.cache = new SoftReference<>(nbt); - } - + public @NotNull NBTCompound nbt() { return nbt; } @@ -124,16 +119,16 @@ public class ItemMeta { if (o == null || getClass() != o.getClass()) return false; ItemMeta itemMeta = (ItemMeta) o; - return toNBT().equals(itemMeta.toNBT()); + return nbt.equals(itemMeta.nbt()); } @Override public int hashCode() { - return toNBT().hashCode(); + return nbt.hashCode(); } @Contract(value = "-> new", pure = true) protected @NotNull ItemMetaBuilder builder() { - return ItemMetaBuilder.fromNBT(builder, toNBT()); + return ItemMetaBuilder.fromNBT(emptyBuilder, nbt); } } diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 49516ab37..487a03b4c 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -110,7 +110,7 @@ public abstract class ItemMetaBuilder implements Cloneable { return this; } else { // Create item meta based on nbt - var currentNbt = build().toNBT(); + var currentNbt = build().nbt(); return fromNBT(this, currentNbt).set(tag, value); } } @@ -122,8 +122,6 @@ public abstract class ItemMetaBuilder implements Cloneable { public abstract void write(@NotNull NBTCompound nbtCompound); - protected abstract void deepClone(@NotNull ItemMetaBuilder metaBuilder); - protected abstract @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier(); @Contract(value = "_, _ -> new", pure = true) @@ -137,11 +135,10 @@ public abstract class ItemMetaBuilder implements Cloneable { @Override protected ItemMetaBuilder clone() { try { + NBTCompound nbtCompound = new NBTCompound(); + write(nbtCompound); var builder = (ItemMetaBuilder) super.clone(); - builder.displayName = displayName; - builder.lore = new ArrayList<>(lore); - builder.enchantmentMap = new HashMap<>(enchantmentMap); - deepClone(builder); + builder.read(nbtCompound); return builder; } catch (CloneNotSupportedException e) { // Should never happen, because ItemMetaBuilder implements Cloneable diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/meta/CompassMeta.java index 0007e2475..856f9df30 100644 --- a/src/main/java/net/minestom/server/item/meta/CompassMeta.java +++ b/src/main/java/net/minestom/server/item/meta/CompassMeta.java @@ -97,14 +97,6 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider getSupplier() { return Builder::new; diff --git a/src/main/java/net/minestom/server/item/meta/MapMeta.java b/src/main/java/net/minestom/server/item/meta/MapMeta.java index e67d05e8e..73651fa4d 100644 --- a/src/main/java/net/minestom/server/item/meta/MapMeta.java +++ b/src/main/java/net/minestom/server/item/meta/MapMeta.java @@ -188,15 +188,6 @@ public class MapMeta extends ItemMeta { } } - @Override - protected void deepClone(@NotNull ItemMetaBuilder metaBuilder) { - var mapBuilder = (MapMeta.Builder) metaBuilder; - mapBuilder.mapId = mapId; - mapBuilder.mapScaleDirection = mapScaleDirection; - mapBuilder.decorations = decorations; - mapBuilder.mapColor = mapColor; - } - @Override protected @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier() { return Builder::new; diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java index 23048a591..22b851dc8 100644 --- a/src/main/java/net/minestom/server/utils/NBTUtils.java +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -286,7 +286,7 @@ public final class NBTUtils { packet.writeVarInt(itemStack.getMaterial().getId()); packet.writeByte((byte) itemStack.getAmount()); - packet.writeNBT("", itemStack.getMeta().toNBT()); + packet.writeNBT("", itemStack.getMeta().nbt()); } } diff --git a/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java b/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java index 721e89790..5ab2ec118 100644 --- a/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java +++ b/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java @@ -100,7 +100,7 @@ public class BiomeParticles { @Override public NBTCompound toNbt() { //todo test count might be wrong type - NBTCompound nbtCompound = item.getMeta().toNBT(); + NBTCompound nbtCompound = item.getMeta().nbt(); nbtCompound.setString("type", type); return nbtCompound; } diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index f066d5072..bee771b8e 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -37,8 +37,8 @@ import net.minestom.server.utils.Vector; import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.world.DimensionType; -import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -243,10 +243,9 @@ public class PlayerInit { .displayName(Component.text("test")) .lore(Component.text("lore")) .build(); - inventory.setChestplate(item.withLore(components -> { - var list = new ArrayList<>(components); - list.add(Component.text("hey")); - return list; + inventory.setChestplate(item.with(itemStackBuilder -> { + itemStackBuilder.lore(Collections.emptyList()) + .displayName(null); })); } }); From 4f5fd125c43def1dc03dbf9153a7a3160d93d36b Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 9 Apr 2021 23:23:33 +0200 Subject: [PATCH 50/77] ItemMetaBuilder doesnt need to be cloneable --- .../minestom/server/item/ItemMetaBuilder.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 487a03b4c..84e7ac464 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -11,7 +11,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.*; import java.util.function.Supplier; -public abstract class ItemMetaBuilder implements Cloneable { +public abstract class ItemMetaBuilder { protected int damage; protected boolean unbreakable; @@ -132,21 +132,6 @@ public abstract class ItemMetaBuilder implements Cloneable { return dest; } - @Override - protected ItemMetaBuilder clone() { - try { - NBTCompound nbtCompound = new NBTCompound(); - write(nbtCompound); - var builder = (ItemMetaBuilder) super.clone(); - builder.read(nbtCompound); - return builder; - } catch (CloneNotSupportedException e) { - // Should never happen, because ItemMetaBuilder implements Cloneable - e.printStackTrace(); - throw new UnsupportedOperationException("Weird thing happened"); - } - } - public interface Provider { } From d6e7c9a6353c0a17592e0311b920c34547243ae6 Mon Sep 17 00:00:00 2001 From: TheMode Date: Fri, 9 Apr 2021 23:57:05 +0200 Subject: [PATCH 51/77] Handle nbt directly inside builders instead of lazily --- .../net/minestom/server/item/ItemMeta.java | 11 +- .../minestom/server/item/ItemMetaBuilder.java | 109 +++++++++++++++--- .../server/item/meta/CompassMeta.java | 35 +++--- .../minestom/server/item/meta/MapMeta.java | 62 +++++----- .../server/item/metadata/CrossbowMeta.java | 2 +- .../net/minestom/server/utils/NBTUtils.java | 105 +---------------- src/test/java/demo/PlayerInit.java | 6 +- 7 files changed, 150 insertions(+), 180 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index f155a1135..7c9439fc6 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -2,7 +2,6 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; import net.minestom.server.item.attribute.ItemAttribute; -import net.minestom.server.utils.NBTUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,7 +10,6 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.function.Consumer; public class ItemMeta { @@ -40,13 +38,8 @@ public class ItemMeta { this.attributes = Collections.unmodifiableList(metaBuilder.attributes); this.customModelData = metaBuilder.customModelData; - // nbt - { - this.nbt = Objects.requireNonNullElseGet(metaBuilder.originalNBT, NBTCompound::new); - NBTUtils.writeMetaNBT(this, nbt); - - this.emptyBuilder = metaBuilder.getSupplier().get(); - } + this.nbt = metaBuilder.nbt; + this.emptyBuilder = metaBuilder.getSupplier().get(); } @Contract(value = "_, -> new", pure = true) diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 84e7ac464..fd631d702 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -1,18 +1,24 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.minestom.server.adventure.AdventureSerializer; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.utils.NBTUtils; +import net.minestom.server.utils.Utils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import org.jglrxavpok.hephaistos.nbt.*; import java.util.*; +import java.util.function.Consumer; import java.util.function.Supplier; public abstract class ItemMetaBuilder { + protected NBTCompound nbt = new NBTCompound(); + protected int damage; protected boolean unbreakable; protected int hideFlag; @@ -22,23 +28,24 @@ public abstract class ItemMetaBuilder { protected List attributes = new ArrayList<>(); protected int customModelData; - protected NBTCompound originalNBT; - @Contract("_ -> this") public @NotNull ItemMetaBuilder damage(int damage) { this.damage = damage; + this.nbt.setInt("Damage", damage); return this; } @Contract("_ -> this") public @NotNull ItemMetaBuilder unbreakable(boolean unbreakable) { this.unbreakable = unbreakable; + this.nbt.setByte("Unbreakable", (byte) (unbreakable ? 1 : 0)); return this; } @Contract("_ -> this") public @NotNull ItemMetaBuilder hideFlag(int hideFlag) { this.hideFlag = hideFlag; + this.nbt.setInt("HideFlags", hideFlag); return this; } @@ -54,12 +61,31 @@ public abstract class ItemMetaBuilder { @Contract("_ -> this") public @NotNull ItemMetaBuilder displayName(@Nullable Component displayName) { this.displayName = displayName; + + handleCompound("display", nbtCompound -> { + if (displayName != null) { + final String name = AdventureSerializer.serialize(displayName); + nbtCompound.setString("Name", name); + } else { + nbtCompound.removeTag("Name"); + } + }); + return this; } @Contract("_ -> this") public @NotNull ItemMetaBuilder lore(@NotNull List<@NotNull Component> lore) { this.lore = lore; + + handleCompound("display", nbtCompound -> { + final NBTList loreNBT = new NBTList<>(NBTTypes.TAG_String); + for (Component line : lore) { + loreNBT.add(new NBTString(GsonComponentSerializer.gson().serialize(line))); + } + nbtCompound.set("Lore", loreNBT); + }); + return this; } @@ -71,13 +97,21 @@ public abstract class ItemMetaBuilder { @Contract("_ -> this") public @NotNull ItemMetaBuilder enchantments(@NotNull Map enchantments) { - this.enchantmentMap.putAll(enchantments); + this.enchantmentMap = enchantments; + + if (!enchantmentMap.isEmpty()) { + NBTUtils.writeEnchant(nbt, "Enchantments", enchantmentMap); + } else { + this.nbt.removeTag("Enchantments"); + } + return this; } @Contract("_, _ -> this") public @NotNull ItemMetaBuilder enchantment(@NotNull Enchantment enchantment, short level) { this.enchantmentMap.put(enchantment, level); + enchantments(enchantmentMap); return this; } @@ -90,29 +124,45 @@ public abstract class ItemMetaBuilder { @Contract("_ -> this") public @NotNull ItemMetaBuilder attributes(@NotNull List<@NotNull ItemAttribute> attributes) { this.attributes = attributes; + + + if (!attributes.isEmpty()) { + NBTList attributesNBT = new NBTList<>(NBTTypes.TAG_Compound); + + for (ItemAttribute itemAttribute : attributes) { + final UUID uuid = itemAttribute.getUuid(); + attributesNBT.add( + new NBTCompound() + .setIntArray("UUID", Utils.uuidToIntArray(uuid)) + .setDouble("Amount", itemAttribute.getValue()) + .setString("Slot", itemAttribute.getSlot().name().toLowerCase()) + .setString("AttributeName", itemAttribute.getAttribute().getKey()) + .setInt("Operation", itemAttribute.getOperation().getId()) + .setString("Name", itemAttribute.getInternalName()) + ); + } + this.nbt.set("AttributeModifiers", attributesNBT); + } else { + this.nbt.removeTag("AttributeModifiers"); + } + return this; } @Contract("_ -> this") public @NotNull ItemMetaBuilder customModelData(int customModelData) { this.customModelData = customModelData; + this.nbt.setInt("CustomModelData", customModelData); return this; } public @NotNull ItemMetaBuilder set(@NotNull ItemTag tag, @Nullable T value) { - if (originalNBT != null) { - // Item is from nbt - if (value != null) { - tag.write(originalNBT, value); - } else { - this.originalNBT.removeTag(tag.getKey()); - } - return this; + if (value != null) { + tag.write(nbt, value); } else { - // Create item meta based on nbt - var currentNbt = build().nbt(); - return fromNBT(this, currentNbt).set(tag, value); + this.nbt.removeTag(tag.getKey()); } + return this; } @Contract("-> new") @@ -120,15 +170,38 @@ public abstract class ItemMetaBuilder { public abstract void read(@NotNull NBTCompound nbtCompound); - public abstract void write(@NotNull NBTCompound nbtCompound); - protected abstract @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier(); + protected void handleCompound(@NotNull String key, + @NotNull Consumer<@NotNull NBTCompound> consumer) { + NBTCompound compound = null; + boolean newNbt = false; + if (nbt.containsKey(key)) { + NBT dNbt = nbt.get(key); + if (dNbt instanceof NBTCompound) { + compound = (NBTCompound) dNbt; + } + } else { + compound = new NBTCompound(); + newNbt = true; + } + + if (compound != null) { + consumer.accept(compound); + + if (newNbt && compound.getSize() > 0) { + this.nbt.set(key, compound); + } else if (!newNbt && compound.getSize() == 0) { + this.nbt.removeTag(key); + } + + } + } + @Contract(value = "_, _ -> new", pure = true) public static @NotNull ItemMetaBuilder fromNBT(@NotNull ItemMetaBuilder src, @NotNull NBTCompound nbtCompound) { ItemMetaBuilder dest = src.getSupplier().get(); NBTUtils.loadDataIntoMeta(dest, nbtCompound); - dest.originalNBT = nbtCompound; return dest; } diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/meta/CompassMeta.java index 856f9df30..8a153fa40 100644 --- a/src/main/java/net/minestom/server/item/meta/CompassMeta.java +++ b/src/main/java/net/minestom/server/item/meta/CompassMeta.java @@ -45,16 +45,35 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider getSupplier() { return Builder::new; diff --git a/src/main/java/net/minestom/server/item/meta/MapMeta.java b/src/main/java/net/minestom/server/item/meta/MapMeta.java index 73651fa4d..243880a7d 100644 --- a/src/main/java/net/minestom/server/item/meta/MapMeta.java +++ b/src/main/java/net/minestom/server/item/meta/MapMeta.java @@ -90,21 +90,47 @@ public class MapMeta extends ItemMeta { public Builder mapId(int value) { this.mapId = value; + this.nbt.setInt("map", mapId); return this; } public Builder mapScaleDirection(int value) { this.mapScaleDirection = value; + this.nbt.setInt("map_scale_direction", value); return this; } public Builder decorations(List value) { this.decorations = value; + + NBTList decorationsList = new NBTList<>(NBTTypes.TAG_Compound); + for (MapDecoration decoration : decorations) { + NBTCompound decorationCompound = new NBTCompound(); + decorationCompound.setString("id", decoration.getId()); + decorationCompound.setByte("type", decoration.getType()); + decorationCompound.setByte("x", decoration.getX()); + decorationCompound.setByte("z", decoration.getZ()); + decorationCompound.setDouble("rot", decoration.getRotation()); + + decorationsList.add(decorationCompound); + } + this.nbt.set("Decorations", decorationsList); + return this; } public Builder mapColor(Color value) { this.mapColor = value; + + NBTCompound displayCompound; + if (nbt.containsKey("display")) { + displayCompound = nbt.getCompound("display"); + } else { + displayCompound = new NBTCompound(); + this.nbt.set("display", displayCompound); + } + displayCompound.setInt("MapColor", mapColor.asRGB()); + return this; } @@ -116,11 +142,11 @@ public class MapMeta extends ItemMeta { @Override public void read(@NotNull NBTCompound compound) { if (compound.containsKey("map")) { - this.mapId = compound.getAsInt("map"); + mapId(compound.getAsInt("map")); } if (compound.containsKey("map_scale_direction")) { - this.mapScaleDirection = compound.getAsInt("map_scale_direction"); + mapScaleDirection(compound.getAsInt("map_scale_direction")); } if (compound.containsKey("Decorations")) { @@ -156,38 +182,6 @@ public class MapMeta extends ItemMeta { } } - @Override - public void write(@NotNull NBTCompound compound) { - compound.setInt("map", mapId); - - compound.setInt("map_scale_direction", mapScaleDirection); - - if (!decorations.isEmpty()) { - NBTList decorationsList = new NBTList<>(NBTTypes.TAG_Compound); - for (MapDecoration decoration : decorations) { - NBTCompound decorationCompound = new NBTCompound(); - decorationCompound.setString("id", decoration.getId()); - decorationCompound.setByte("type", decoration.getType()); - decorationCompound.setByte("x", decoration.getX()); - decorationCompound.setByte("z", decoration.getZ()); - decorationCompound.setDouble("rot", decoration.getRotation()); - - decorationsList.add(decorationCompound); - } - compound.set("Decorations", decorationsList); - } - - { - NBTCompound displayCompound; - if (compound.containsKey("display")) { - displayCompound = compound.getCompound("display"); - } else { - displayCompound = new NBTCompound(); - } - displayCompound.setInt("MapColor", mapColor.asRGB()); - } - } - @Override protected @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier() { return Builder::new; diff --git a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java index 0d64585c6..657fd2543 100644 --- a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java @@ -193,7 +193,7 @@ public class CrossbowMeta extends ItemMeta { @NotNull private NBTCompound getItemCompound(@NotNull ItemStack itemStack) { - NBTCompound compound = NBTUtils.getMetaNBT(itemStack.getMeta()); + NBTCompound compound = itemStack.getMeta().nbt(); compound.setByte("Count", (byte) itemStack.getAmount()); compound.setString("id", itemStack.getMaterial().getName()); return compound; diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java index 22b851dc8..6267073f2 100644 --- a/src/main/java/net/minestom/server/utils/NBTUtils.java +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -5,11 +5,13 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.util.Codec; import net.minestom.server.MinecraftServer; -import net.minestom.server.adventure.AdventureSerializer; import net.minestom.server.attribute.Attribute; import net.minestom.server.attribute.AttributeOperation; import net.minestom.server.inventory.Inventory; -import net.minestom.server.item.*; +import net.minestom.server.item.Enchantment; +import net.minestom.server.item.ItemMetaBuilder; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; import net.minestom.server.item.attribute.AttributeSlot; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.registry.Registries; @@ -86,7 +88,7 @@ public final class NBTUtils { final ItemStack stack = inventory.getItemStack(i); NBTCompound nbt = new NBTCompound(); - NBTCompound tag = getMetaNBT(stack.getMeta()); + NBTCompound tag = stack.getMeta().nbt(); nbt.set("tag", tag); nbt.setByte("Slot", (byte) i); @@ -290,103 +292,6 @@ public final class NBTUtils { } } - public static void writeMetaNBT(@NotNull ItemMeta itemMeta, @NotNull NBTCompound itemNBT) { - // Unbreakable - if (itemMeta.isUnbreakable()) { - itemNBT.setInt("Unbreakable", 1); - } - - // Damage - { - final int damage = itemMeta.getDamage(); - if (damage > 0) { - itemNBT.setInt("Damage", damage); - } - } - - // Start display - { - final var displayName = itemMeta.getDisplayName(); - final var lore = itemMeta.getLore(); - final boolean hasDisplayName = displayName != null; - final boolean hasLore = !lore.isEmpty(); - if (hasDisplayName || hasLore) { - NBTCompound displayNBT = new NBTCompound(); - if (hasDisplayName) { - final String name = AdventureSerializer.serialize(displayName); - displayNBT.setString("Name", name); - } - - if (hasLore) { - final NBTList loreNBT = new NBTList<>(NBTTypes.TAG_String); - for (Component line : lore) { - loreNBT.add(new NBTString(GsonComponentSerializer.gson().serialize(line))); - } - displayNBT.set("Lore", loreNBT); - } - - itemNBT.set("display", displayNBT); - } - } - // End display - - // Start enchantment - { - final var enchantmentMap = itemMeta.getEnchantmentMap(); - if (!enchantmentMap.isEmpty()) { - NBTUtils.writeEnchant(itemNBT, "Enchantments", enchantmentMap); - } - } - // End enchantment - - // Start attribute - { - final var attributes = itemMeta.getAttributes(); - if (!attributes.isEmpty()) { - NBTList attributesNBT = new NBTList<>(NBTTypes.TAG_Compound); - - for (ItemAttribute itemAttribute : attributes) { - final UUID uuid = itemAttribute.getUuid(); - attributesNBT.add( - new NBTCompound() - .setIntArray("UUID", Utils.uuidToIntArray(uuid)) - .setDouble("Amount", itemAttribute.getValue()) - .setString("Slot", itemAttribute.getSlot().name().toLowerCase()) - .setString("AttributeName", itemAttribute.getAttribute().getKey()) - .setInt("Operation", itemAttribute.getOperation().getId()) - .setString("Name", itemAttribute.getInternalName()) - ); - } - itemNBT.set("AttributeModifiers", attributesNBT); - } - } - // End attribute - - // Start hide flag - { - final int hideFlag = itemMeta.getHideFlag(); - if (hideFlag != 0) { - itemNBT.setInt("HideFlags", hideFlag); - } - } - // End hide flag - - // Start custom model data - { - final int customModelData = itemMeta.getCustomModelData(); - if (customModelData != 0) { - itemNBT.setInt("CustomModelData", customModelData); - } - } - // End custom model data - } - - public static @NotNull NBTCompound getMetaNBT(@NotNull ItemMeta itemMeta) { - var nbt = new NBTCompound(); - writeMetaNBT(itemMeta, nbt); - return nbt; - } - @FunctionalInterface public interface EnchantmentSetter { void applyEnchantment(Enchantment name, short level); diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index bee771b8e..ec77a6fee 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -243,9 +243,11 @@ public class PlayerInit { .displayName(Component.text("test")) .lore(Component.text("lore")) .build(); + + //inventory.setChestplate(item); + inventory.setChestplate(item.with(itemStackBuilder -> { - itemStackBuilder.lore(Collections.emptyList()) - .displayName(null); + itemStackBuilder.lore(Collections.emptyList()); })); } }); From 64e70c3b6447e1c81a100d334ae5617d9ad5a5d4 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 00:01:06 +0200 Subject: [PATCH 52/77] Use the builder methods instead of fields --- .../java/net/minestom/server/item/meta/CompassMeta.java | 7 +++---- src/main/java/net/minestom/server/item/meta/MapMeta.java | 7 +++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/meta/CompassMeta.java index 8a153fa40..edf642398 100644 --- a/src/main/java/net/minestom/server/item/meta/CompassMeta.java +++ b/src/main/java/net/minestom/server/item/meta/CompassMeta.java @@ -85,18 +85,17 @@ public class CompassMeta extends ItemMeta implements ItemMetaBuilder.Provider decorationsList = compound.getList("Decorations"); + List mapDecorations = new ArrayList<>(); for (NBTCompound decorationCompound : decorationsList) { final String id = decorationCompound.getString("id"); final byte type = decorationCompound.getAsByte("type"); @@ -170,14 +172,15 @@ public class MapMeta extends ItemMeta { rotation = decorationCompound.getAsDouble("rot"); } - this.decorations.add(new MapDecoration(id, type, x, z, rotation)); + mapDecorations.add(new MapDecoration(id, type, x, z, rotation)); } + decorations(mapDecorations); } if (compound.containsKey("display")) { final NBTCompound displayCompound = compound.getCompound("display"); if (displayCompound.containsKey("MapColor")) { - this.mapColor = new Color(displayCompound.getAsInt("MapColor")); + mapColor(new Color(displayCompound.getAsInt("MapColor"))); } } } From 5e8e7cbaf48cafd8e96db3748a17ea80d2e67304 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 00:24:29 +0200 Subject: [PATCH 53/77] Rename nbt method to remove confusion about the object being mutable or not --- .../minestom/server/chat/ChatHoverEvent.java | 2 +- .../net/minestom/server/item/ItemMeta.java | 18 +++++++++++++----- .../server/item/metadata/CrossbowMeta.java | 2 +- .../net/minestom/server/utils/NBTUtils.java | 4 ++-- .../server/world/biomes/BiomeParticles.java | 2 +- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/minestom/server/chat/ChatHoverEvent.java b/src/main/java/net/minestom/server/chat/ChatHoverEvent.java index a1e4dbd00..162447c38 100644 --- a/src/main/java/net/minestom/server/chat/ChatHoverEvent.java +++ b/src/main/java/net/minestom/server/chat/ChatHoverEvent.java @@ -93,7 +93,7 @@ public class ChatHoverEvent { JsonObject obj = GsonComponentSerializer.gson().serializer().toJsonTree(Component.empty().hoverEvent(event)).getAsJsonObject(); obj = obj.get("hoverEvent").getAsJsonObject().get("contents").getAsJsonObject(); - NBTCompound compound = itemStack.getMeta().nbt(); + NBTCompound compound = itemStack.getMeta().toNBT(); obj.add("tag", new JsonPrimitive(compound.toSNBT())); return new ChatHoverEvent("show_item", obj); diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 7c9439fc6..acd62a6fa 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import java.lang.ref.SoftReference; import java.util.Collections; import java.util.List; import java.util.Map; @@ -28,6 +29,8 @@ public class ItemMeta { private final NBTCompound nbt; private final ItemMetaBuilder emptyBuilder; + private SoftReference nbtCache; + protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { this.damage = metaBuilder.damage; this.unbreakable = metaBuilder.unbreakable; @@ -92,18 +95,23 @@ public class ItemMeta { public T getOrDefault(@NotNull ItemTag tag, @Nullable T defaultValue) { var key = tag.getKey(); if (nbt.containsKey(key)) { - return tag.read(nbt); + return tag.read(toNBT()); } else { return defaultValue; } } public @Nullable T get(@NotNull ItemTag tag) { - return tag.read(nbt); + return tag.read(toNBT()); } - public @NotNull NBTCompound nbt() { - return nbt; + public @NotNull NBTCompound toNBT() { + NBTCompound cache = nbtCache.get(); + if (cache == null) { + cache = nbt.deepClone(); + nbtCache = new SoftReference<>(cache); + } + return cache; } @Override @@ -112,7 +120,7 @@ public class ItemMeta { if (o == null || getClass() != o.getClass()) return false; ItemMeta itemMeta = (ItemMeta) o; - return nbt.equals(itemMeta.nbt()); + return nbt.equals(itemMeta.nbt); } @Override diff --git a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java index 657fd2543..908af5183 100644 --- a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java @@ -193,7 +193,7 @@ public class CrossbowMeta extends ItemMeta { @NotNull private NBTCompound getItemCompound(@NotNull ItemStack itemStack) { - NBTCompound compound = itemStack.getMeta().nbt(); + NBTCompound compound = itemStack.getMeta().toNBT(); compound.setByte("Count", (byte) itemStack.getAmount()); compound.setString("id", itemStack.getMaterial().getName()); return compound; diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java index 6267073f2..2d640de38 100644 --- a/src/main/java/net/minestom/server/utils/NBTUtils.java +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -88,7 +88,7 @@ public final class NBTUtils { final ItemStack stack = inventory.getItemStack(i); NBTCompound nbt = new NBTCompound(); - NBTCompound tag = stack.getMeta().nbt(); + NBTCompound tag = stack.getMeta().toNBT(); nbt.set("tag", tag); nbt.setByte("Slot", (byte) i); @@ -288,7 +288,7 @@ public final class NBTUtils { packet.writeVarInt(itemStack.getMaterial().getId()); packet.writeByte((byte) itemStack.getAmount()); - packet.writeNBT("", itemStack.getMeta().nbt()); + packet.writeNBT("", itemStack.getMeta().toNBT()); } } diff --git a/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java b/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java index 5ab2ec118..721e89790 100644 --- a/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java +++ b/src/main/java/net/minestom/server/world/biomes/BiomeParticles.java @@ -100,7 +100,7 @@ public class BiomeParticles { @Override public NBTCompound toNbt() { //todo test count might be wrong type - NBTCompound nbtCompound = item.getMeta().nbt(); + NBTCompound nbtCompound = item.getMeta().toNBT(); nbtCompound.setString("type", type); return nbtCompound; } From f5b8f267d6c0ae06da9671dcc5e99f37df7a9945 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 00:25:50 +0200 Subject: [PATCH 54/77] Clone instead of caching --- src/main/java/net/minestom/server/item/ItemMeta.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index acd62a6fa..1560decc7 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -7,7 +7,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import java.lang.ref.SoftReference; import java.util.Collections; import java.util.List; import java.util.Map; @@ -29,8 +28,6 @@ public class ItemMeta { private final NBTCompound nbt; private final ItemMetaBuilder emptyBuilder; - private SoftReference nbtCache; - protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { this.damage = metaBuilder.damage; this.unbreakable = metaBuilder.unbreakable; @@ -106,12 +103,7 @@ public class ItemMeta { } public @NotNull NBTCompound toNBT() { - NBTCompound cache = nbtCache.get(); - if (cache == null) { - cache = nbt.deepClone(); - nbtCache = new SoftReference<>(cache); - } - return cache; + return nbt.deepClone(); } @Override From d1f8e60a7e3c0dc1304570ebd5bf4fe6d47c2579 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 00:55:18 +0200 Subject: [PATCH 55/77] Cache meta binary --- .../java/net/minestom/server/item/ItemMeta.java | 17 ++++++++++++++++- .../net/minestom/server/utils/NBTUtils.java | 13 ------------- .../server/utils/binary/BinaryWriter.java | 10 ++++++++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 1560decc7..7c02be9de 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -2,6 +2,8 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; import net.minestom.server.item.attribute.ItemAttribute; +import net.minestom.server.utils.binary.BinaryWriter; +import net.minestom.server.utils.binary.Writeable; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,7 +14,7 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; -public class ItemMeta { +public class ItemMeta implements Writeable { private final int damage; private final boolean unbreakable; @@ -28,6 +30,8 @@ public class ItemMeta { private final NBTCompound nbt; private final ItemMetaBuilder emptyBuilder; + private BinaryWriter cachedBuffer; + protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { this.damage = metaBuilder.damage; this.unbreakable = metaBuilder.unbreakable; @@ -124,4 +128,15 @@ public class ItemMeta { protected @NotNull ItemMetaBuilder builder() { return ItemMetaBuilder.fromNBT(emptyBuilder, nbt); } + + @Override + public synchronized void write(@NotNull BinaryWriter writer) { + if (cachedBuffer == null) { + BinaryWriter w = new BinaryWriter(); + w.writeNBT("", nbt); + this.cachedBuffer = w; + } + writer.write(cachedBuffer); + cachedBuffer.getBuffer().resetReaderIndex(); + } } diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java index 2d640de38..87b25e519 100644 --- a/src/main/java/net/minestom/server/utils/NBTUtils.java +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -16,7 +16,6 @@ import net.minestom.server.item.attribute.AttributeSlot; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.registry.Registries; import net.minestom.server.utils.binary.BinaryReader; -import net.minestom.server.utils.binary.BinaryWriter; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -280,18 +279,6 @@ public final class NBTUtils { } } - public static void writeItemStack(@NotNull BinaryWriter packet, @NotNull ItemStack itemStack) { - if (itemStack.isAir()) { - packet.writeBoolean(false); - } else { - packet.writeBoolean(true); - packet.writeVarInt(itemStack.getMaterial().getId()); - packet.writeByte((byte) itemStack.getAmount()); - - packet.writeNBT("", itemStack.getMeta().toNBT()); - } - } - @FunctionalInterface public interface EnchantmentSetter { void applyEnchantment(Enchantment name, short level); diff --git a/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java b/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java index 152f65268..2f6edee3d 100644 --- a/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java +++ b/src/main/java/net/minestom/server/utils/binary/BinaryWriter.java @@ -9,7 +9,6 @@ import net.minestom.server.adventure.AdventureSerializer; import net.minestom.server.chat.JsonMessage; import net.minestom.server.item.ItemStack; import net.minestom.server.utils.BlockPosition; -import net.minestom.server.utils.NBTUtils; import net.minestom.server.utils.SerializerUtils; import net.minestom.server.utils.Utils; import org.jetbrains.annotations.NotNull; @@ -264,7 +263,14 @@ public class BinaryWriter extends OutputStream { } public void writeItemStack(@NotNull ItemStack itemStack) { - NBTUtils.writeItemStack(this, itemStack); + if (itemStack.isAir()) { + writeBoolean(false); + } else { + writeBoolean(true); + writeVarInt(itemStack.getMaterial().getId()); + writeByte((byte) itemStack.getAmount()); + write(itemStack.getMeta()); + } } public void writeNBT(@NotNull String name, @NotNull NBT tag) { From 1d12a5de9544ca894c17642b59667e34f3ff1667 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 05:53:40 +0200 Subject: [PATCH 56/77] Implement all meta --- .../net/minestom/server/entity/Player.java | 1 - .../server/item/meta/CrossbowMeta.java | 190 +++++++++++ .../server/item/meta/EnchantedBookMeta.java | 66 ++++ .../server/item/meta/FireworkEffectMeta.java | 52 +++ .../server/item/meta/FireworkMeta.java | 90 ++++++ .../server/item/meta/LeatherArmorMeta.java | 61 ++++ .../server/item/meta/PlayerHeadMeta.java | 95 ++++++ .../minestom/server/item/meta/PotionMeta.java | 123 +++++++ .../server/item/meta/SpawnEggMeta.java | 50 +++ .../server/item/meta/WritableBookMeta.java | 103 ++++++ .../server/item/meta/WrittenBookMeta.java | 159 ++++++++++ .../server/item/metadata/CompassMeta.java | 103 ------ .../server/item/metadata/CrossbowMeta.java | 201 ------------ .../item/metadata/EnchantedBookMeta.java | 95 ------ .../item/metadata/FireworkEffectMeta.java | 92 ------ .../server/item/metadata/FireworkMeta.java | 179 ----------- .../server/item/metadata/ItemMeta.java | 61 ---- .../item/metadata/LeatherArmorMeta.java | 175 ---------- .../server/item/metadata/MapMeta.java | 300 ------------------ .../server/item/metadata/PlayerHeadMeta.java | 161 ---------- .../server/item/metadata/PotionMeta.java | 166 ---------- .../server/item/metadata/SpawnEggMeta.java | 50 --- .../item/metadata/WritableBookMeta.java | 120 ------- .../server/item/metadata/WrittenBookMeta.java | 221 ------------- 24 files changed, 989 insertions(+), 1925 deletions(-) create mode 100644 src/main/java/net/minestom/server/item/meta/CrossbowMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/FireworkEffectMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/FireworkMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/LeatherArmorMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/PlayerHeadMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/PotionMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/SpawnEggMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/WritableBookMeta.java create mode 100644 src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/CompassMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/EnchantedBookMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/FireworkEffectMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/FireworkMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/ItemMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/LeatherArmorMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/MapMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/PotionMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/WritableBookMeta.java delete mode 100644 src/main/java/net/minestom/server/item/metadata/WrittenBookMeta.java diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index a9b177d08..b0b754429 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -42,7 +42,6 @@ import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.minestom.server.item.metadata.WrittenBookMeta; import net.minestom.server.listener.PlayerDiggingListener; import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionState; diff --git a/src/main/java/net/minestom/server/item/meta/CrossbowMeta.java b/src/main/java/net/minestom/server/item/meta/CrossbowMeta.java new file mode 100644 index 000000000..8844a32ac --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/CrossbowMeta.java @@ -0,0 +1,190 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.minestom.server.registry.Registries; +import net.minestom.server.utils.NBTUtils; +import net.minestom.server.utils.validate.Check; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import org.jglrxavpok.hephaistos.nbt.NBTList; +import org.jglrxavpok.hephaistos.nbt.NBTTypes; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final boolean triple; + private final ItemStack projectile1, projectile2, projectile3; + private final boolean charged; + + protected CrossbowMeta(@NotNull ItemMetaBuilder metaBuilder, + boolean triple, + ItemStack projectile1, ItemStack projectile2, ItemStack projectile3, + boolean charged) { + super(metaBuilder); + this.triple = triple; + this.projectile1 = projectile1; + this.projectile2 = projectile2; + this.projectile3 = projectile3; + this.charged = charged; + } + + /** + * Gets if this crossbow is charged with 3 projectiles. + * + * @return true if this crossbow is charged with 3 projectiles, false otherwise + */ + public boolean isTriple() { + return triple; + } + + /** + * Gets the first projectile. + * + * @return the first projectile, null if not present + */ + public @Nullable ItemStack getProjectile1() { + return projectile1; + } + + /** + * Gets the second projectile. + * + * @return the second projectile, null if not present + */ + public @Nullable ItemStack getProjectile2() { + return projectile2; + } + + /** + * Gets the third projectile. + * + * @return the third projectile, null if not present + */ + public @Nullable ItemStack getProjectile3() { + return projectile3; + } + + /** + * Gets if the crossbow is currently charged. + * + * @return true if the crossbow is charged, false otherwise + */ + public boolean isCharged() { + return charged; + } + + public static class Builder extends ItemMetaBuilder { + + private boolean triple; + private ItemStack projectile1, projectile2, projectile3; + private boolean charged; + + /** + * Sets the projectile of this crossbow. + * + * @param projectile the projectile of the crossbow + */ + public Builder projectile(@NotNull ItemStack projectile) { + Check.argCondition(projectile.isAir(), "the projectile of your crossbow isn't visible"); + this.projectile1 = projectile; + this.triple = false; + + NBTList chargedProjectiles = new NBTList<>(NBTTypes.TAG_Compound); + chargedProjectiles.add(getItemCompound(projectile)); + this.nbt.set("ChargedProjectiles", chargedProjectiles); + + return this; + } + + /** + * Sets the triple projectiles of this crossbow. + * + * @param projectile1 the projectile 1 + * @param projectile2 the projectile 2 + * @param projectile3 the projectile 3 + */ + public Builder projectiles(@NotNull ItemStack projectile1, @NotNull ItemStack projectile2, @NotNull ItemStack projectile3) { + Check.argCondition(projectile1.isAir(), "the projectile1 of your crossbow isn't visible"); + Check.argCondition(projectile2.isAir(), "the projectile2 of your crossbow isn't visible"); + Check.argCondition(projectile3.isAir(), "the projectile3 of your crossbow isn't visible"); + + this.projectile1 = projectile1; + this.projectile2 = projectile2; + this.projectile3 = projectile3; + this.triple = true; + + NBTList chargedProjectiles = new NBTList<>(NBTTypes.TAG_Compound); + chargedProjectiles.add(getItemCompound(projectile1)); + chargedProjectiles.add(getItemCompound(projectile2)); + chargedProjectiles.add(getItemCompound(projectile3)); + this.nbt.set("ChargedProjectiles", chargedProjectiles); + + return this; + } + + /** + * Makes the bow charged or uncharged. + * + * @param charged true to make the crossbow charged, false otherwise + */ + public Builder charged(boolean charged) { + this.charged = charged; + this.nbt.setByte("Charged", (byte) (charged ? 1 : 0)); + return this; + } + + @Override + public @NotNull CrossbowMeta build() { + return new CrossbowMeta(this, triple, projectile1, projectile2, projectile3, charged); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey("ChargedProjectiles")) { + final NBTList projectilesList = nbtCompound.getList("ChargedProjectiles"); + List projectiles = new ArrayList<>(); + for (NBTCompound projectileCompound : projectilesList) { + final byte count = projectileCompound.getByte("Count"); + final String id = projectileCompound.getString("id"); + final Material material = Registries.getMaterial(id); + + final NBTCompound tagsCompound = projectileCompound.getCompound("tag"); + + ItemStack itemStack = NBTUtils.loadItem(material, count, tagsCompound); + + projectiles.add(itemStack); + } + + if (projectiles.size() == 1) { + projectile(projectiles.get(0)); + } else if (projectiles.size() == 3) { + projectiles(projectiles.get(0), projectiles.get(1), projectiles.get(2)); + } + + } + + if (nbtCompound.containsKey("Charged")) { + charged(nbtCompound.getByte("Charged") == 1); + } + } + + @Override + protected @NotNull Supplier getSupplier() { + return Builder::new; + } + + private @NotNull NBTCompound getItemCompound(@NotNull ItemStack itemStack) { + NBTCompound compound = itemStack.getMeta().toNBT(); + compound.setByte("Count", (byte) itemStack.getAmount()); + compound.setString("id", itemStack.getMaterial().getName()); + return compound; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java b/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java new file mode 100644 index 000000000..6de4c48cd --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java @@ -0,0 +1,66 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.item.Enchantment; +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import net.minestom.server.utils.NBTUtils; +import org.jetbrains.annotations.NotNull; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; + +import java.util.Collections; +import java.util.Map; +import java.util.function.Supplier; + +public class EnchantedBookMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final Map storedEnchantmentMap; + + protected EnchantedBookMeta(@NotNull ItemMetaBuilder metaBuilder, Map storedEnchantmentMap) { + super(metaBuilder); + this.storedEnchantmentMap = storedEnchantmentMap; + } + + /** + * Gets the stored enchantment map. + * Stored enchantments are used on enchanted book. + * + * @return an unmodifiable map containing the item stored enchantments + */ + public @NotNull Map getStoredEnchantmentMap() { + return Collections.unmodifiableMap(storedEnchantmentMap); + } + + public static class Builder extends ItemMetaBuilder { + + private Map enchantments; + + public Builder enchantments(Map enchantments) { + this.enchantments = enchantments; + NBTUtils.writeEnchant(nbt, "StoredEnchantments", enchantments); + return this; + } + + public Builder enchantment(Enchantment enchantment, short level) { + this.enchantments.put(enchantment, level); + enchantments(enchantments); + return this; + } + + @Override + public @NotNull EnchantedBookMeta build() { + return new EnchantedBookMeta(this, enchantments); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey("StoredEnchantments")) { + NBTUtils.loadEnchantments(nbtCompound.getList("StoredEnchantments"), this::enchantment); + } + } + + @Override + protected @NotNull Supplier getSupplier() { + return Builder::new; + } + } +} diff --git a/src/main/java/net/minestom/server/item/meta/FireworkEffectMeta.java b/src/main/java/net/minestom/server/item/meta/FireworkEffectMeta.java new file mode 100644 index 000000000..2c209f5ba --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/FireworkEffectMeta.java @@ -0,0 +1,52 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import net.minestom.server.item.firework.FireworkEffect; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; + +import java.util.function.Supplier; + +public class FireworkEffectMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final FireworkEffect fireworkEffect; + + protected FireworkEffectMeta(@NotNull ItemMetaBuilder metaBuilder, FireworkEffect fireworkEffect) { + super(metaBuilder); + this.fireworkEffect = fireworkEffect; + } + + public FireworkEffect getFireworkEffect() { + return fireworkEffect; + } + + public static class Builder extends ItemMetaBuilder { + + private FireworkEffect fireworkEffect; + + public Builder effect(@Nullable FireworkEffect fireworkEffect) { + this.fireworkEffect = fireworkEffect; + this.nbt.set("Explosion", this.fireworkEffect.asCompound()); + return this; + } + + @Override + public @NotNull FireworkEffectMeta build() { + return new FireworkEffectMeta(this, fireworkEffect); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey("Explosion")) { + effect(FireworkEffect.fromCompound(nbtCompound.getCompound("Explosion"))); + } + } + + @Override + protected @NotNull Supplier getSupplier() { + return Builder::new; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/minestom/server/item/meta/FireworkMeta.java b/src/main/java/net/minestom/server/item/meta/FireworkMeta.java new file mode 100644 index 000000000..4ab915c02 --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/FireworkMeta.java @@ -0,0 +1,90 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import net.minestom.server.item.firework.FireworkEffect; +import org.jetbrains.annotations.NotNull; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import org.jglrxavpok.hephaistos.nbt.NBTList; +import org.jglrxavpok.hephaistos.nbt.NBTTypes; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Supplier; + +public class FireworkMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final List effects; + private final byte flightDuration; + + protected FireworkMeta(@NotNull ItemMetaBuilder metaBuilder, List effects, + byte flightDuration) { + super(metaBuilder); + this.effects = effects; + this.flightDuration = flightDuration; + } + + public List getEffects() { + return effects; + } + + public byte getFlightDuration() { + return flightDuration; + } + + public static class Builder extends ItemMetaBuilder { + + private List effects = new CopyOnWriteArrayList<>(); + private byte flightDuration; + + public Builder effects(List effects) { + this.effects = effects; + handleCompound("Fireworks", nbtCompound -> { + NBTList explosions = new NBTList<>(NBTTypes.TAG_Compound); + for (FireworkEffect effect : this.effects) { + explosions.add(effect.asCompound()); + } + nbtCompound.set("Explosions", explosions); + }); + return this; + } + + public Builder flightDuration(byte flightDuration) { + this.flightDuration = flightDuration; + handleCompound("Fireworks", nbtCompound -> { + nbtCompound.setByte("Flight", this.flightDuration); + }); + return this; + } + + @Override + public @NotNull FireworkMeta build() { + return new FireworkMeta(this, effects, flightDuration); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey("Fireworks")) { + NBTCompound fireworksCompound = nbtCompound.getCompound("Fireworks"); + + if (fireworksCompound.containsKey("Flight")) { + flightDuration(fireworksCompound.getAsByte("Flight")); + } + + if (fireworksCompound.containsKey("Explosions")) { + NBTList explosions = fireworksCompound.getList("Explosions"); + + for (NBTCompound explosion : explosions) { + this.effects.add(FireworkEffect.fromCompound(explosion)); + } + effects(effects); + } + } + } + + @Override + protected @NotNull Supplier getSupplier() { + return Builder::new; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/minestom/server/item/meta/LeatherArmorMeta.java b/src/main/java/net/minestom/server/item/meta/LeatherArmorMeta.java new file mode 100644 index 000000000..0a3414a6b --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/LeatherArmorMeta.java @@ -0,0 +1,61 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.color.Color; +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; + +import java.util.function.Supplier; + +public class LeatherArmorMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final Color color; + + protected LeatherArmorMeta(@NotNull ItemMetaBuilder metaBuilder, @Nullable Color color) { + super(metaBuilder); + this.color = color; + } + + public @Nullable Color getColor() { + return color; + } + + public static class Builder extends ItemMetaBuilder { + + private Color color; + + public Builder color(@Nullable Color color) { + this.color = color; + handleCompound("display", nbtCompound -> { + if (color != null) { + nbtCompound.setInt("color", color.asRGB()); + } else { + nbtCompound.removeTag("color"); + } + }); + return this; + } + + @Override + public @NotNull LeatherArmorMeta build() { + return new LeatherArmorMeta(this, color); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey("display")) { + final NBTCompound displayCompound = nbtCompound.getCompound("display"); + if (displayCompound.containsKey("color")) { + color(new Color(displayCompound.getInt("color"))); + } + } + } + + @Override + protected @NotNull Supplier getSupplier() { + return Builder::new; + } + } +} diff --git a/src/main/java/net/minestom/server/item/meta/PlayerHeadMeta.java b/src/main/java/net/minestom/server/item/meta/PlayerHeadMeta.java new file mode 100644 index 000000000..661302f02 --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/PlayerHeadMeta.java @@ -0,0 +1,95 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.entity.PlayerSkin; +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import net.minestom.server.utils.Utils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import org.jglrxavpok.hephaistos.nbt.NBTList; +import org.jglrxavpok.hephaistos.nbt.NBTTypes; + +import java.util.UUID; +import java.util.function.Supplier; + +public class PlayerHeadMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final UUID skullOwner; + private final PlayerSkin playerSkin; + + protected PlayerHeadMeta(@NotNull ItemMetaBuilder metaBuilder, UUID skullOwner, + PlayerSkin playerSkin) { + super(metaBuilder); + this.skullOwner = skullOwner; + this.playerSkin = playerSkin; + } + + public UUID getSkullOwner() { + return skullOwner; + } + + public PlayerSkin getPlayerSkin() { + return playerSkin; + } + + public static class Builder extends ItemMetaBuilder { + + private UUID skullOwner; + private PlayerSkin playerSkin; + + public Builder skullOwner(@Nullable UUID skullOwner) { + this.skullOwner = skullOwner; + handleCompound("SkullOwner", nbtCompound -> { + nbtCompound.setIntArray("Id", Utils.uuidToIntArray(this.skullOwner)); + }); + return this; + } + + public Builder playerSkin(@Nullable PlayerSkin playerSkin) { + this.playerSkin = playerSkin; + handleCompound("SkullOwner", nbtCompound -> { + NBTList textures = new NBTList<>(NBTTypes.TAG_Compound); + String value = this.playerSkin.getTextures() == null ? "" : this.playerSkin.getTextures(); + String signature = this.playerSkin.getSignature() == null ? "" : this.playerSkin.getSignature(); + textures.add(new NBTCompound().setString("Value", value).setString("Signature", signature)); + nbtCompound.set("Properties", new NBTCompound().set("textures", textures)); + }); + return this; + } + + @Override + public @NotNull PlayerHeadMeta build() { + return new PlayerHeadMeta(this, skullOwner, playerSkin); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey("SkullOwner")) { + NBTCompound skullOwnerCompound = nbtCompound.getCompound("SkullOwner"); + + if (skullOwnerCompound.containsKey("Id")) { + skullOwner(Utils.intArrayToUuid(skullOwnerCompound.getIntArray("Id"))); + } + + if (skullOwnerCompound.containsKey("Properties")) { + NBTCompound propertyCompound = skullOwnerCompound.getCompound("Properties"); + + if (propertyCompound.containsKey("textures")) { + NBTList textures = propertyCompound.getList("textures"); + if (textures != null) { + NBTCompound nbt = textures.get(0); + playerSkin(new PlayerSkin(nbt.getString("Value"), nbt.getString("Signature"))); + } + } + + } + } + } + + @Override + protected @NotNull Supplier getSupplier() { + return Builder::new; + } + } +} diff --git a/src/main/java/net/minestom/server/item/meta/PotionMeta.java b/src/main/java/net/minestom/server/item/meta/PotionMeta.java new file mode 100644 index 000000000..2d717367b --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/PotionMeta.java @@ -0,0 +1,123 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.color.Color; +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import net.minestom.server.potion.CustomPotionEffect; +import net.minestom.server.potion.PotionType; +import net.minestom.server.registry.Registries; +import net.minestom.server.utils.time.TimeUnit; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import org.jglrxavpok.hephaistos.nbt.NBTList; +import org.jglrxavpok.hephaistos.nbt.NBTTypes; + +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final PotionType potionType; + private final List customPotionEffects; + private final Color color; + + protected PotionMeta(@NotNull ItemMetaBuilder metaBuilder, @Nullable PotionType potionType, + List customPotionEffects, + Color color) { + super(metaBuilder); + this.potionType = potionType; + this.customPotionEffects = Collections.unmodifiableList(customPotionEffects); + this.color = color; + } + + public PotionType getPotionType() { + return potionType; + } + + public List getCustomPotionEffects() { + return customPotionEffects; + } + + + public Color getColor() { + return color; + } + + public static class Builder extends ItemMetaBuilder { + + private PotionType potionType; + private List customPotionEffects; + private Color color; + + public Builder potionType(@NotNull PotionType potionType) { + this.potionType = potionType; + this.nbt.setString("Potion", potionType.getNamespaceID()); + return this; + } + + public Builder effects(@NotNull List customPotionEffects) { + this.customPotionEffects = customPotionEffects; + + NBTList potionList = new NBTList<>(NBTTypes.TAG_Compound); + for (CustomPotionEffect customPotionEffect : customPotionEffects) { + NBTCompound potionCompound = new NBTCompound(); + potionCompound.setByte("Id", customPotionEffect.getId()); + potionCompound.setByte("Amplifier", customPotionEffect.getAmplifier()); + potionCompound.setInt("Duration", customPotionEffect.getDuration()); + potionCompound.setByte("Ambient", (byte) (customPotionEffect.isAmbient() ? 1 : 0)); + potionCompound.setByte("ShowParticles", (byte) (customPotionEffect.showParticles() ? 1 : 0)); + potionCompound.setByte("ShowIcon", (byte) (customPotionEffect.showIcon() ? 1 : 0)); + + potionList.add(potionCompound); + } + this.nbt.set("CustomPotionEffects", potionList); + + return this; + } + + public Builder color(@NotNull Color color) { + this.color = color; + this.nbt.setInt("CustomPotionColor", color.asRGB()); + return this; + } + + @Override + public @NotNull PotionMeta build() { + return new PotionMeta(this, potionType, customPotionEffects, color); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey("Potion")) { + potionType(Registries.getPotionType(nbtCompound.getString("Potion"))); + } + + if (nbtCompound.containsKey("CustomPotionEffects")) { + NBTList customEffectList = nbtCompound.getList("CustomPotionEffects"); + for (NBTCompound potionCompound : customEffectList) { + final byte id = potionCompound.getAsByte("Id"); + final byte amplifier = potionCompound.getAsByte("Amplifier"); + final int duration = potionCompound.containsKey("Duration") ? potionCompound.getNumber("Duration").intValue() : (int) TimeUnit.SECOND.toMilliseconds(30); + final boolean ambient = potionCompound.containsKey("Ambient") ? potionCompound.getAsByte("Ambient") == 1 : false; + final boolean showParticles = potionCompound.containsKey("ShowParticles") ? potionCompound.getAsByte("ShowParticles") == 1 : true; + final boolean showIcon = potionCompound.containsKey("ShowIcon") ? potionCompound.getAsByte("ShowIcon") == 1 : true; + + this.customPotionEffects.add( + new CustomPotionEffect(id, amplifier, duration, ambient, showParticles, showIcon)); + } + effects(customPotionEffects); + } + + if (nbtCompound.containsKey("CustomPotionColor")) { + color(new Color(nbtCompound.getInt("CustomPotionColor"))); + } + } + + @Override + protected @NotNull Supplier getSupplier() { + return Builder::new; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/minestom/server/item/meta/SpawnEggMeta.java b/src/main/java/net/minestom/server/item/meta/SpawnEggMeta.java new file mode 100644 index 000000000..f9aef14c2 --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/SpawnEggMeta.java @@ -0,0 +1,50 @@ +package net.minestom.server.item.meta; + +import net.minestom.server.entity.EntityType; +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; + +import java.util.function.Supplier; + +public class SpawnEggMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final EntityType entityType; + + protected SpawnEggMeta(@NotNull ItemMetaBuilder metaBuilder, @Nullable EntityType entityType) { + super(metaBuilder); + this.entityType = entityType; + } + + public @Nullable EntityType getEntityType() { + return entityType; + } + + public static class Builder extends ItemMetaBuilder { + + private EntityType entityType; + + public Builder entityType(@Nullable EntityType entityType) { + this.entityType = entityType; + // TODO nbt + return this; + } + + @Override + public @NotNull SpawnEggMeta build() { + return new SpawnEggMeta(this, entityType); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + // TODO + } + + @Override + protected @NotNull Supplier getSupplier() { + return Builder::new; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java b/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java new file mode 100644 index 000000000..e150d6739 --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java @@ -0,0 +1,103 @@ +package net.minestom.server.item.meta; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.minestom.server.adventure.AdventureSerializer; +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import org.jetbrains.annotations.NotNull; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import org.jglrxavpok.hephaistos.nbt.NBTList; +import org.jglrxavpok.hephaistos.nbt.NBTString; +import org.jglrxavpok.hephaistos.nbt.NBTTypes; + +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final String author; + private final String title; + private final List pages; + + protected WritableBookMeta(@NotNull ItemMetaBuilder metaBuilder, + String author, String title, + List pages) { + super(metaBuilder); + this.author = author; + this.title = title; + this.pages = Collections.unmodifiableList(pages); + } + + public String getAuthor() { + return author; + } + + public String getTitle() { + return title; + } + + public List getPages() { + return pages; + } + + public static class Builder extends ItemMetaBuilder { + + private String author; + private String title; + private List pages; + + public Builder author(String author) { + this.author = author; + this.nbt.setString("author", author); + return this; + } + + public Builder title(String title) { + this.title = title; + this.nbt.setString("title", author); + return this; + } + + public Builder pages(List pages) { + this.pages = pages; + this.nbt.setString("title", author); + + NBTList list = new NBTList<>(NBTTypes.TAG_String); + for (Component page : pages) { + list.add(new NBTString(AdventureSerializer.serialize(page))); + } + this.nbt.set("pages", list); + + return this; + } + + @Override + public @NotNull WritableBookMeta build() { + return new WritableBookMeta(this, author, title, pages); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey("author")) { + author(nbtCompound.getString("author")); + } + if (nbtCompound.containsKey("title")) { + title(nbtCompound.getString("title")); + } + if (nbtCompound.containsKey("pages")) { + final NBTList list = nbtCompound.getList("pages"); + for (NBTString page : list) { + this.pages.add(GsonComponentSerializer.gson().deserialize(page.getValue())); + } + pages(pages); + } + } + + @Override + protected @NotNull Supplier getSupplier() { + return WritableBookMeta.Builder::new; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java b/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java new file mode 100644 index 000000000..447fd143f --- /dev/null +++ b/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java @@ -0,0 +1,159 @@ +package net.minestom.server.item.meta; + +import net.kyori.adventure.inventory.Book; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.minestom.server.adventure.AdventureSerializer; +import net.minestom.server.adventure.Localizable; +import net.minestom.server.item.ItemMeta; +import net.minestom.server.item.ItemMetaBuilder; +import org.jetbrains.annotations.NotNull; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; +import org.jglrxavpok.hephaistos.nbt.NBTList; +import org.jglrxavpok.hephaistos.nbt.NBTString; +import org.jglrxavpok.hephaistos.nbt.NBTTypes; + +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provider { + + private final boolean resolved; + private final WrittenBookGeneration generation; + private final String author; + private final String title; + private final List pages; + + protected WrittenBookMeta(@NotNull ItemMetaBuilder metaBuilder, boolean resolved, + WrittenBookGeneration generation, String author, String title, + List pages) { + super(metaBuilder); + this.resolved = resolved; + this.generation = generation; + this.author = author; + this.title = title; + this.pages = Collections.unmodifiableList(pages); + } + + public boolean isResolved() { + return resolved; + } + + public WrittenBookGeneration getGeneration() { + return generation; + } + + public String getAuthor() { + return author; + } + + public String getTitle() { + return title; + } + + public List getPages() { + return pages; + } + + public enum WrittenBookGeneration { + ORIGINAL, COPY_OF_ORIGINAL, COPY_OF_COPY, TATTERED + } + + /** + * Creates a written book meta from an Adventure book. This meta will not be + * resolved and the generation will default to {@link WrittenBookGeneration#ORIGINAL}. + * + * @param book the book + * @param localizable who the book is for + * @return the meta + */ + public static @NotNull WrittenBookMeta fromAdventure(@NotNull Book book, @NotNull Localizable localizable) { + return new Builder() + .resolved(false) + .generation(WrittenBookGeneration.ORIGINAL) + .author(AdventureSerializer.translateAndSerialize(book.author(), localizable)) + .title(AdventureSerializer.translateAndSerialize(book.title(), localizable)) + .pages(book.pages()) + .build(); + } + + public static class Builder extends ItemMetaBuilder { + + private boolean resolved; + private WrittenBookGeneration generation; + private String author; + private String title; + private List pages; + + public Builder resolved(boolean resolved) { + this.resolved = resolved; + this.nbt.setByte("resolved", (byte) (resolved ? 1 : 0)); + return this; + } + + public Builder generation(WrittenBookGeneration generation) { + this.generation = generation; + this.nbt.setInt("generation", generation.ordinal()); + return this; + } + + public Builder author(String author) { + this.author = author; + this.nbt.setString("author", author); + return this; + } + + public Builder title(String title) { + this.title = title; + this.nbt.setString("title", author); + return this; + } + + public Builder pages(List pages) { + this.pages = pages; + this.nbt.setString("title", author); + + NBTList list = new NBTList<>(NBTTypes.TAG_String); + for (Component page : pages) { + list.add(new NBTString(AdventureSerializer.serialize(page))); + } + this.nbt.set("pages", list); + + return this; + } + + @Override + public @NotNull WrittenBookMeta build() { + return new WrittenBookMeta(this, resolved, generation, author, title, pages); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + if (nbtCompound.containsKey("resolved")) { + resolved(nbtCompound.getByte("resolved") == 1); + } + if (nbtCompound.containsKey("generation")) { + generation(WrittenBookGeneration.values()[nbtCompound.getInt("generation")]); + } + if (nbtCompound.containsKey("author")) { + author(nbtCompound.getString("author")); + } + if (nbtCompound.containsKey("title")) { + title(nbtCompound.getString("title")); + } + if (nbtCompound.containsKey("pages")) { + final NBTList list = nbtCompound.getList("pages"); + for (NBTString page : list) { + this.pages.add(GsonComponentSerializer.gson().deserialize(page.getValue())); + } + pages(pages); + } + } + + @Override + protected @NotNull Supplier getSupplier() { + return Builder::new; + } + } +} diff --git a/src/main/java/net/minestom/server/item/metadata/CompassMeta.java b/src/main/java/net/minestom/server/item/metadata/CompassMeta.java deleted file mode 100644 index da5424d51..000000000 --- a/src/main/java/net/minestom/server/item/metadata/CompassMeta.java +++ /dev/null @@ -1,103 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.utils.Position; -import net.minestom.server.utils.clone.CloneUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; - -import java.util.Objects; - -public class CompassMeta extends ItemMeta { - - private boolean lodestoneTracked; - private String lodestoneDimension; - - private Position lodestonePosition; - - public boolean isLodestoneTracked() { - return lodestoneTracked; - } - - public void setLodestoneTracked(boolean lodestoneTracked) { - this.lodestoneTracked = lodestoneTracked; - } - - @Nullable - public String getLodestoneDimension() { - return lodestoneDimension; - } - - public void setLodestoneDimension(@Nullable String lodestoneDimension) { - this.lodestoneDimension = lodestoneDimension; - } - - @Nullable - public Position getLodestonePosition() { - return lodestonePosition; - } - - public void setLodestonePosition(@Nullable Position lodestonePosition) { - this.lodestonePosition = lodestonePosition; - } - - @Override - public boolean hasNbt() { - return true; - } - - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof CompassMeta)) - return false; - CompassMeta compassMeta = (CompassMeta) itemMeta; - return (compassMeta.lodestoneTracked == lodestoneTracked) && - (Objects.equals(compassMeta.lodestoneDimension, lodestoneDimension)) && - (Objects.equals(compassMeta.lodestonePosition, lodestonePosition)); - } - - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("LodestoneTracked")) { - this.lodestoneTracked = compound.getByte("LodestoneTracked") == 1; - } - if (compound.containsKey("LodestoneDimension")) { - this.lodestoneDimension = compound.getString("LodestoneDimension"); - } - if (compound.containsKey("LodestonePos")) { - final NBTCompound posCompound = compound.getCompound("LodestonePos"); - final int x = posCompound.getInt("X"); - final int y = posCompound.getInt("Y"); - final int z = posCompound.getInt("Z"); - - this.lodestonePosition = new Position(x, y, z); - } - } - - @Override - public void write(@NotNull NBTCompound compound) { - compound.setByte("LodestoneTracked", (byte) (lodestoneTracked ? 1 : 0)); - if (lodestoneDimension != null) { - compound.setString("LodestoneDimension", lodestoneDimension); - } - - if (lodestonePosition != null) { - NBTCompound posCompound = new NBTCompound(); - posCompound.setInt("X", (int) lodestonePosition.getX()); - posCompound.setInt("Y", (int) lodestonePosition.getY()); - posCompound.setInt("Z", (int) lodestonePosition.getZ()); - compound.set("LodestonePos", posCompound); - } - } - - @NotNull - @Override - public ItemMeta clone() { - CompassMeta compassMeta = (CompassMeta) super.clone(); - compassMeta.lodestoneTracked = lodestoneTracked; - compassMeta.lodestoneDimension = lodestoneDimension; - compassMeta.lodestonePosition = CloneUtils.optionalClone(lodestonePosition); - - return compassMeta; - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java deleted file mode 100644 index 908af5183..000000000 --- a/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java +++ /dev/null @@ -1,201 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.item.ItemStack; -import net.minestom.server.item.Material; -import net.minestom.server.registry.Registries; -import net.minestom.server.utils.NBTUtils; -import net.minestom.server.utils.validate.Check; -import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTList; -import org.jglrxavpok.hephaistos.nbt.NBTTypes; - -public class CrossbowMeta extends ItemMeta { - - private boolean triple; - private ItemStack projectile1, projectile2, projectile3; - - private boolean charged; - - /** - * Sets the projectile of this crossbow. - * - * @param projectile the projectile of the crossbow - */ - public void setProjectile(@NotNull ItemStack projectile) { - Check.argCondition(projectile.isAir(), "the projectile of your crossbow isn't visible"); - this.projectile1 = projectile; - this.triple = false; - } - - /** - * Sets the triple projectiles of this crossbow. - * - * @param projectile1 the projectile 1 - * @param projectile2 the projectile 2 - * @param projectile3 the projectile 3 - */ - public void setProjectiles(@NotNull ItemStack projectile1, @NotNull ItemStack projectile2, @NotNull ItemStack projectile3) { - Check.argCondition(projectile1.isAir(), "the projectile1 of your crossbow isn't visible"); - Check.argCondition(projectile2.isAir(), "the projectile2 of your crossbow isn't visible"); - Check.argCondition(projectile3.isAir(), "the projectile3 of your crossbow isn't visible"); - - this.projectile1 = projectile1; - this.projectile2 = projectile2; - this.projectile3 = projectile3; - this.triple = true; - } - - /** - * Gets if this crossbow is charged with 3 projectiles. - * - * @return true if this crossbow is charged with 3 projectiles, false otherwise - */ - public boolean isTriple() { - return triple; - } - - /** - * Gets the first projectile. - * - * @return the first projectile, null if not present - */ - public ItemStack getProjectile1() { - return projectile1; - } - - /** - * Gets the second projectile. - * - * @return the second projectile, null if not present - */ - public ItemStack getProjectile2() { - return projectile2; - } - - /** - * Gets the third projectile. - * - * @return the third projectile, null if not present - */ - public ItemStack getProjectile3() { - return projectile3; - } - - /** - * Gets if the crossbow is currently charged. - * - * @return true if the crossbow is charged, false otherwise - */ - public boolean isCharged() { - return charged; - } - - /** - * Makes the bow charged or uncharged. - * - * @param charged true to make the crossbow charged, false otherwise - */ - public void setCharged(boolean charged) { - this.charged = charged; - } - - @Override - public boolean hasNbt() { - return projectile1 != null && !projectile1.isAir(); - } - - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof CrossbowMeta)) - return false; - - final CrossbowMeta crossbowMeta = (CrossbowMeta) itemMeta; - final boolean checkCount = triple && crossbowMeta.triple; - if (!checkCount) - return false; - - if (projectile1.isSimilar(crossbowMeta.projectile1) && - projectile2.isSimilar(crossbowMeta.projectile2) && - projectile3.isSimilar(crossbowMeta.projectile3)) { - return true; - } - - return !triple && (projectile1.isSimilar(crossbowMeta.projectile1)); - } - - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("ChargedProjectiles")) { - final NBTList projectilesList = compound.getList("ChargedProjectiles"); - int index = 0; - for (NBTCompound projectileCompound : projectilesList) { - final byte count = projectileCompound.getByte("Count"); - final String id = projectileCompound.getString("id"); - final Material material = Registries.getMaterial(id); - - final NBTCompound tagsCompound = projectileCompound.getCompound("tag"); - - ItemStack itemStack = NBTUtils.loadItem(material, count, tagsCompound); - - index++; - - if (index == 1) { - projectile1 = itemStack; - } else if (index == 2) { - projectile2 = itemStack; - } else if (index == 3) { - projectile3 = itemStack; - } - - } - } - - if (compound.containsKey("Charged")) { - this.charged = compound.getByte("Charged") == 1; - } - } - - @Override - public void write(@NotNull NBTCompound compound) { - if (projectile1 != null || projectile2 != null || projectile3 != null) { - NBTList chargedProjectiles = new NBTList<>(NBTTypes.TAG_Compound); - if (projectile1 != null) { - chargedProjectiles.add(getItemCompound(projectile1)); - } - if (projectile2 != null) { - chargedProjectiles.add(getItemCompound(projectile2)); - } - if (projectile3 != null) { - chargedProjectiles.add(getItemCompound(projectile3)); - } - compound.set("ChargedProjectiles", chargedProjectiles); - } - - if (charged) { - compound.setByte("Charged", (byte) (charged ? 1 : 0)); - } - } - - @NotNull - @Override - public ItemMeta clone() { - CrossbowMeta crossbowMeta = (CrossbowMeta) super.clone(); - crossbowMeta.triple = triple; - crossbowMeta.projectile1 = projectile1; - crossbowMeta.projectile2 = projectile2; - crossbowMeta.projectile3 = projectile3; - - crossbowMeta.charged = charged; - - return crossbowMeta; - } - - @NotNull - private NBTCompound getItemCompound(@NotNull ItemStack itemStack) { - NBTCompound compound = itemStack.getMeta().toNBT(); - compound.setByte("Count", (byte) itemStack.getAmount()); - compound.setString("id", itemStack.getMaterial().getName()); - return compound; - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/EnchantedBookMeta.java b/src/main/java/net/minestom/server/item/metadata/EnchantedBookMeta.java deleted file mode 100644 index 7f280c8b2..000000000 --- a/src/main/java/net/minestom/server/item/metadata/EnchantedBookMeta.java +++ /dev/null @@ -1,95 +0,0 @@ -package net.minestom.server.item.metadata; - -import it.unimi.dsi.fastutil.objects.Object2ShortMap; -import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap; -import net.minestom.server.item.Enchantment; -import net.minestom.server.utils.NBTUtils; -import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; - -import java.util.Collections; -import java.util.Map; - -public class EnchantedBookMeta extends ItemMeta { - - private final Object2ShortMap storedEnchantmentMap = new Object2ShortOpenHashMap<>(); - - /** - * Gets the stored enchantment map. - * Stored enchantments are used on enchanted book. - * - * @return an unmodifiable map containing the item stored enchantments - */ - @NotNull - public Map getStoredEnchantmentMap() { - return Collections.unmodifiableMap(storedEnchantmentMap); - } - - /** - * Sets a stored enchantment level. - * - * @param enchantment the enchantment type - * @param level the enchantment level - */ - public void setStoredEnchantment(@NotNull Enchantment enchantment, short level) { - if (level < 1) { - removeStoredEnchantment(enchantment); - return; - } - - this.storedEnchantmentMap.put(enchantment, level); - } - - /** - * Removes a stored enchantment. - * - * @param enchantment the enchantment type - */ - public void removeStoredEnchantment(@NotNull Enchantment enchantment) { - this.storedEnchantmentMap.removeShort(enchantment); - } - - /** - * Gets a stored enchantment level. - * - * @param enchantment the enchantment type - * @return the stored enchantment level, 0 if not present - */ - public int getStoredEnchantmentLevel(@NotNull Enchantment enchantment) { - return this.storedEnchantmentMap.getOrDefault(enchantment, (short) 0); - } - - @Override - public boolean hasNbt() { - return !storedEnchantmentMap.isEmpty(); - } - - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - return itemMeta instanceof EnchantedBookMeta && - ((EnchantedBookMeta) itemMeta).storedEnchantmentMap.equals(storedEnchantmentMap); - } - - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("StoredEnchantments")) { - NBTUtils.loadEnchantments(compound.getList("StoredEnchantments"), this::setStoredEnchantment); - } - } - - @Override - public void write(@NotNull NBTCompound compound) { - if (!storedEnchantmentMap.isEmpty()) { - NBTUtils.writeEnchant(compound, "StoredEnchantments", storedEnchantmentMap); - } - } - - @NotNull - @Override - public ItemMeta clone() { - EnchantedBookMeta enchantedBookMeta = (EnchantedBookMeta) super.clone(); - enchantedBookMeta.storedEnchantmentMap.putAll(storedEnchantmentMap); - - return enchantedBookMeta; - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/FireworkEffectMeta.java b/src/main/java/net/minestom/server/item/metadata/FireworkEffectMeta.java deleted file mode 100644 index 045dee42e..000000000 --- a/src/main/java/net/minestom/server/item/metadata/FireworkEffectMeta.java +++ /dev/null @@ -1,92 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.item.firework.FireworkEffect; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; - -public class FireworkEffectMeta extends ItemMeta { - - private FireworkEffect fireworkEffect; - - /** - * Retrieves the firework effect for this meta. - * - * @return The current firework effect, or {@code null} if none. - */ - @Nullable - public FireworkEffect getFireworkEffect() { - return fireworkEffect; - } - - /** - * Changes the {@link FireworkEffect} for this item meta. - * - * @param fireworkEffect The new firework effect, or {@code null}. - */ - public void setFireworkEffect(@Nullable FireworkEffect fireworkEffect) { - this.fireworkEffect = fireworkEffect; - } - - /** - * Whether if this item meta has an effect. - * - * @return {@code true} if this item meta has an effect, otherwise {@code false}. - */ - public boolean hasFireworkEffect() { - return this.fireworkEffect != null; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasNbt() { - return this.hasFireworkEffect(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof FireworkEffectMeta)) { - return false; - } - - FireworkEffectMeta fireworkEffectMeta = (FireworkEffectMeta) itemMeta; - return fireworkEffectMeta.fireworkEffect == this.fireworkEffect; - } - - /** - * {@inheritDoc} - */ - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("Explosion")) { - this.fireworkEffect = FireworkEffect.fromCompound(compound.getCompound("Explosion")); - } - - } - - /** - * {@inheritDoc} - */ - @Override - public void write(@NotNull NBTCompound compound) { - if (this.fireworkEffect != null) { - compound.set("Explosion", this.fireworkEffect.asCompound()); - } - } - - /** - * {@inheritDoc} - */ - @NotNull - @Override - public ItemMeta clone() { - FireworkEffectMeta fireworkEffectMeta = (FireworkEffectMeta) super.clone(); - fireworkEffectMeta.fireworkEffect = this.fireworkEffect; - return fireworkEffectMeta; - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/FireworkMeta.java b/src/main/java/net/minestom/server/item/metadata/FireworkMeta.java deleted file mode 100644 index ca8d7ec5f..000000000 --- a/src/main/java/net/minestom/server/item/metadata/FireworkMeta.java +++ /dev/null @@ -1,179 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.item.firework.FireworkEffect; -import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTList; -import org.jglrxavpok.hephaistos.nbt.NBTTypes; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Represents a firework rocket meta data and its effects. - */ -public class FireworkMeta extends ItemMeta { - - private List effects = new CopyOnWriteArrayList<>(); - private byte flightDuration; - - /** - * Adds a firework effect to this firework. - * - * @param effect The firework effect to be added. - */ - public void addFireworkEffect(FireworkEffect effect) { - this.effects.add(effect); - } - - /** - * Adds an array of firework effects to this firework. - * - * @param effects An array of firework effects to be added. - */ - public void addFireworkEffects(FireworkEffect... effects) { - this.effects.addAll(Arrays.asList(effects)); - } - - /** - * Removes a firework effect from this firework. - * - * @param index The index of the firework effect to be removed. - * @throws IndexOutOfBoundsException If index {@literal < 0 or index >} {@link #getEffectSize()} - */ - public void removeFireworkEffect(int index) throws IndexOutOfBoundsException { - this.effects.remove(index); - } - - /** - * Removes a firework effects from this firework. - * - * @param effect The effect to be removed. - */ - public void removeFireworkEffect(FireworkEffect effect) { - this.effects.remove(effect); - } - - /** - * Retrieves a collection with all effects in this firework. - * - * @return A collection with all effects in this firework. - */ - public List getEffects() { - return effects; - } - - /** - * Retrieves the size of effects in this firework. - * - * @return The size of the effects. - */ - public int getEffectSize() { - return this.effects.size(); - } - - /** - * Removes all effects from this firework. - */ - public void clearEffects() { - this.effects.clear(); - } - - /** - * Whether this firework has any effects. - * - * @return {@code true} if this firework has any effects, otherwise {@code false}. - */ - public boolean hasEffects() { - return this.effects.isEmpty(); - } - - /** - * Changes the flight duration of this firework. - * - * @param flightDuration The new flight duration for this firework. - */ - public void setFlightDuration(byte flightDuration) { - this.flightDuration = flightDuration; - } - - /** - * Returns the flight duration of this firework - * @return the flight duration of this firework - */ - public byte getFlightDuration() { - return flightDuration; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasNbt() { - return this.flightDuration == 0 || !this.effects.isEmpty(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public void read(@NotNull NBTCompound compound) { - this.effects.clear(); - if (compound.containsKey("Fireworks")) { - NBTCompound fireworksCompound = compound.getCompound("Fireworks"); - - if (fireworksCompound.containsKey("Flight")) { - this.flightDuration = fireworksCompound.getAsByte("Flight"); - } - - if (fireworksCompound.containsKey("Explosions")) { - NBTList explosions = fireworksCompound.getList("Explosions"); - - for (NBTCompound explosion : explosions) { - this.effects.add(FireworkEffect.fromCompound(explosion)); - } - } - - } - } - - /** - * {@inheritDoc} - */ - @Override - public void write(@NotNull NBTCompound compound) { - NBTCompound fireworksCompound = new NBTCompound(); - fireworksCompound.setByte("Flight", this.flightDuration); - - NBTList explosions = new NBTList<>(NBTTypes.TAG_Compound); - for (FireworkEffect effect : this.effects) { - explosions.add(effect.asCompound()); - } - - fireworksCompound.set("Explosions", explosions); - - compound.set("Fireworks", fireworksCompound); - } - - /** - * {@inheritDoc} - */ - @NotNull - @Override - public ItemMeta clone() { - FireworkMeta fireworkMeta = (FireworkMeta) super.clone(); - fireworkMeta.effects = this.effects; - fireworkMeta.flightDuration = this.flightDuration; - - return fireworkMeta; - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/ItemMeta.java b/src/main/java/net/minestom/server/item/metadata/ItemMeta.java deleted file mode 100644 index 4e200e331..000000000 --- a/src/main/java/net/minestom/server/item/metadata/ItemMeta.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.item.ItemStack; -import net.minestom.server.utils.clone.PublicCloneable; -import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; - -/** - * Represents nbt data only available for a type of item. - */ -public abstract class ItemMeta implements PublicCloneable { - - /** - * Gets if this meta object contains any useful data to send to the client. - * - * @return true if this item has nbt data, false otherwise - */ - public abstract boolean hasNbt(); - - /** - * Gets if the two ItemMeta are similar. - *

- * It is used by {@link ItemStack#isSimilar(ItemStack)}. - * - * @param itemMeta the second item meta to check - * @return true if the two meta are similar, false otherwise - */ - public abstract boolean isSimilar(@NotNull ItemMeta itemMeta); - - /** - * Reads nbt data from a compound. - *

- * WARNING: it is possible that it contains no useful data, - * it has to be checked before getting anything. - * - * @param compound the compound containing the data - */ - public abstract void read(@NotNull NBTCompound compound); - - /** - * Writes nbt data to a compound. - * - * @param compound the compound receiving the item meta data - */ - public abstract void write(@NotNull NBTCompound compound); - - /** - * {@inheritDoc} - */ - @NotNull - @Override - public ItemMeta clone() { - try { - return (ItemMeta) super.clone(); - } catch (CloneNotSupportedException e) { - MinecraftServer.getExceptionManager().handleException(e); - throw new IllegalStateException("Weird thing happened"); - } - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/LeatherArmorMeta.java b/src/main/java/net/minestom/server/item/metadata/LeatherArmorMeta.java deleted file mode 100644 index 0926074aa..000000000 --- a/src/main/java/net/minestom/server/item/metadata/LeatherArmorMeta.java +++ /dev/null @@ -1,175 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.chat.ChatColor; -import net.minestom.server.color.Color; -import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; - -/** - * Represents the item meta for leather armor parts. - */ -public class LeatherArmorMeta extends ItemMeta { - private boolean modified; - private Color color; - - /** - * Sets the color of the leather armor piece. - * - * @param color the color of the leather armor - * @deprecated Use {@link #setColor(Color)} - */ - @Deprecated - public void setColor(ChatColor color) { - this.setColor(color.asColor()); - } - - /** - * Changes the color of the leather armor piece. - * - * @param red The red color of the leather armor piece. - * @param green The green color of the leather armor piece. - * @param blue The blue color of the leather armor piece. - * @deprecated Use {@link #setColor(Color)} - */ - @Deprecated - public void setColor(byte red, byte green, byte blue) { - this.setColor(new Color(red, green, blue)); - } - - /** - * Sets the color of this leather armor piece. - * - * @param color the new color - */ - public void setColor(@NotNull Color color) { - this.modified = !color.equals(this.color); - this.color = color; - } - - /** - * Gets the color of this leather armor piece. - * - * @return the color - */ - public @NotNull Color getColor() { - return this.color; - } - - /** - * Resets the color to the default leather one. - */ - public void reset() { - this.color = new Color(0, 0, 0); - this.modified = false; - } - - /** - * Gets the red component. - * - * @return the red component - * @deprecated Use {@link #getColor} - */ - @Deprecated - public int getRed() { - return this.color.getRed(); - } - - /** - * Gets the green component. - * - * @return the green component - * @deprecated Use {@link #getColor} - */ - @Deprecated - public int getGreen() { - return this.color.getGreen(); - } - - /** - * Gets the blue component. - * - * @return the blue component - * @deprecated Use {@link #getColor} - */ - @Deprecated - public int getBlue() { - return this.color.getBlue(); - } - - /** - * Gets if the color of this armor piece have been changed. - * - * @return true if the color has been changed, false otherwise - */ - public boolean isModified() { - return modified; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasNbt() { - return modified; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof LeatherArmorMeta)) return false; - final LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) itemMeta; - return leatherArmorMeta.isModified() == isModified() - && leatherArmorMeta.getColor().equals(getColor()); - } - - /** - * {@inheritDoc} - */ - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("display")) { - final NBTCompound nbtCompound = compound.getCompound("display"); - if (nbtCompound.containsKey("color")) { - final int color = nbtCompound.getInt("color"); - - // Sets the color of the leather armor piece - // This also fixes that the armor pieces do not decolorize again when you are in creative - // mode. - this.setColor(new Color(color)); - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public void write(@NotNull NBTCompound compound) { - if (modified) { - NBTCompound displayCompound; - if (!compound.containsKey("display")) { - displayCompound = new NBTCompound(); - } else { - displayCompound = compound.getCompound("display"); - } - displayCompound.setInt("color", color.asRGB()); - // Adds the color compound to the display compound - compound.set("display", displayCompound); - } - } - - /** - * {@inheritDoc} - */ - @NotNull - @Override - public ItemMeta clone() { - LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) super.clone(); - leatherArmorMeta.modified = this.isModified(); - leatherArmorMeta.color = color; - - return leatherArmorMeta; - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/MapMeta.java b/src/main/java/net/minestom/server/item/metadata/MapMeta.java deleted file mode 100644 index 7fef87752..000000000 --- a/src/main/java/net/minestom/server/item/metadata/MapMeta.java +++ /dev/null @@ -1,300 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.chat.ChatColor; -import net.minestom.server.color.Color; -import net.minestom.server.utils.clone.CloneUtils; -import net.minestom.server.utils.clone.PublicCloneable; -import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTList; -import org.jglrxavpok.hephaistos.nbt.NBTTypes; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -public class MapMeta extends ItemMeta { - - private int mapId; - private int mapScaleDirection = 1; - private List decorations = new CopyOnWriteArrayList<>(); - private Color mapColor = new Color(0, 0, 0); - - public MapMeta() { - } - - public MapMeta(int id) { - this.mapId = id; - } - - /** - * Gets the map id. - * - * @return the map id - */ - public int getMapId() { - return mapId; - } - - /** - * Changes the map id. - * - * @param mapId the new map id - */ - public void setMapId(int mapId) { - this.mapId = mapId; - } - - /** - * Gets the map scale direction. - * - * @return the map scale direction - */ - public int getMapScaleDirection() { - return mapScaleDirection; - } - - /** - * Changes the map scale direction. - * - * @param mapScaleDirection the new map scale direction - */ - public void setMapScaleDirection(int mapScaleDirection) { - this.mapScaleDirection = mapScaleDirection; - } - - /** - * Gets the map decorations. - * - * @return a modifiable list containing all the map decorations - */ - public List getDecorations() { - return decorations; - } - - /** - * Changes the map decorations list. - * - * @param decorations the new map decorations list - */ - public void setDecorations(List decorations) { - this.decorations = decorations; - } - - /** - * Gets the map color. - * - * @return the map color - * @deprecated Use {@link #getMapColor()} - */ - @Deprecated - public ChatColor getLegacyMapColor() { - return this.mapColor.asLegacyChatColor(); - } - - /** - * Gets the map color. - * - * @return the map color - */ - public @NotNull Color getMapColor() { - return this.mapColor; - } - - /** - * Changes the map color. - * - * @param mapColor the new map color - * @deprecated Use {@link #setMapColor(Color)} - */ - @Deprecated - public void setMapColor(ChatColor mapColor) { - this.setMapColor(mapColor.asColor()); - } - - /** - * Changes the map color. - * - * @param color the new map color - */ - public void setMapColor(@NotNull Color color) { - this.mapColor = color; - } - - @Override - public boolean hasNbt() { - return true; - } - - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof MapMeta)) - return false; - - final MapMeta mapMeta = (MapMeta) itemMeta; - return mapMeta.mapId == mapId && - mapMeta.mapScaleDirection == mapScaleDirection && - mapMeta.decorations.equals(decorations) && - mapMeta.mapColor == mapColor; - } - - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("map")) { - this.mapId = compound.getAsInt("map"); - } - - if (compound.containsKey("map_scale_direction")) { - this.mapScaleDirection = compound.getAsInt("map_scale_direction"); - } - - if (compound.containsKey("Decorations")) { - final NBTList decorationsList = compound.getList("Decorations"); - for (NBTCompound decorationCompound : decorationsList) { - final String id = decorationCompound.getString("id"); - final byte type = decorationCompound.getAsByte("type"); - byte x = 0; - - if (decorationCompound.containsKey("x")) { - x = decorationCompound.getAsByte("x"); - } - - byte z = 0; - if (decorationCompound.containsKey("z")) { - z = decorationCompound.getAsByte("z"); - } - - double rotation = 0.0; - if (decorationCompound.containsKey("rot")) { - rotation = decorationCompound.getAsDouble("rot"); - } - - this.decorations.add(new MapDecoration(id, type, x, z, rotation)); - } - } - - if (compound.containsKey("display")) { - final NBTCompound displayCompound = compound.getCompound("display"); - if (displayCompound.containsKey("MapColor")) { - this.mapColor = new Color(displayCompound.getAsInt("MapColor")); - } - } - - } - - @Override - public void write(@NotNull NBTCompound compound) { - compound.setInt("map", mapId); - - compound.setInt("map_scale_direction", mapScaleDirection); - - if (!decorations.isEmpty()) { - NBTList decorationsList = new NBTList<>(NBTTypes.TAG_Compound); - for (MapDecoration decoration : decorations) { - NBTCompound decorationCompound = new NBTCompound(); - decorationCompound.setString("id", decoration.getId()); - decorationCompound.setByte("type", decoration.getType()); - decorationCompound.setByte("x", decoration.getX()); - decorationCompound.setByte("z", decoration.getZ()); - decorationCompound.setDouble("rot", decoration.getRotation()); - - decorationsList.add(decorationCompound); - } - compound.set("Decorations", decorationsList); - } - - { - NBTCompound displayCompound; - if (compound.containsKey("display")) { - displayCompound = compound.getCompound("display"); - } else { - displayCompound = new NBTCompound(); - } - displayCompound.setInt("MapColor", mapColor.asRGB()); - } - } - - @NotNull - @Override - public ItemMeta clone() { - MapMeta mapMeta = (MapMeta) super.clone(); - mapMeta.setMapId(mapId); - mapMeta.setMapScaleDirection(mapScaleDirection); - mapMeta.decorations = CloneUtils.cloneCopyOnWriteArrayList(decorations); - mapMeta.setMapColor(mapColor); - return mapMeta; - } - - public static class MapDecoration implements PublicCloneable { - private final String id; - private final byte type; - private final byte x, z; - private final double rotation; - - public MapDecoration(@NotNull String id, byte type, byte x, byte z, double rotation) { - this.id = id; - this.type = type; - this.x = x; - this.z = z; - this.rotation = rotation; - } - - /** - * Gets the arbitrary decoration id. - * - * @return the decoration id - */ - public String getId() { - return id; - } - - /** - * Gets the decoration type. - * - * @return the decoration type - * @see Map icons - */ - public byte getType() { - return type; - } - - /** - * Gets the X position of the decoration. - * - * @return the X position - */ - public byte getX() { - return x; - } - - /** - * Gets the Z position of the decoration. - * - * @return the Z position - */ - public byte getZ() { - return z; - } - - /** - * Gets the rotation of the symbol (0;360). - * - * @return the rotation of the symbol - */ - public double getRotation() { - return rotation; - } - - @NotNull - @Override - public MapDecoration clone() { - try { - return (MapDecoration) super.clone(); - } catch (CloneNotSupportedException e) { - MinecraftServer.getExceptionManager().handleException(e); - throw new IllegalStateException("Something weird happened"); - } - } - } - -} diff --git a/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java b/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java deleted file mode 100644 index 18f1ae07e..000000000 --- a/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java +++ /dev/null @@ -1,161 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.entity.Player; -import net.minestom.server.entity.PlayerSkin; -import net.minestom.server.utils.Utils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTList; -import org.jglrxavpok.hephaistos.nbt.NBTTypes; - -import java.util.UUID; - -/** - * Represents a skull that can have an owner. - */ -public class PlayerHeadMeta extends ItemMeta { - - private UUID skullOwner; - private PlayerSkin playerSkin; - - /** - * Sets the owner of the skull. - * - * @param player The new owner of the skull. - * @return {@code true} if the owner was successfully set, otherwise {@code false}. - */ - public boolean setOwningPlayer(@NotNull Player player) { - if (player.getSkin() != null) { - this.skullOwner = player.getUuid(); - this.playerSkin = player.getSkin(); - return true; - } - return false; - } - - /** - * Retrieves the owner of the head. - * - * @return The head's owner. - */ - @Nullable - public UUID getSkullOwner() { - return skullOwner; - } - - /** - * Changes the owner of the head. - * - * @param skullOwner The new head owner. - */ - public void setSkullOwner(@NotNull UUID skullOwner) { - this.skullOwner = skullOwner; - } - - /** - * Retrieves the skin of the head. - * - * @return The head's skin. - */ - @Nullable - public PlayerSkin getPlayerSkin() { - return playerSkin; - } - - /** - * Changes the skin of the head. - * - * @param playerSkin The new skin for the head. - */ - public void setPlayerSkin(@NotNull PlayerSkin playerSkin) { - this.playerSkin = playerSkin; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasNbt() { - return this.skullOwner != null || playerSkin != null; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof PlayerHeadMeta)) - return false; - final PlayerHeadMeta playerHeadMeta = (PlayerHeadMeta) itemMeta; - return playerHeadMeta.playerSkin == playerSkin; - } - - /** - * {@inheritDoc} - */ - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("SkullOwner")) { - NBTCompound skullOwnerCompound = compound.getCompound("SkullOwner"); - - if (skullOwnerCompound.containsKey("Id")) { - this.skullOwner = Utils.intArrayToUuid(skullOwnerCompound.getIntArray("Id")); - } - - if (skullOwnerCompound.containsKey("Properties")) { - NBTCompound propertyCompound = skullOwnerCompound.getCompound("Properties"); - - if (propertyCompound.containsKey("textures")) { - NBTList textures = propertyCompound.getList("textures"); - if (textures != null) { - NBTCompound nbt = textures.get(0); - this.playerSkin = new PlayerSkin(nbt.getString("Value"), nbt.getString("Signature")); - } - } - - } - - } - } - - /** - * {@inheritDoc} - */ - @Override - public void write(@NotNull NBTCompound compound) { - NBTCompound skullOwnerCompound = new NBTCompound(); - // Sets the identifier for the skull - if (this.skullOwner != null) - skullOwnerCompound.setIntArray("Id", Utils.uuidToIntArray(this.skullOwner)); - - if (this.playerSkin == null && this.skullOwner != null) { - this.playerSkin = PlayerSkin.fromUuid(this.skullOwner.toString()); - } - - if (this.playerSkin != null) { - NBTList textures = new NBTList<>(NBTTypes.TAG_Compound); - String value = this.playerSkin.getTextures() == null ? "" : this.playerSkin.getTextures(); - String signature = this.playerSkin.getSignature() == null ? "" : this.playerSkin.getSignature(); - textures.add(new NBTCompound().setString("Value", value).setString("Signature", signature)); - skullOwnerCompound.set("Properties", new NBTCompound().set("textures", textures)); - } - - compound.set("SkullOwner", skullOwnerCompound); - - } - - /** - * {@inheritDoc} - */ - @NotNull - @Override - public ItemMeta clone() { - PlayerHeadMeta playerHeadMeta = (PlayerHeadMeta) super.clone(); - playerHeadMeta.skullOwner = this.skullOwner; - playerHeadMeta.playerSkin = this.playerSkin; - return playerHeadMeta; - } - - -} diff --git a/src/main/java/net/minestom/server/item/metadata/PotionMeta.java b/src/main/java/net/minestom/server/item/metadata/PotionMeta.java deleted file mode 100644 index 7ad2b281b..000000000 --- a/src/main/java/net/minestom/server/item/metadata/PotionMeta.java +++ /dev/null @@ -1,166 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.chat.ChatColor; -import net.minestom.server.color.Color; -import net.minestom.server.potion.CustomPotionEffect; -import net.minestom.server.potion.PotionType; -import net.minestom.server.registry.Registries; -import net.minestom.server.utils.clone.CloneUtils; -import net.minestom.server.utils.time.TimeUnit; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTList; -import org.jglrxavpok.hephaistos.nbt.NBTTypes; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * ItemStack meta for - * {@link net.minestom.server.item.Material#POTION}, - * {@link net.minestom.server.item.Material#LINGERING_POTION}, - * {@link net.minestom.server.item.Material#SPLASH_POTION}, - * {@link net.minestom.server.item.Material#TIPPED_ARROW}. - */ -public class PotionMeta extends ItemMeta { - - private PotionType potionType; - - // Not final because of #clone() - private List customPotionEffects = new CopyOnWriteArrayList<>(); - - private Color color; - - /** - * Gets the potion type. - * - * @return the potion type - */ - @Nullable - public PotionType getPotionType() { - return potionType; - } - - /** - * Changes the potion type. - * - * @param potionType the new potion type - */ - public void setPotionType(@Nullable PotionType potionType) { - this.potionType = potionType; - } - - /** - * Get a list of {@link CustomPotionEffect}. - * - * @return the custom potion effect list - */ - @NotNull - public List getCustomPotionEffects() { - return customPotionEffects; - } - - /** - * Changes the color of the potion. - * - * @param color the new color of the potion - * @deprecated Use {@link #setColor(Color)} - */ - @Deprecated - public void setColor(ChatColor color) { - this.setColor(color.asColor()); - } - - /** - * Changes the color of the potion. - * - * @param color the new color of the potion - */ - public void setColor(@Nullable Color color) { - this.color = color; - } - - @Override - public boolean hasNbt() { - return potionType != null || - !customPotionEffects.isEmpty(); - } - - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof PotionMeta)) - return false; - PotionMeta potionMeta = (PotionMeta) itemMeta; - return potionMeta.potionType == potionType && - potionMeta.customPotionEffects.equals(customPotionEffects) && - potionMeta.color.equals(color); - } - - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("Potion")) { - this.potionType = Registries.getPotionType(compound.getString("Potion")); - } - - if (compound.containsKey("CustomPotionEffects")) { - NBTList customEffectList = compound.getList("CustomPotionEffects"); - for (NBTCompound potionCompound : customEffectList) { - final byte id = potionCompound.getAsByte("Id"); - final byte amplifier = potionCompound.getAsByte("Amplifier"); - final int duration = potionCompound.containsKey("Duration") ? potionCompound.getNumber("Duration").intValue() : (int) TimeUnit.SECOND.toMilliseconds(30); - final boolean ambient = potionCompound.containsKey("Ambient") ? potionCompound.getAsByte("Ambient") == 1 : false; - final boolean showParticles = potionCompound.containsKey("ShowParticles") ? potionCompound.getAsByte("ShowParticles") == 1 : true; - final boolean showIcon = potionCompound.containsKey("ShowIcon") ? potionCompound.getAsByte("ShowIcon") == 1 : true; - - this.customPotionEffects.add( - new CustomPotionEffect(id, amplifier, duration, ambient, showParticles, showIcon)); - } - } - - if (compound.containsKey("CustomPotionColor")) { - this.color = new Color(compound.getInt("CustomPotionColor")); - } - } - - @Override - public void write(@NotNull NBTCompound compound) { - if (potionType != null) { - compound.setString("Potion", potionType.getNamespaceID()); - } - if (!customPotionEffects.isEmpty()) { - NBTList potionList = new NBTList<>(NBTTypes.TAG_Compound); - - for (CustomPotionEffect customPotionEffect : customPotionEffects) { - NBTCompound potionCompound = new NBTCompound(); - potionCompound.setByte("Id", customPotionEffect.getId()); - potionCompound.setByte("Amplifier", customPotionEffect.getAmplifier()); - potionCompound.setInt("Duration", customPotionEffect.getDuration()); - potionCompound.setByte("Ambient", (byte) (customPotionEffect.isAmbient() ? 1 : 0)); - potionCompound.setByte("ShowParticles", (byte) (customPotionEffect.showParticles() ? 1 : 0)); - potionCompound.setByte("ShowIcon", (byte) (customPotionEffect.showIcon() ? 1 : 0)); - - potionList.add(potionCompound); - } - - compound.set("CustomPotionEffects", potionList); - } - - if (color != null) { - compound.setInt("CustomPotionColor", color.asRGB()); - } - - } - - @NotNull - @Override - public ItemMeta clone() { - PotionMeta potionMeta = (PotionMeta) super.clone(); - potionMeta.potionType = potionType; - potionMeta.customPotionEffects = CloneUtils.cloneCopyOnWriteArrayList(customPotionEffects); - - potionMeta.color = color; - - return potionMeta; - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java b/src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java deleted file mode 100644 index 868298b1f..000000000 --- a/src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.minestom.server.entity.EntityType; -import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; - -// TODO for which item -public class SpawnEggMeta extends ItemMeta { - - private EntityType entityType; - - @Override - public boolean hasNbt() { - return entityType != null; - } - - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof SpawnEggMeta)) - return false; - final SpawnEggMeta spawnEggMeta = (SpawnEggMeta) itemMeta; - return spawnEggMeta.entityType == entityType; - } - - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("EntityTag")) { - // TODO - } - } - - @Override - public void write(@NotNull NBTCompound compound) { - if (!hasNbt()) - return; - NBTCompound entityCompound = new NBTCompound(); - if (entityType != null) { - entityCompound.setString("id", entityType.getNamespaceID()); - } - - } - - @NotNull - @Override - public ItemMeta clone() { - SpawnEggMeta spawnEggMeta = (SpawnEggMeta) super.clone(); - spawnEggMeta.entityType = entityType; - return spawnEggMeta; - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/WritableBookMeta.java b/src/main/java/net/minestom/server/item/metadata/WritableBookMeta.java deleted file mode 100644 index d5f36e001..000000000 --- a/src/main/java/net/minestom/server/item/metadata/WritableBookMeta.java +++ /dev/null @@ -1,120 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.minestom.server.adventure.AdventureSerializer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTList; -import org.jglrxavpok.hephaistos.nbt.NBTString; -import org.jglrxavpok.hephaistos.nbt.NBTTypes; - -import java.util.ArrayList; -import java.util.List; - -public class WritableBookMeta extends ItemMeta { - - private String title; - private String author; - private List pages = new ArrayList<>(); - - @Nullable - public String getTitle() { - return title; - } - - public void setTitle(@Nullable String title) { - this.title = title; - } - - @Nullable - public String getAuthor() { - return author; - } - - public void setAuthor(@Nullable String author) { - this.author = author; - } - - /** - * Gets an array list containing the book pages. - *

- * The list is modifiable. - * - * @return a modifiable {@link ArrayList} containing the book pages - */ - @NotNull - public List getPages() { - return pages; - } - - /** - * Sets the pages list of this book. - * - * @param pages the pages list - */ - public void setPages(@NotNull List pages) { - this.pages = pages; - } - - @Override - public boolean hasNbt() { - return !pages.isEmpty(); - } - - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof WritableBookMeta)) - return false; - final WritableBookMeta writableBookMeta = (WritableBookMeta) itemMeta; - return writableBookMeta.pages.equals(pages); - } - - @Override - public void read(@NotNull NBTCompound compound) { - - if (compound.containsKey("title")) { - this.title = compound.getString("title"); - } - - if (compound.containsKey("author")) { - this.author = compound.getString("author"); - } - - if (compound.containsKey("pages")) { - final NBTList list = compound.getList("pages"); - for (NBTString page : list) { - this.pages.add(GsonComponentSerializer.gson().deserialize(page.getValue())); - } - } - } - - @Override - public void write(@NotNull NBTCompound compound) { - - if (title != null) { - compound.setString("title", title); - } - - if (author != null) { - compound.setString("author", author); - } - - if (!pages.isEmpty()) { - NBTList list = new NBTList<>(NBTTypes.TAG_String); - for (Component page : pages) { - list.add(new NBTString(AdventureSerializer.serialize(page))); - } - compound.set("pages", list); - } - } - - @NotNull - @Override - public ItemMeta clone() { - WritableBookMeta writableBookMeta = (WritableBookMeta) super.clone(); - writableBookMeta.pages = new ArrayList<>(pages); - return writableBookMeta; - } -} diff --git a/src/main/java/net/minestom/server/item/metadata/WrittenBookMeta.java b/src/main/java/net/minestom/server/item/metadata/WrittenBookMeta.java deleted file mode 100644 index 48331d3c1..000000000 --- a/src/main/java/net/minestom/server/item/metadata/WrittenBookMeta.java +++ /dev/null @@ -1,221 +0,0 @@ -package net.minestom.server.item.metadata; - -import net.kyori.adventure.inventory.Book; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.minestom.server.adventure.AdventureSerializer; -import net.minestom.server.adventure.Localizable; -import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTList; -import org.jglrxavpok.hephaistos.nbt.NBTString; -import org.jglrxavpok.hephaistos.nbt.NBTTypes; - -import java.util.ArrayList; -import java.util.List; - -public class WrittenBookMeta extends ItemMeta { - - private boolean resolved; - private WrittenBookGeneration generation; - private String author; - private String title; - private List pages = new ArrayList<>(); - - /** - * Gets if the book is resolved. - * - * @return true if the book is resolved, false otherwise - */ - public boolean isResolved() { - return resolved; - } - - /** - * Sets to true when the book (or a book from the stack) - * is opened for the first time after being created. - * - * @param resolved true to make the book resolved, false otherwise - */ - public void setResolved(boolean resolved) { - this.resolved = resolved; - } - - /** - * Gets the copy tier of the book. - * - * @return the copy tier of the book - */ - public WrittenBookGeneration getGeneration() { - return generation; - } - - /** - * Sets the copy tier of the book. - * - * @param generation the copy tier of the book - */ - public void setGeneration(WrittenBookGeneration generation) { - this.generation = generation; - } - - /** - * Gets the author of the book. - * - * @return the author of the book - */ - public String getAuthor() { - return author; - } - - /** - * Sets the author of the book. - * - * @param author the author of the book - */ - public void setAuthor(String author) { - this.author = author; - } - - /** - * Gets the title of the book. - * - * @return the title of the book - */ - public String getTitle() { - return title; - } - - /** - * Sets the title of the book. - * - * @param title the title of the book - */ - public void setTitle(String title) { - this.title = title; - } - - /** - * Gets an {@link ArrayList} containing all the pages. - *

- * The list is not modifiable as it is . - * - * @return a modifiable {@link ArrayList} with the pages of the book - */ - @Deprecated - public List getPagesJson() { - return pages; - } - - /** - * Sets the {@link ArrayList} containing the book pages. - * - * @param pages the array list containing the book pages - */ - public void setPages(List pages) { - this.pages = pages; - } - - @Override - public boolean hasNbt() { - return resolved || generation != null || - author != null || title != null || - !pages.isEmpty(); - } - - @Override - public boolean isSimilar(@NotNull ItemMeta itemMeta) { - if (!(itemMeta instanceof WrittenBookMeta)) - return false; - final WrittenBookMeta writtenBookMeta = (WrittenBookMeta) itemMeta; - return writtenBookMeta.resolved == resolved && - writtenBookMeta.generation == generation && - writtenBookMeta.author.equals(author) && - writtenBookMeta.title.equals(title) && - writtenBookMeta.pages.equals(pages); - } - - @Override - public void read(@NotNull NBTCompound compound) { - if (compound.containsKey("resolved")) { - this.resolved = compound.getByte("resolved") == 1; - } - if (compound.containsKey("generation")) { - this.generation = WrittenBookGeneration.values()[compound.getInt("generation")]; - } - if (compound.containsKey("author")) { - this.author = compound.getString("author"); - } - if (compound.containsKey("title")) { - this.title = compound.getString("title"); - } - if (compound.containsKey("pages")) { - final NBTList list = compound.getList("pages"); - for (NBTString page : list) { - this.pages.add(GsonComponentSerializer.gson().deserialize(page.getValue())); - } - } - } - - @Override - public void write(@NotNull NBTCompound compound) { - if (resolved) { - compound.setByte("resolved", (byte) 1); - } - if (generation != null) { - compound.setInt("generation", generation.ordinal()); - } - if (author != null) { - compound.setString("author", author); - } - if (title != null) { - compound.setString("title", title); - } - if (!pages.isEmpty()) { - NBTList list = new NBTList<>(NBTTypes.TAG_String); - for (Component page : pages) { - list.add(new NBTString(AdventureSerializer.serialize(page))); - } - compound.set("pages", list); - } - } - - @NotNull - @Override - public ItemMeta clone() { - WrittenBookMeta writtenBookMeta = (WrittenBookMeta) super.clone(); - writtenBookMeta.resolved = resolved; - writtenBookMeta.generation = generation; - writtenBookMeta.author = author; - writtenBookMeta.title = title; - writtenBookMeta.pages.addAll(pages); - - return writtenBookMeta; - } - - public enum WrittenBookGeneration { - ORIGINAL, COPY_OF_ORIGINAL, COPY_OF_COPY, TATTERED - } - - /** - * Creates a written book meta from an Adventure book. This meta will not be - * resolved and the generation will default to {@link WrittenBookGeneration#ORIGINAL}. - * - * @param book the book - * @param localizable who the book is for - * - * @return the meta - */ - public static @NotNull WrittenBookMeta fromAdventure(@NotNull Book book, @NotNull Localizable localizable) { - // make the book - WrittenBookMeta meta = new WrittenBookMeta(); - meta.resolved = false; - meta.generation = WrittenBookGeneration.ORIGINAL; - meta.author = AdventureSerializer.translateAndSerialize(book.author(), localizable); - meta.title = AdventureSerializer.translateAndSerialize(book.title(), localizable); - meta.pages = new ArrayList<>(); - meta.pages.addAll(book.pages()); - - return meta; - } -} From 50ceeb33e4a05fb4cd950e7b7e6f7c6c5ab1afd1 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 06:03:48 +0200 Subject: [PATCH 57/77] Use proper meta based on material --- .../server/item/ItemStackBuilder.java | 52 +++++++++++++++++-- .../server/item/meta/EnchantedBookMeta.java | 5 +- .../minestom/server/item/meta/PotionMeta.java | 7 ++- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemStackBuilder.java b/src/main/java/net/minestom/server/item/ItemStackBuilder.java index f85a4581d..e6c95b7df 100644 --- a/src/main/java/net/minestom/server/item/ItemStackBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemStackBuilder.java @@ -1,13 +1,17 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; -import net.minestom.server.item.meta.CompassMeta; +import net.minestom.server.item.meta.*; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.function.UnaryOperator; public class ItemStackBuilder { @@ -24,9 +28,34 @@ public class ItemStackBuilder { this.storeBuilder = storeBuilder; } + private static final Map> MATERIAL_SUPPLIER_MAP = new ConcurrentHashMap<>(); + + static { + MATERIAL_SUPPLIER_MAP.put(Material.POTION, PotionMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.LINGERING_POTION, PotionMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.SPLASH_POTION, PotionMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.TIPPED_ARROW, PotionMeta.Builder::new); + + MATERIAL_SUPPLIER_MAP.put(Material.FILLED_MAP, MapMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.COMPASS, CompassMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.ENCHANTED_BOOK, EnchantedBookMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.CROSSBOW, CrossbowMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.WRITABLE_BOOK, WritableBookMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.WRITTEN_BOOK, WrittenBookMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.FIREWORK_STAR, FireworkEffectMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.FIREWORK_ROCKET, FireworkMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.PLAYER_HEAD, PlayerHeadMeta.Builder::new); + + MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_HELMET, LeatherArmorMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_CHESTPLATE, LeatherArmorMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_LEGGINGS, LeatherArmorMeta.Builder::new); + MATERIAL_SUPPLIER_MAP.put(Material.LEATHER_BOOTS, LeatherArmorMeta.Builder::new); + } + protected ItemStackBuilder(@NotNull Material material) { - // TODO: meta depends on material - this(material, new CompassMeta.Builder(), new ItemStoreBuilder()); + this(material, + MATERIAL_SUPPLIER_MAP.getOrDefault(material, DefaultMeta::new).get(), + new ItemStoreBuilder()); } @Contract(value = "_ -> this") @@ -88,4 +117,21 @@ public class ItemStackBuilder { return new ItemStack(material, amount, metaBuilder.build(), storeBuilder.build()); } + private static final class DefaultMeta extends ItemMetaBuilder { + @Override + public @NotNull ItemMeta build() { + return new ItemMeta(this); + } + + @Override + public void read(@NotNull NBTCompound nbtCompound) { + // Empty + } + + @Override + protected @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier() { + return DefaultMeta::new; + } + } + } diff --git a/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java b/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java index 6de4c48cd..28a36349e 100644 --- a/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java +++ b/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.NotNull; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; @@ -17,7 +18,7 @@ public class EnchantedBookMeta extends ItemMeta implements ItemMetaBuilder.Provi protected EnchantedBookMeta(@NotNull ItemMetaBuilder metaBuilder, Map storedEnchantmentMap) { super(metaBuilder); - this.storedEnchantmentMap = storedEnchantmentMap; + this.storedEnchantmentMap = new HashMap<>(storedEnchantmentMap); } /** @@ -32,7 +33,7 @@ public class EnchantedBookMeta extends ItemMeta implements ItemMetaBuilder.Provi public static class Builder extends ItemMetaBuilder { - private Map enchantments; + private Map enchantments = new HashMap<>(); public Builder enchantments(Map enchantments) { this.enchantments = enchantments; diff --git a/src/main/java/net/minestom/server/item/meta/PotionMeta.java b/src/main/java/net/minestom/server/item/meta/PotionMeta.java index 2d717367b..b2be6ba9e 100644 --- a/src/main/java/net/minestom/server/item/meta/PotionMeta.java +++ b/src/main/java/net/minestom/server/item/meta/PotionMeta.java @@ -13,7 +13,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.jglrxavpok.hephaistos.nbt.NBTList; import org.jglrxavpok.hephaistos.nbt.NBTTypes; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; @@ -28,7 +28,7 @@ public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider(customPotionEffects); this.color = color; } @@ -40,7 +40,6 @@ public class PotionMeta extends ItemMeta implements ItemMetaBuilder.Provider customPotionEffects; + private List customPotionEffects = new ArrayList<>(); private Color color; public Builder potionType(@NotNull PotionType potionType) { From d2efb43625d22fb5b772a4c128589173b72b2141 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 06:08:08 +0200 Subject: [PATCH 58/77] Improve immutability & prevent NPE --- .../net/minestom/server/item/ItemMetaBuilder.java | 4 ---- .../minestom/server/item/meta/FireworkMeta.java | 6 ++++-- .../server/item/meta/WritableBookMeta.java | 9 +++++---- .../minestom/server/item/meta/WrittenBookMeta.java | 14 ++++++++++---- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index fd631d702..2c1a98d56 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -61,7 +61,6 @@ public abstract class ItemMetaBuilder { @Contract("_ -> this") public @NotNull ItemMetaBuilder displayName(@Nullable Component displayName) { this.displayName = displayName; - handleCompound("display", nbtCompound -> { if (displayName != null) { final String name = AdventureSerializer.serialize(displayName); @@ -70,14 +69,12 @@ public abstract class ItemMetaBuilder { nbtCompound.removeTag("Name"); } }); - return this; } @Contract("_ -> this") public @NotNull ItemMetaBuilder lore(@NotNull List<@NotNull Component> lore) { this.lore = lore; - handleCompound("display", nbtCompound -> { final NBTList loreNBT = new NBTList<>(NBTTypes.TAG_String); for (Component line : lore) { @@ -85,7 +82,6 @@ public abstract class ItemMetaBuilder { } nbtCompound.set("Lore", loreNBT); }); - return this; } diff --git a/src/main/java/net/minestom/server/item/meta/FireworkMeta.java b/src/main/java/net/minestom/server/item/meta/FireworkMeta.java index 4ab915c02..baab018b3 100644 --- a/src/main/java/net/minestom/server/item/meta/FireworkMeta.java +++ b/src/main/java/net/minestom/server/item/meta/FireworkMeta.java @@ -8,6 +8,8 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.jglrxavpok.hephaistos.nbt.NBTList; import org.jglrxavpok.hephaistos.nbt.NBTTypes; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; @@ -20,12 +22,12 @@ public class FireworkMeta extends ItemMeta implements ItemMetaBuilder.Provider effects, byte flightDuration) { super(metaBuilder); - this.effects = effects; + this.effects = new ArrayList<>(effects); this.flightDuration = flightDuration; } public List getEffects() { - return effects; + return Collections.unmodifiableList(effects); } public byte getFlightDuration() { diff --git a/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java b/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java index e150d6739..cfeace3b5 100644 --- a/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java +++ b/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java @@ -11,6 +11,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTList; import org.jglrxavpok.hephaistos.nbt.NBTString; import org.jglrxavpok.hephaistos.nbt.NBTTypes; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Supplier; @@ -27,7 +28,7 @@ public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provid super(metaBuilder); this.author = author; this.title = title; - this.pages = Collections.unmodifiableList(pages); + this.pages = new ArrayList<>(pages); } public String getAuthor() { @@ -38,15 +39,15 @@ public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provid return title; } - public List getPages() { - return pages; + public @NotNull List<@NotNull Component> getPages() { + return Collections.unmodifiableList(pages); } public static class Builder extends ItemMetaBuilder { private String author; private String title; - private List pages; + private List pages = new ArrayList<>(); public Builder author(String author) { this.author = author; diff --git a/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java b/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java index 447fd143f..9e4ecb04b 100644 --- a/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java +++ b/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java @@ -13,6 +13,8 @@ import org.jglrxavpok.hephaistos.nbt.NBTList; import org.jglrxavpok.hephaistos.nbt.NBTString; import org.jglrxavpok.hephaistos.nbt.NBTTypes; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.Supplier; @@ -33,7 +35,7 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide this.generation = generation; this.author = author; this.title = title; - this.pages = Collections.unmodifiableList(pages); + this.pages = new ArrayList<>(pages); } public boolean isResolved() { @@ -52,8 +54,8 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide return title; } - public List getPages() { - return pages; + public @NotNull List<@NotNull Component> getPages() { + return Collections.unmodifiableList(pages); } public enum WrittenBookGeneration { @@ -84,7 +86,7 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide private WrittenBookGeneration generation; private String author; private String title; - private List pages; + private List pages = new ArrayList<>(); public Builder resolved(boolean resolved) { this.resolved = resolved; @@ -123,6 +125,10 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide return this; } + public Builder pages(Component... pages) { + return pages(Arrays.asList(pages)); + } + @Override public @NotNull WrittenBookMeta build() { return new WrittenBookMeta(this, resolved, generation, author, title, pages); From bd3c678bde699f1329ea97977d382107d10ef037 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 17:01:50 +0200 Subject: [PATCH 59/77] Add HoverEventSource to ItemStack --- .../net/minestom/server/chat/ChatHoverEvent.java | 6 +++--- src/main/java/net/minestom/server/item/ItemMeta.java | 8 ++++++++ .../java/net/minestom/server/item/ItemStack.java | 12 +++++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/chat/ChatHoverEvent.java b/src/main/java/net/minestom/server/chat/ChatHoverEvent.java index 162447c38..a288b5814 100644 --- a/src/main/java/net/minestom/server/chat/ChatHoverEvent.java +++ b/src/main/java/net/minestom/server/chat/ChatHoverEvent.java @@ -10,12 +10,12 @@ import net.minestom.server.entity.EntityType; import net.minestom.server.item.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; import java.util.UUID; /** * Represents a hover event for a specific portion of the message. + * * @deprecated Use {@link HoverEvent} */ @Deprecated @@ -93,8 +93,8 @@ public class ChatHoverEvent { JsonObject obj = GsonComponentSerializer.gson().serializer().toJsonTree(Component.empty().hoverEvent(event)).getAsJsonObject(); obj = obj.get("hoverEvent").getAsJsonObject().get("contents").getAsJsonObject(); - NBTCompound compound = itemStack.getMeta().toNBT(); - obj.add("tag", new JsonPrimitive(compound.toSNBT())); + final String snbt = itemStack.getMeta().toSNBT(); + obj.add("tag", new JsonPrimitive(snbt)); return new ChatHoverEvent("show_item", obj); } diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 7c02be9de..fd9fc58fb 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -30,6 +30,7 @@ public class ItemMeta implements Writeable { private final NBTCompound nbt; private final ItemMetaBuilder emptyBuilder; + private String cachedSNBT; private BinaryWriter cachedBuffer; protected ItemMeta(@NotNull ItemMetaBuilder metaBuilder) { @@ -110,6 +111,13 @@ public class ItemMeta implements Writeable { return nbt.deepClone(); } + public @NotNull String toSNBT() { + if (cachedSNBT == null) { + this.cachedSNBT = nbt.toSNBT(); + } + return cachedSNBT; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index 72a19d244..3f9fb5ede 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -1,7 +1,10 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.event.HoverEventSource; import net.minestom.server.item.rule.VanillaStackingRule; +import net.minestom.server.utils.NBTUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,7 +21,7 @@ import java.util.function.UnaryOperator; *

* An item stack cannot be null, {@link ItemStack#AIR} should be used instead. */ -public class ItemStack { +public class ItemStack implements HoverEventSource { /** * Constant AIR item. Should be used instead of 'null'. @@ -194,4 +197,11 @@ public class ItemStack { return new ItemStackBuilder(material, meta.builder(), store.builder()) .amount(amount); } + + @Override + public @NotNull HoverEvent asHoverEvent(@NotNull UnaryOperator op) { + return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.of(this.material, + this.amount, + NBTUtils.asBinaryTagHolder(this.meta.toNBT().getCompound("tag"))))); + } } From e81c31f61b77a3efa6373c0d319cc60a0a29ff97 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 17:47:45 +0200 Subject: [PATCH 60/77] Remove Ownership code --- .../net/minestom/server/entity/Player.java | 9 --- .../utils/ownership/OwnershipHandler.java | 59 ------------------- 2 files changed, 68 deletions(-) delete mode 100644 src/main/java/net/minestom/server/utils/ownership/OwnershipHandler.java diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index b0b754429..60d1b3aba 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -588,15 +588,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable, } } - // ItemStack ownership cache - { - ItemStack[] itemStacks = inventory.getItemStacks(); - for (ItemStack itemStack : itemStacks) { - // FIXME: item data - //ItemStack.DATA_OWNERSHIP.clearCache(itemStack.getIdentifier()); - } - } - // Clear all viewable entities this.viewableEntities.forEach(entity -> entity.removeViewer(this)); // Clear all viewable chunks diff --git a/src/main/java/net/minestom/server/utils/ownership/OwnershipHandler.java b/src/main/java/net/minestom/server/utils/ownership/OwnershipHandler.java deleted file mode 100644 index 7cfdfca08..000000000 --- a/src/main/java/net/minestom/server/utils/ownership/OwnershipHandler.java +++ /dev/null @@ -1,59 +0,0 @@ -package net.minestom.server.utils.ownership; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Convenient class to keep trace of objects linked to an {@link UUID}. - * - * @param the owned object type - */ -public class OwnershipHandler { - - // identifier = the object having an ownership - private ConcurrentHashMap ownershipDataMap = new ConcurrentHashMap<>(); - - /** - * Generates a new unique identifier. - *

- * Does call {@link UUID#randomUUID()} internally. - * - * @return a new generated identifier - */ - public UUID generateIdentifier() { - return UUID.randomUUID(); - } - - /** - * Retrieves the owned object based on its identifier. - * - * @param identifier the object identifier - * @return the own object, null if not found - */ - @Nullable - public T getOwnObject(@NotNull UUID identifier) { - return ownershipDataMap.get(identifier); - } - - /** - * Saves, replace or remove the own object of an identifier. - * - * @param identifier the identifier of the object - * @param value the value of the object, can override the previous value, null means removing the identifier - */ - public void saveOwnObject(@NotNull UUID identifier, @Nullable T value) { - if (value != null) { - this.ownershipDataMap.put(identifier, value); - } else { - clearCache(identifier); - } - } - - public void clearCache(@NotNull UUID identifier) { - this.ownershipDataMap.remove(identifier); - } - -} From 0619b1b14b41cd6b789012b819b9c5c0521adf36 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 18:36:20 +0200 Subject: [PATCH 61/77] Fix immutability inside ItemMeta --- src/main/java/net/minestom/server/item/ItemMeta.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index fd9fc58fb..39b282dae 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -9,7 +9,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import java.util.Collections; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -38,9 +39,9 @@ public class ItemMeta implements Writeable { this.unbreakable = metaBuilder.unbreakable; this.hideFlag = metaBuilder.hideFlag; this.displayName = metaBuilder.displayName; - this.lore = Collections.unmodifiableList(metaBuilder.lore); - this.enchantmentMap = Collections.unmodifiableMap(metaBuilder.enchantmentMap); - this.attributes = Collections.unmodifiableList(metaBuilder.attributes); + this.lore = new ArrayList<>(metaBuilder.lore); + this.enchantmentMap = new HashMap<>(metaBuilder.enchantmentMap); + this.attributes = new ArrayList<>(metaBuilder.attributes); this.customModelData = metaBuilder.customModelData; this.nbt = metaBuilder.nbt; From 0be4c6d8c729e9bab03d33f257f2761de7e9bf2a Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 10 Apr 2021 18:55:26 +0200 Subject: [PATCH 62/77] More meta utils method, fix openBook --- .../net/minestom/server/entity/Player.java | 13 ++--- .../minestom/server/item/ItemMetaBuilder.java | 53 ++++++++++++++----- .../server/item/meta/EnchantedBookMeta.java | 4 +- .../server/item/meta/WritableBookMeta.java | 35 ++++++------ .../server/item/meta/WrittenBookMeta.java | 52 +++++++++--------- 5 files changed, 95 insertions(+), 62 deletions(-) diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 60d1b3aba..7b49c2159 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -42,6 +42,7 @@ import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.item.meta.WrittenBookMeta; import net.minestom.server.listener.PlayerDiggingListener; import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionState; @@ -67,6 +68,7 @@ import net.minestom.server.utils.chunk.ChunkCallback; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.entity.EntityUtils; import net.minestom.server.utils.instance.InstanceUtils; +import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.time.Cooldown; import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.time.UpdateOption; @@ -1100,15 +1102,14 @@ public class Player extends LivingEntity implements CommandSender, Localizable, @Override public void openBook(@NotNull Book book) { - // make the book - ItemStack writtenBook = ItemStack.of(Material.WRITTEN_BOOK); - // TODO: WRITTEN_BOOK meta - //writtenBook.setItemMeta(WrittenBookMeta.fromAdventure(book, this)); + ItemStack writtenBook = ItemStack.builder(Material.WRITTEN_BOOK) + .meta(WrittenBookMeta.fromAdventure(book, this)) + .build(); // Set book in offhand SetSlotPacket setBookPacket = new SetSlotPacket(); setBookPacket.windowId = 0; - setBookPacket.slot = 45; + setBookPacket.slot = PlayerInventoryUtils.OFFHAND_SLOT; setBookPacket.itemStack = writtenBook; playerConnection.sendPacket(setBookPacket); @@ -1120,7 +1121,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, // Restore the item in offhand SetSlotPacket restoreItemPacket = new SetSlotPacket(); restoreItemPacket.windowId = 0; - restoreItemPacket.slot = 45; + restoreItemPacket.slot = PlayerInventoryUtils.OFFHAND_SLOT; restoreItemPacket.itemStack = getItemInOffHand(); playerConnection.sendPacket(restoreItemPacket); } diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 2c1a98d56..b70d99b5c 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -94,13 +94,10 @@ public abstract class ItemMetaBuilder { @Contract("_ -> this") public @NotNull ItemMetaBuilder enchantments(@NotNull Map enchantments) { this.enchantmentMap = enchantments; - - if (!enchantmentMap.isEmpty()) { + handleMap(enchantmentMap, "Enchantments", nbt, () -> { NBTUtils.writeEnchant(nbt, "Enchantments", enchantmentMap); - } else { - this.nbt.removeTag("Enchantments"); - } - + return nbt.get("Enchantments"); + }); return this; } @@ -114,6 +111,7 @@ public abstract class ItemMetaBuilder { @Contract("-> this") public @NotNull ItemMetaBuilder clearEnchantment() { this.enchantmentMap.clear(); + enchantments(enchantmentMap); return this; } @@ -121,10 +119,8 @@ public abstract class ItemMetaBuilder { public @NotNull ItemMetaBuilder attributes(@NotNull List<@NotNull ItemAttribute> attributes) { this.attributes = attributes; - - if (!attributes.isEmpty()) { + handleCollection(attributes, "AttributeModifiers", nbt, () -> { NBTList attributesNBT = new NBTList<>(NBTTypes.TAG_Compound); - for (ItemAttribute itemAttribute : attributes) { final UUID uuid = itemAttribute.getUuid(); attributesNBT.add( @@ -137,10 +133,8 @@ public abstract class ItemMetaBuilder { .setString("Name", itemAttribute.getInternalName()) ); } - this.nbt.set("AttributeModifiers", attributesNBT); - } else { - this.nbt.removeTag("AttributeModifiers"); - } + return attributesNBT; + }); return this; } @@ -194,6 +188,39 @@ public abstract class ItemMetaBuilder { } } + protected void handleNullable(@Nullable Object value, + @NotNull String key, + @NotNull NBTCompound nbtCompound, + @NotNull Supplier<@NotNull NBT> supplier) { + if (value != null) { + nbtCompound.set(key, supplier.get()); + } else { + nbtCompound.removeTag(key); + } + } + + protected void handleCollection(@NotNull Collection objects, + @NotNull String key, + @NotNull NBTCompound nbtCompound, + @NotNull Supplier<@NotNull NBT> supplier) { + if (!objects.isEmpty()) { + nbtCompound.set(key, supplier.get()); + } else { + nbtCompound.removeTag(key); + } + } + + protected void handleMap(@NotNull Map objects, + @NotNull String key, + @NotNull NBTCompound nbtCompound, + @NotNull Supplier<@NotNull NBT> supplier) { + if (!objects.isEmpty()) { + nbtCompound.set(key, supplier.get()); + } else { + nbtCompound.removeTag(key); + } + } + @Contract(value = "_, _ -> new", pure = true) public static @NotNull ItemMetaBuilder fromNBT(@NotNull ItemMetaBuilder src, @NotNull NBTCompound nbtCompound) { ItemMetaBuilder dest = src.getSupplier().get(); diff --git a/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java b/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java index 28a36349e..4853b7a38 100644 --- a/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java +++ b/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java @@ -35,13 +35,13 @@ public class EnchantedBookMeta extends ItemMeta implements ItemMetaBuilder.Provi private Map enchantments = new HashMap<>(); - public Builder enchantments(Map enchantments) { + public @NotNull Builder enchantments(Map enchantments) { this.enchantments = enchantments; NBTUtils.writeEnchant(nbt, "StoredEnchantments", enchantments); return this; } - public Builder enchantment(Enchantment enchantment, short level) { + public @NotNull Builder enchantment(Enchantment enchantment, short level) { this.enchantments.put(enchantment, level); enchantments(enchantments); return this; diff --git a/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java b/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java index cfeace3b5..a2cf89b0b 100644 --- a/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java +++ b/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java @@ -6,6 +6,7 @@ import net.minestom.server.adventure.AdventureSerializer; import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemMetaBuilder; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.jglrxavpok.hephaistos.nbt.NBTList; import org.jglrxavpok.hephaistos.nbt.NBTString; @@ -14,6 +15,7 @@ import org.jglrxavpok.hephaistos.nbt.NBTTypes; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.function.Supplier; public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provider { @@ -23,19 +25,19 @@ public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provid private final List pages; protected WritableBookMeta(@NotNull ItemMetaBuilder metaBuilder, - String author, String title, - List pages) { + @Nullable String author, @Nullable String title, + @NotNull List<@NotNull Component> pages) { super(metaBuilder); this.author = author; this.title = title; this.pages = new ArrayList<>(pages); } - public String getAuthor() { + public @Nullable String getAuthor() { return author; } - public String getTitle() { + public @Nullable String getTitle() { return title; } @@ -49,27 +51,30 @@ public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provid private String title; private List pages = new ArrayList<>(); - public Builder author(String author) { + public Builder author(@Nullable String author) { this.author = author; - this.nbt.setString("author", author); + handleNullable(author, "author", nbt, + () -> new NBTString(Objects.requireNonNull(author))); return this; } - public Builder title(String title) { + public Builder title(@Nullable String title) { this.title = title; - this.nbt.setString("title", author); + handleNullable(title, "title", nbt, + () -> new NBTString(Objects.requireNonNull(title))); return this; } - public Builder pages(List pages) { + public Builder pages(@NotNull List<@NotNull Component> pages) { this.pages = pages; - this.nbt.setString("title", author); - NBTList list = new NBTList<>(NBTTypes.TAG_String); - for (Component page : pages) { - list.add(new NBTString(AdventureSerializer.serialize(page))); - } - this.nbt.set("pages", list); + handleCollection(pages, "pages", nbt, () -> { + NBTList list = new NBTList<>(NBTTypes.TAG_String); + for (Component page : pages) { + list.add(new NBTString(AdventureSerializer.serialize(page))); + } + return list; + }); return this; } diff --git a/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java b/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java index 9e4ecb04b..3645645ff 100644 --- a/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java +++ b/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java @@ -8,15 +8,10 @@ import net.minestom.server.adventure.Localizable; import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemMetaBuilder; import org.jetbrains.annotations.NotNull; -import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import org.jglrxavpok.hephaistos.nbt.NBTList; -import org.jglrxavpok.hephaistos.nbt.NBTString; -import org.jglrxavpok.hephaistos.nbt.NBTTypes; +import org.jetbrains.annotations.Nullable; +import org.jglrxavpok.hephaistos.nbt.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.function.Supplier; public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provider { @@ -28,8 +23,9 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide private final List pages; protected WrittenBookMeta(@NotNull ItemMetaBuilder metaBuilder, boolean resolved, - WrittenBookGeneration generation, String author, String title, - List pages) { + @Nullable WrittenBookGeneration generation, + @Nullable String author, @Nullable String title, + @NotNull List<@NotNull Component> pages) { super(metaBuilder); this.resolved = resolved; this.generation = generation; @@ -42,15 +38,15 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide return resolved; } - public WrittenBookGeneration getGeneration() { + public @Nullable WrittenBookGeneration getGeneration() { return generation; } - public String getAuthor() { + public @Nullable String getAuthor() { return author; } - public String getTitle() { + public @Nullable String getTitle() { return title; } @@ -94,33 +90,37 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide return this; } - public Builder generation(WrittenBookGeneration generation) { + public Builder generation(@Nullable WrittenBookGeneration generation) { this.generation = generation; - this.nbt.setInt("generation", generation.ordinal()); + handleNullable(generation, "generation", nbt, + () -> new NBTInt(Objects.requireNonNull(generation).ordinal())); return this; } - public Builder author(String author) { + public Builder author(@Nullable String author) { this.author = author; - this.nbt.setString("author", author); + handleNullable(author, "author", nbt, + () -> new NBTString(Objects.requireNonNull(author))); return this; } - public Builder title(String title) { + public Builder title(@Nullable String title) { this.title = title; - this.nbt.setString("title", author); + handleNullable(title, "title", nbt, + () -> new NBTString(Objects.requireNonNull(title))); return this; } - public Builder pages(List pages) { + public Builder pages(@NotNull List<@NotNull Component> pages) { this.pages = pages; - this.nbt.setString("title", author); - NBTList list = new NBTList<>(NBTTypes.TAG_String); - for (Component page : pages) { - list.add(new NBTString(AdventureSerializer.serialize(page))); - } - this.nbt.set("pages", list); + handleCollection(pages, "pages", nbt, () -> { + NBTList list = new NBTList<>(NBTTypes.TAG_String); + for (Component page : pages) { + list.add(new NBTString(AdventureSerializer.serialize(page))); + } + return list; + }); return this; } From e0c2c4b6552ee3d51102510291a5e0f84221c9e5 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 11 Apr 2021 00:42:09 +0200 Subject: [PATCH 63/77] Support for canPlace & canDestroy meta --- .../net/minestom/server/item/ItemMeta.java | 29 +++++++++---- .../minestom/server/item/ItemMetaBuilder.java | 27 ++++++++++++ .../listener/BlockPlacementListener.java | 4 +- .../listener/PlayerDiggingListener.java | 6 +-- .../net/minestom/server/utils/NBTUtils.java | 42 ++++++++----------- src/test/java/demo/PlayerInit.java | 8 +++- 6 files changed, 78 insertions(+), 38 deletions(-) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index 39b282dae..e859813ad 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -1,6 +1,7 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; +import net.minestom.server.instance.block.Block; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.Writeable; @@ -9,10 +10,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Consumer; public class ItemMeta implements Writeable { @@ -28,6 +26,9 @@ public class ItemMeta implements Writeable { private final int customModelData; + private final Set canDestroy; + private final Set canPlaceOn; + private final NBTCompound nbt; private final ItemMetaBuilder emptyBuilder; @@ -43,6 +44,8 @@ public class ItemMeta implements Writeable { this.enchantmentMap = new HashMap<>(metaBuilder.enchantmentMap); this.attributes = new ArrayList<>(metaBuilder.attributes); this.customModelData = metaBuilder.customModelData; + this.canDestroy = new HashSet<>(metaBuilder.canDestroy); + this.canPlaceOn = new HashSet<>(metaBuilder.canPlaceOn); this.nbt = metaBuilder.nbt; this.emptyBuilder = metaBuilder.getSupplier().get(); @@ -77,17 +80,17 @@ public class ItemMeta implements Writeable { @Contract(pure = true) public @NotNull List<@NotNull Component> getLore() { - return lore; + return Collections.unmodifiableList(lore); } @Contract(pure = true) public @NotNull Map getEnchantmentMap() { - return enchantmentMap; + return Collections.unmodifiableMap(enchantmentMap); } @Contract(pure = true) - public @NotNull List getAttributes() { - return attributes; + public @NotNull List<@NotNull ItemAttribute> getAttributes() { + return Collections.unmodifiableList(attributes); } @Contract(pure = true) @@ -95,6 +98,16 @@ public class ItemMeta implements Writeable { return customModelData; } + @Contract(pure = true) + public @NotNull Set<@NotNull Block> getCanDestroy() { + return Collections.unmodifiableSet(canDestroy); + } + + @Contract(pure = true) + public @NotNull Set<@NotNull Block> getCanPlaceOn() { + return Collections.unmodifiableSet(canPlaceOn); + } + public T getOrDefault(@NotNull ItemTag tag, @Nullable T defaultValue) { var key = tag.getKey(); if (nbt.containsKey(key)) { diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index b70d99b5c..09a5c4c91 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -3,6 +3,7 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minestom.server.adventure.AdventureSerializer; +import net.minestom.server.instance.block.Block; import net.minestom.server.item.attribute.ItemAttribute; import net.minestom.server.utils.NBTUtils; import net.minestom.server.utils.Utils; @@ -27,6 +28,8 @@ public abstract class ItemMetaBuilder { protected Map enchantmentMap = new HashMap<>(); protected List attributes = new ArrayList<>(); protected int customModelData; + protected Set canDestroy = new HashSet<>(); + protected Set canPlaceOn = new HashSet<>(); @Contract("_ -> this") public @NotNull ItemMetaBuilder damage(int damage) { @@ -146,6 +149,30 @@ public abstract class ItemMetaBuilder { return this; } + @Contract("_ -> this") + public @NotNull ItemMetaBuilder canPlaceOn(@NotNull Set<@NotNull Block> blocks) { + this.canPlaceOn = blocks; + handleCollection(canPlaceOn, "CanPlaceOn", nbt, () -> { + NBTList list = new NBTList<>(NBTTypes.TAG_String); + canPlaceOn.forEach(block -> list.add(new NBTString(block.getName()))); + nbt.set("CanPlaceOn", list); + return list; + }); + return this; + } + + @Contract("_ -> this") + public @NotNull ItemMetaBuilder canDestroy(@NotNull Set<@NotNull Block> blocks) { + this.canDestroy = blocks; + handleCollection(canDestroy, "CanDestroy", nbt, () -> { + NBTList list = new NBTList<>(NBTTypes.TAG_String); + canDestroy.forEach(block -> list.add(new NBTString(block.getName()))); + nbt.set("CanDestroy", list); + return list; + }); + return this; + } + public @NotNull ItemMetaBuilder set(@NotNull ItemTag tag, @Nullable T value) { if (value != null) { tag.write(nbt, value); diff --git a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java index f6eb3bfc3..413d34a6d 100644 --- a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java +++ b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java @@ -86,8 +86,8 @@ public class BlockPlacementListener { canPlaceBlock = false; //Spectators can't place blocks } else if (player.getGameMode() == GameMode.ADVENTURE) { //Check if the block can placed on the block - // FIXME: canPlaceOn - canPlaceBlock = true;//usedItem.canPlaceOn(instance.getBlock(blockPosition).getName()); + Block placeBlock = instance.getBlock(blockPosition); + canPlaceBlock = usedItem.getMeta().getCanPlaceOn().contains(placeBlock); } } diff --git a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java index 1d39f8513..8ed5da8e3 100644 --- a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java @@ -47,12 +47,12 @@ public class PlayerDiggingListener { } else if (player.getGameMode() == GameMode.ADVENTURE) { //Check if the item can break the block with the current item ItemStack itemInMainHand = player.getItemInMainHand(); - // FIXME: canDestroy - /*if (!itemInMainHand.canDestroy(instance.getBlock(blockPosition).getName())) { + Block destroyedBlock = instance.getBlock(blockPosition); + if (!itemInMainHand.getMeta().getCanDestroy().contains(destroyedBlock)) { sendAcknowledgePacket(player, blockPosition, blockStateId, ClientPlayerDiggingPacket.Status.STARTED_DIGGING, false); return; - }*/ + } } final boolean instantBreak = player.isCreative() || diff --git a/src/main/java/net/minestom/server/utils/NBTUtils.java b/src/main/java/net/minestom/server/utils/NBTUtils.java index 87b25e519..4fe49d468 100644 --- a/src/main/java/net/minestom/server/utils/NBTUtils.java +++ b/src/main/java/net/minestom/server/utils/NBTUtils.java @@ -7,6 +7,7 @@ import net.kyori.adventure.util.Codec; import net.minestom.server.MinecraftServer; import net.minestom.server.attribute.Attribute; import net.minestom.server.attribute.AttributeOperation; +import net.minestom.server.instance.block.Block; import net.minestom.server.inventory.Inventory; import net.minestom.server.item.Enchantment; import net.minestom.server.item.ItemMetaBuilder; @@ -25,10 +26,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; // for lack of a better name public final class NBTUtils { @@ -236,34 +234,30 @@ public final class NBTUtils { // Meta specific fields metaBuilder.read(nbt); - // Ownership + // CanPlaceOn { - // FIXME: custom data - /*if (nbt.containsKey(ItemStack.OWNERSHIP_DATA_KEY)) { - final String identifierString = nbt.getString(ItemStack.OWNERSHIP_DATA_KEY); - final UUID identifier = UUID.fromString(identifierString); - final Data data = ItemStack.DATA_OWNERSHIP.getOwnObject(identifier); - if (data != null) { - item.setData(data); - } - }*/ - } - - //CanPlaceOn - // FIXME: PlaceOn/CanDestroy - /*{ if (nbt.containsKey("CanPlaceOn")) { NBTList canPlaceOn = nbt.getList("CanPlaceOn"); - canPlaceOn.forEach(x -> item.getCanPlaceOn().add(x.getValue())); + Set blocks = new HashSet<>(); + for (NBTString blockNamespace : canPlaceOn) { + Block block = Registries.getBlock(blockNamespace.getValue()); + blocks.add(block); + } + metaBuilder.canPlaceOn(blocks); } } - //CanDestroy + // CanDestroy { if (nbt.containsKey("CanDestroy")) { - NBTList canPlaceOn = nbt.getList("CanDestroy"); - canPlaceOn.forEach(x -> item.getCanDestroy().add(x.getValue())); + NBTList canDestroy = nbt.getList("CanDestroy"); + Set blocks = new HashSet<>(); + for (NBTString blockNamespace : canDestroy) { + Block block = Registries.getBlock(blockNamespace.getValue()); + blocks.add(block); + } + metaBuilder.canDestroy(blocks); } - }*/ + } } public static void loadEnchantments(NBTList enchantments, EnchantmentSetter setter) { diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index ec77a6fee..72ae68559 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -39,6 +39,7 @@ import net.minestom.server.world.DimensionType; import java.util.Collection; import java.util.Collections; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -229,12 +230,17 @@ public class PlayerInit { PlayerInventory inventory = player.getInventory(); ItemStack itemStack = ItemStack.builder(Material.STONE) .amount(64) + .meta(itemMetaBuilder -> + itemMetaBuilder.canPlaceOn(Set.of(Block.STONE)) + .canDestroy(Set.of(Block.DIAMOND_ORE))) .store(store -> { store.set("key", 5, Integer::sum); }) .build(); - itemStack = itemStack.withStore(storeBuilder -> storeBuilder.set("key2", 25, Integer::sum)); + System.out.println(itemStack.getMeta().toSNBT()); + + //itemStack = itemStack.withStore(storeBuilder -> storeBuilder.set("key2", 25, Integer::sum)); inventory.addItemStack(itemStack); From 2fadf1da94671eb3adbcf4968114ab734f4ab56b Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 11 Apr 2021 15:01:43 +0200 Subject: [PATCH 64/77] Added varargs equivalent for canPlace/Destroy --- .../java/net/minestom/server/item/ItemMetaBuilder.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 09a5c4c91..4bb33947d 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -161,6 +161,11 @@ public abstract class ItemMetaBuilder { return this; } + @Contract("_ -> this") + public @NotNull ItemMetaBuilder canPlaceOn(@NotNull Block... blocks) { + return canPlaceOn(Set.of(blocks)); + } + @Contract("_ -> this") public @NotNull ItemMetaBuilder canDestroy(@NotNull Set<@NotNull Block> blocks) { this.canDestroy = blocks; @@ -173,6 +178,11 @@ public abstract class ItemMetaBuilder { return this; } + @Contract("_ -> this") + public @NotNull ItemMetaBuilder canDestroy(@NotNull Block... blocks) { + return canDestroy(Set.of(blocks)); + } + public @NotNull ItemMetaBuilder set(@NotNull ItemTag tag, @Nullable T value) { if (value != null) { tag.write(nbt, value); From 792dd9787f54d7aa8d03f77b37c86581649fe46e Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 11 Apr 2021 17:01:05 +0200 Subject: [PATCH 65/77] Remove ItemStore API until a stable solution is found --- .../minestom/server/item/ItemMetaBuilder.java | 2 +- .../net/minestom/server/item/ItemStack.java | 31 +----------- .../server/item/ItemStackBuilder.java | 21 ++------ .../net/minestom/server/item/ItemStore.java | 30 ------------ .../server/item/ItemStoreBuilder.java | 48 ------------------- src/test/java/demo/PlayerInit.java | 8 +--- 6 files changed, 7 insertions(+), 133 deletions(-) delete mode 100644 src/main/java/net/minestom/server/item/ItemStore.java delete mode 100644 src/main/java/net/minestom/server/item/ItemStoreBuilder.java diff --git a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java index 4bb33947d..d7c871b39 100644 --- a/src/main/java/net/minestom/server/item/ItemMetaBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemMetaBuilder.java @@ -265,7 +265,7 @@ public abstract class ItemMetaBuilder { return dest; } - public interface Provider { + public interface Provider { } } diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index 3f9fb5ede..50a6b37e1 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.UUID; import java.util.function.Consumer; import java.util.function.IntUnaryOperator; import java.util.function.UnaryOperator; @@ -28,22 +27,17 @@ public class ItemStack implements HoverEventSource { */ public static final @NotNull ItemStack AIR = ItemStack.of(Material.AIR); - private final UUID uuid = UUID.randomUUID(); private final StackingRule stackingRule = new VanillaStackingRule(64); private final Material material; private final int amount; private final ItemMeta meta; - private final ItemStore store; - protected ItemStack(@NotNull Material material, int amount, - @NotNull ItemMeta meta, - @NotNull ItemStore store) { + @NotNull ItemMeta meta) { this.material = material; this.amount = amount; this.meta = meta; - this.store = store; } @Contract(value = "_ -> new", pure = true) @@ -61,11 +55,6 @@ public class ItemStack implements HoverEventSource { return of(material, 1); } - @Contract(pure = true) - public @NotNull UUID getUuid() { - return uuid; - } - @Contract(pure = true) public @NotNull Material getMaterial() { return material; @@ -103,16 +92,6 @@ public class ItemStack implements HoverEventSource { return builder().meta(metaOperator).build(); } - @Contract(value = "_, -> new", pure = true) - public @NotNull ItemStack withStore(@NotNull ItemStore store) { - return builder().store(store).build(); - } - - @Contract(value = "_ -> new", pure = true) - public @NotNull ItemStack withStore(@NotNull Consumer<@NotNull ItemStoreBuilder> storeConsumer) { - return builder().store(storeConsumer).build(); - } - @Contract(pure = true) public @Nullable Component getDisplayName() { return meta.getDisplayName(); @@ -153,11 +132,6 @@ public class ItemStack implements HoverEventSource { return meta; } - @Contract(pure = true) - public @NotNull ItemStore getStore() { - return store; - } - @Contract(pure = true) public boolean isAir() { return material.equals(Material.AIR); @@ -175,7 +149,6 @@ public class ItemStack implements HoverEventSource { if (o == null || getClass() != o.getClass()) return false; ItemStack itemStack = (ItemStack) o; - if (uuid.equals(itemStack.uuid)) return true; if (amount != itemStack.amount) return false; if (!stackingRule.equals(itemStack.stackingRule)) return false; @@ -194,7 +167,7 @@ public class ItemStack implements HoverEventSource { @Contract(value = "-> new", pure = true) protected @NotNull ItemStackBuilder builder() { - return new ItemStackBuilder(material, meta.builder(), store.builder()) + return new ItemStackBuilder(material, meta.builder()) .amount(amount); } diff --git a/src/main/java/net/minestom/server/item/ItemStackBuilder.java b/src/main/java/net/minestom/server/item/ItemStackBuilder.java index e6c95b7df..6b0a37e71 100644 --- a/src/main/java/net/minestom/server/item/ItemStackBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemStackBuilder.java @@ -19,13 +19,11 @@ public class ItemStackBuilder { private final Material material; private int amount; protected ItemMetaBuilder metaBuilder; - protected ItemStoreBuilder storeBuilder; - protected ItemStackBuilder(@NotNull Material material, @NotNull ItemMetaBuilder metaBuilder, @NotNull ItemStoreBuilder storeBuilder) { + protected ItemStackBuilder(@NotNull Material material, @NotNull ItemMetaBuilder metaBuilder) { this.material = material; this.amount = 1; this.metaBuilder = metaBuilder; - this.storeBuilder = storeBuilder; } private static final Map> MATERIAL_SUPPLIER_MAP = new ConcurrentHashMap<>(); @@ -54,8 +52,7 @@ public class ItemStackBuilder { protected ItemStackBuilder(@NotNull Material material) { this(material, - MATERIAL_SUPPLIER_MAP.getOrDefault(material, DefaultMeta::new).get(), - new ItemStoreBuilder()); + MATERIAL_SUPPLIER_MAP.getOrDefault(material, DefaultMeta::new).get()); } @Contract(value = "_ -> this") @@ -100,21 +97,9 @@ public class ItemStackBuilder { return this; } - @Contract(value = "_ -> this") - public @NotNull ItemStackBuilder store(@NotNull ItemStore store) { - this.storeBuilder = store.builder(); - return this; - } - - @Contract(value = "_ -> this") - public @NotNull ItemStackBuilder store(@NotNull Consumer<@NotNull ItemStoreBuilder> consumer) { - consumer.accept(storeBuilder); - return this; - } - @Contract(value = "-> new", pure = true) public @NotNull ItemStack build() { - return new ItemStack(material, amount, metaBuilder.build(), storeBuilder.build()); + return new ItemStack(material, amount, metaBuilder.build()); } private static final class DefaultMeta extends ItemMetaBuilder { diff --git a/src/main/java/net/minestom/server/item/ItemStore.java b/src/main/java/net/minestom/server/item/ItemStore.java deleted file mode 100644 index 8dd82769a..000000000 --- a/src/main/java/net/minestom/server/item/ItemStore.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.minestom.server.item; - -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class ItemStore { - - private final Map> entryMap; - - protected ItemStore(@NotNull Map> entryMap) { - this.entryMap = Collections.unmodifiableMap(entryMap); - } - - public T get(@NotNull String key) { - if (entryMap.containsKey(key)) { - return (T) entryMap.get(key).value; - } - return null; - } - - @Contract(value = "-> new", pure = true) - protected @NotNull ItemStoreBuilder builder() { - return new ItemStoreBuilder(new ConcurrentHashMap<>(entryMap)); - } - -} diff --git a/src/main/java/net/minestom/server/item/ItemStoreBuilder.java b/src/main/java/net/minestom/server/item/ItemStoreBuilder.java deleted file mode 100644 index e1c430e7f..000000000 --- a/src/main/java/net/minestom/server/item/ItemStoreBuilder.java +++ /dev/null @@ -1,48 +0,0 @@ -package net.minestom.server.item; - -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class ItemStoreBuilder { - - private final Map> entryMap; - - protected ItemStoreBuilder(@NotNull Map> entryMap) { - this.entryMap = entryMap; - } - - protected ItemStoreBuilder() { - this(new ConcurrentHashMap<>()); - } - - @Contract(value = "_, _, _ -> this") - public @NotNull ItemStoreBuilder set(@NotNull String key, T value, MergingRule mergingRule) { - this.entryMap.put(key, new Entry<>(value, mergingRule)); - return this; - } - - @Contract(value = "-> new", pure = true) - public @NotNull ItemStore build() { - return new ItemStore(new HashMap<>(entryMap)); - } - - public interface MergingRule { - @Nullable T apply(@NotNull T value1, @NotNull T value2); - } - - protected static class Entry { - protected final T value; - protected final MergingRule mergingRule; - - private Entry(@NotNull T value, @NotNull MergingRule mergingRule) { - this.value = value; - this.mergingRule = mergingRule; - } - } - -} diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 72ae68559..428e27379 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -76,9 +76,6 @@ public class PlayerInit { builder.lodestonePosition(new Position(0, 0, 0)); builder.set(ItemTag.Integer("int"), 25); }) - .store(store -> { - store.set("key", 5, Integer::sum); - }) .build(); itemStack = itemStack.with(itemBuilder -> itemBuilder @@ -207,6 +204,7 @@ public class PlayerInit { globalEventHandler.addEventCallback(PlayerLoginEvent.class, event -> { final Player player = event.getPlayer(); + player.sendMessage("test"); event.setSpawningInstance(instanceContainer); int x = Math.abs(ThreadLocalRandom.current().nextInt()) % 1000 - 250; @@ -233,9 +231,6 @@ public class PlayerInit { .meta(itemMetaBuilder -> itemMetaBuilder.canPlaceOn(Set.of(Block.STONE)) .canDestroy(Set.of(Block.DIAMOND_ORE))) - .store(store -> { - store.set("key", 5, Integer::sum); - }) .build(); System.out.println(itemStack.getMeta().toSNBT()); @@ -265,7 +260,6 @@ public class PlayerInit { globalEventHandler.addEventCallback(PlayerUseItemEvent.class, useEvent -> { final Player player = useEvent.getPlayer(); - System.out.println("test: " + player.getItemInMainHand().getStore().get("key2")); player.sendMessage("Using item in air: " + useEvent.getItemStack().getMaterial()); }); From ea3aedd76f4db8f70e123419689d5d437fb68596 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 11 Apr 2021 17:05:32 +0200 Subject: [PATCH 66/77] ItemMeta#getOrDefault annotation --- src/main/java/net/minestom/server/item/ItemMeta.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/minestom/server/item/ItemMeta.java b/src/main/java/net/minestom/server/item/ItemMeta.java index e859813ad..6eb11fffd 100644 --- a/src/main/java/net/minestom/server/item/ItemMeta.java +++ b/src/main/java/net/minestom/server/item/ItemMeta.java @@ -108,6 +108,7 @@ public class ItemMeta implements Writeable { return Collections.unmodifiableSet(canPlaceOn); } + @Contract(pure = true) public T getOrDefault(@NotNull ItemTag tag, @Nullable T defaultValue) { var key = tag.getKey(); if (nbt.containsKey(key)) { From df20670ce8230ed0684549d67d813f6ac64c6786 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 11 Apr 2021 17:12:28 +0200 Subject: [PATCH 67/77] Use AIR as default in CrossbowMeta instead of null --- .../server/item/meta/CrossbowMeta.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/minestom/server/item/meta/CrossbowMeta.java b/src/main/java/net/minestom/server/item/meta/CrossbowMeta.java index 8844a32ac..cc0c09000 100644 --- a/src/main/java/net/minestom/server/item/meta/CrossbowMeta.java +++ b/src/main/java/net/minestom/server/item/meta/CrossbowMeta.java @@ -8,7 +8,6 @@ import net.minestom.server.registry.Registries; import net.minestom.server.utils.NBTUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.jglrxavpok.hephaistos.nbt.NBTList; import org.jglrxavpok.hephaistos.nbt.NBTTypes; @@ -47,27 +46,27 @@ public class CrossbowMeta extends ItemMeta implements ItemMetaBuilder.Provider chargedProjectiles = new NBTList<>(NBTTypes.TAG_Compound); - chargedProjectiles.add(getItemCompound(projectile)); + if (!projectile.isAir()) { + chargedProjectiles.add(getItemCompound(projectile)); + } this.nbt.set("ChargedProjectiles", chargedProjectiles); return this; From c7cd8c332adbfdbb357b883fbf62a9fc601ade51 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 11 Apr 2021 19:13:50 +0200 Subject: [PATCH 68/77] Rename meta package to metadata to limit breaking changes --- src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java | 2 +- src/main/java/net/minestom/server/entity/Player.java | 2 +- src/main/java/net/minestom/server/item/ItemStackBuilder.java | 2 +- .../minestom/server/item/{meta => metadata}/CompassMeta.java | 2 +- .../minestom/server/item/{meta => metadata}/CrossbowMeta.java | 2 +- .../server/item/{meta => metadata}/EnchantedBookMeta.java | 2 +- .../server/item/{meta => metadata}/FireworkEffectMeta.java | 2 +- .../minestom/server/item/{meta => metadata}/FireworkMeta.java | 2 +- .../server/item/{meta => metadata}/LeatherArmorMeta.java | 2 +- .../net/minestom/server/item/{meta => metadata}/MapMeta.java | 2 +- .../minestom/server/item/{meta => metadata}/PlayerHeadMeta.java | 2 +- .../net/minestom/server/item/{meta => metadata}/PotionMeta.java | 2 +- .../minestom/server/item/{meta => metadata}/SpawnEggMeta.java | 2 +- .../server/item/{meta => metadata}/WritableBookMeta.java | 2 +- .../server/item/{meta => metadata}/WrittenBookMeta.java | 2 +- src/test/java/demo/PlayerInit.java | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) rename src/main/java/net/minestom/server/item/{meta => metadata}/CompassMeta.java (98%) rename src/main/java/net/minestom/server/item/{meta => metadata}/CrossbowMeta.java (99%) rename src/main/java/net/minestom/server/item/{meta => metadata}/EnchantedBookMeta.java (98%) rename src/main/java/net/minestom/server/item/{meta => metadata}/FireworkEffectMeta.java (97%) rename src/main/java/net/minestom/server/item/{meta => metadata}/FireworkMeta.java (98%) rename src/main/java/net/minestom/server/item/{meta => metadata}/LeatherArmorMeta.java (97%) rename src/main/java/net/minestom/server/item/{meta => metadata}/MapMeta.java (99%) rename src/main/java/net/minestom/server/item/{meta => metadata}/PlayerHeadMeta.java (98%) rename src/main/java/net/minestom/server/item/{meta => metadata}/PotionMeta.java (99%) rename src/main/java/net/minestom/server/item/{meta => metadata}/SpawnEggMeta.java (96%) rename src/main/java/net/minestom/server/item/{meta => metadata}/WritableBookMeta.java (98%) rename src/main/java/net/minestom/server/item/{meta => metadata}/WrittenBookMeta.java (99%) diff --git a/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java b/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java index 2fb89afc3..e0f4be51d 100644 --- a/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java +++ b/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java @@ -8,7 +8,7 @@ import net.minestom.server.instance.Instance; import net.minestom.server.instance.InstanceManager; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.minestom.server.item.meta.MapMeta; +import net.minestom.server.item.metadata.MapMeta; import net.minestom.server.map.Framebuffer; import net.minestom.server.map.LargeFramebuffer; import net.minestom.server.map.MapColors; diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 7b49c2159..dc7c736ab 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -42,7 +42,7 @@ import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; -import net.minestom.server.item.meta.WrittenBookMeta; +import net.minestom.server.item.metadata.WrittenBookMeta; import net.minestom.server.listener.PlayerDiggingListener; import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionState; diff --git a/src/main/java/net/minestom/server/item/ItemStackBuilder.java b/src/main/java/net/minestom/server/item/ItemStackBuilder.java index 6b0a37e71..71547a751 100644 --- a/src/main/java/net/minestom/server/item/ItemStackBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemStackBuilder.java @@ -1,7 +1,7 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; -import net.minestom.server.item.meta.*; +import net.minestom.server.item.metadata.*; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/minestom/server/item/meta/CompassMeta.java b/src/main/java/net/minestom/server/item/metadata/CompassMeta.java similarity index 98% rename from src/main/java/net/minestom/server/item/meta/CompassMeta.java rename to src/main/java/net/minestom/server/item/metadata/CompassMeta.java index edf642398..a046f0597 100644 --- a/src/main/java/net/minestom/server/item/meta/CompassMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/CompassMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemMetaBuilder; diff --git a/src/main/java/net/minestom/server/item/meta/CrossbowMeta.java b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java similarity index 99% rename from src/main/java/net/minestom/server/item/meta/CrossbowMeta.java rename to src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java index cc0c09000..7c64abcf2 100644 --- a/src/main/java/net/minestom/server/item/meta/CrossbowMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/CrossbowMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemMetaBuilder; diff --git a/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java b/src/main/java/net/minestom/server/item/metadata/EnchantedBookMeta.java similarity index 98% rename from src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java rename to src/main/java/net/minestom/server/item/metadata/EnchantedBookMeta.java index 4853b7a38..3f5c218ab 100644 --- a/src/main/java/net/minestom/server/item/meta/EnchantedBookMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/EnchantedBookMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.item.Enchantment; import net.minestom.server.item.ItemMeta; diff --git a/src/main/java/net/minestom/server/item/meta/FireworkEffectMeta.java b/src/main/java/net/minestom/server/item/metadata/FireworkEffectMeta.java similarity index 97% rename from src/main/java/net/minestom/server/item/meta/FireworkEffectMeta.java rename to src/main/java/net/minestom/server/item/metadata/FireworkEffectMeta.java index 2c209f5ba..1af345b36 100644 --- a/src/main/java/net/minestom/server/item/meta/FireworkEffectMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/FireworkEffectMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemMetaBuilder; diff --git a/src/main/java/net/minestom/server/item/meta/FireworkMeta.java b/src/main/java/net/minestom/server/item/metadata/FireworkMeta.java similarity index 98% rename from src/main/java/net/minestom/server/item/meta/FireworkMeta.java rename to src/main/java/net/minestom/server/item/metadata/FireworkMeta.java index baab018b3..757bd739f 100644 --- a/src/main/java/net/minestom/server/item/meta/FireworkMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/FireworkMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.item.ItemMeta; import net.minestom.server.item.ItemMetaBuilder; diff --git a/src/main/java/net/minestom/server/item/meta/LeatherArmorMeta.java b/src/main/java/net/minestom/server/item/metadata/LeatherArmorMeta.java similarity index 97% rename from src/main/java/net/minestom/server/item/meta/LeatherArmorMeta.java rename to src/main/java/net/minestom/server/item/metadata/LeatherArmorMeta.java index 0a3414a6b..da392a894 100644 --- a/src/main/java/net/minestom/server/item/meta/LeatherArmorMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/LeatherArmorMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.color.Color; import net.minestom.server.item.ItemMeta; diff --git a/src/main/java/net/minestom/server/item/meta/MapMeta.java b/src/main/java/net/minestom/server/item/metadata/MapMeta.java similarity index 99% rename from src/main/java/net/minestom/server/item/meta/MapMeta.java rename to src/main/java/net/minestom/server/item/metadata/MapMeta.java index f6b6c2398..c7068b093 100644 --- a/src/main/java/net/minestom/server/item/meta/MapMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/MapMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.MinecraftServer; import net.minestom.server.chat.ChatColor; diff --git a/src/main/java/net/minestom/server/item/meta/PlayerHeadMeta.java b/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java similarity index 98% rename from src/main/java/net/minestom/server/item/meta/PlayerHeadMeta.java rename to src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java index 661302f02..10d8f0a06 100644 --- a/src/main/java/net/minestom/server/item/meta/PlayerHeadMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/PlayerHeadMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.entity.PlayerSkin; import net.minestom.server.item.ItemMeta; diff --git a/src/main/java/net/minestom/server/item/meta/PotionMeta.java b/src/main/java/net/minestom/server/item/metadata/PotionMeta.java similarity index 99% rename from src/main/java/net/minestom/server/item/meta/PotionMeta.java rename to src/main/java/net/minestom/server/item/metadata/PotionMeta.java index b2be6ba9e..bbf4b0e98 100644 --- a/src/main/java/net/minestom/server/item/meta/PotionMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/PotionMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.color.Color; import net.minestom.server.item.ItemMeta; diff --git a/src/main/java/net/minestom/server/item/meta/SpawnEggMeta.java b/src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java similarity index 96% rename from src/main/java/net/minestom/server/item/meta/SpawnEggMeta.java rename to src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java index f9aef14c2..2c56be1a8 100644 --- a/src/main/java/net/minestom/server/item/meta/SpawnEggMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/SpawnEggMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.minestom.server.entity.EntityType; import net.minestom.server.item.ItemMeta; diff --git a/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java b/src/main/java/net/minestom/server/item/metadata/WritableBookMeta.java similarity index 98% rename from src/main/java/net/minestom/server/item/meta/WritableBookMeta.java rename to src/main/java/net/minestom/server/item/metadata/WritableBookMeta.java index a2cf89b0b..815ab6a5d 100644 --- a/src/main/java/net/minestom/server/item/meta/WritableBookMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/WritableBookMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; diff --git a/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java b/src/main/java/net/minestom/server/item/metadata/WrittenBookMeta.java similarity index 99% rename from src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java rename to src/main/java/net/minestom/server/item/metadata/WrittenBookMeta.java index 3645645ff..02c922003 100644 --- a/src/main/java/net/minestom/server/item/meta/WrittenBookMeta.java +++ b/src/main/java/net/minestom/server/item/metadata/WrittenBookMeta.java @@ -1,4 +1,4 @@ -package net.minestom.server.item.meta; +package net.minestom.server.item.metadata; import net.kyori.adventure.inventory.Book; import net.kyori.adventure.text.Component; diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 428e27379..579d10c4e 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -29,7 +29,7 @@ import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemTag; import net.minestom.server.item.Material; -import net.minestom.server.item.meta.CompassMeta; +import net.minestom.server.item.metadata.CompassMeta; import net.minestom.server.network.ConnectionManager; import net.minestom.server.ping.ResponseDataConsumer; import net.minestom.server.utils.Position; From d86a733b79c50ed125b48e69b4672ac37334cb82 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 11 Apr 2021 23:43:35 +0200 Subject: [PATCH 69/77] WIP FillOption --- .../server/inventory/AbstractInventory.java | 128 +++--------------- .../minestom/server/inventory/FillOption.java | 32 +++++ src/test/java/demo/Main.java | 1 + src/test/java/demo/commands/GiveCommand.java | 56 ++++++++ 4 files changed, 107 insertions(+), 110 deletions(-) create mode 100644 src/main/java/net/minestom/server/inventory/FillOption.java create mode 100644 src/test/java/demo/commands/GiveCommand.java diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 7885be34c..4f32dc1bf 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -52,13 +52,11 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo /** * Adds an {@link ItemStack} to the inventory and sends relevant update to the viewer(s). - *

- * Does nothing if the item cannot be fully added. * * @param itemStack the item to add * @return true if the item has been successfully added, false otherwise */ - public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { + public synchronized T addItemStack(@NotNull ItemStack itemStack, FillOption fillOption) { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); final StackingRule stackingRule = itemStack.getStackingRule(); @@ -96,81 +94,35 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo break; } - if (itemStack.isAir()) { - // Item can be fully placed inside the inventory, do so - itemChangesMap.forEach(this::safeItemInsert); - return true; - } else { - // Inventory cannot accept the item fully - return false; - } + return fillOption.fill(this, itemStack, itemChangesMap); + } + + public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { + return addItemStack(itemStack, FillOption.ALL_OR_NOTHING); } /** * Adds {@link ItemStack}s to the inventory and sends relevant updates to the viewer(s). - *

- * Does nothing if the item cannot be fully added. * * @param itemStacks items to add - * @return list of items that could not be successfully added, empty list otherwise + * @return the operation results */ - public @NotNull List addItemStacks(@NotNull List itemStacks) { - List result = new ArrayList<>(); + public @NotNull List addItemStacks(@NotNull List itemStacks, @NotNull FillOption fillOption) { + List result = new ArrayList<>(itemStacks.size()); itemStacks.forEach(itemStack -> { - if (!addItemStack(itemStack)) { - result.add(itemStack); - } + T fillResult = addItemStack(itemStack, fillOption); + result.add(fillResult); }); return result; } - /** - * Checks whether {@link ItemStack} can be fully added to the inventory. - * - * @param itemStack the item to be checked - * @return true if the item can be fully added to the inventory, false otherwise - */ - public boolean canAddItemStack(@NotNull ItemStack itemStack) { - final StackingRule stackingRule = itemStack.getStackingRule(); - int amountLeft = stackingRule.getAmount(itemStack); - for (int i = 0; i < getInnerSize(); i++) { - ItemStack inventoryItem = getItemStack(i); - if (stackingRule.canBeStacked(itemStack, inventoryItem)) { - final int itemAmount = stackingRule.getAmount(inventoryItem); - if (itemAmount == stackingRule.getMaxSize()) - continue; - if (!stackingRule.canApply(itemStack, amountLeft + itemAmount)) { - // Slot cannot accept the whole item, reduce amount to 'itemStack' - amountLeft -= stackingRule.getMaxSize() - itemAmount; - } else { - return true; - } - } else if (inventoryItem.isAir()) { - return true; - } - } - return false; - } - - /** - * Checks whether {@link ItemStack}s can be fully added to the inventory. - * - * @param itemStacks items to be checked - * @return true if all the items can be fully added to the inventory, false otherwise - */ - public boolean canAddItemStacks(@NotNull List itemStacks) { - return itemStacks.stream().allMatch(this::canAddItemStack); - } - /** * Takes an {@link ItemStack} from the inventory and sends relevant update to the viewer(s). - *

- * Even the item cannot be fully taken, the amount of {@code itemStack} will be updated. * * @param itemStack the item to take * @return true if the item has been successfully fully taken, false otherwise */ - public boolean takeItemStack(@NotNull ItemStack itemStack) { + public T takeItemStack(@NotNull ItemStack itemStack, @NotNull FillOption fillOption) { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); final StackingRule stackingRule = itemStack.getStackingRule(); for (int i = 0; i < getInnerSize(); i++) { @@ -195,68 +147,24 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo } } - if (itemStack.isAir()) { - // Item can be fully taken from the inventory, do so - itemChangesMap.forEach(this::safeItemInsert); - return true; - } else { - return false; - } + return fillOption.fill(this, itemStack, itemChangesMap); } /** * Takes {@link ItemStack}s from the inventory and sends relevant updates to the viewer(s). - *

- * Even items cannot be fully taken, the amount of {@code itemStack}s will be updated. * * @param itemStacks items to take - * @return list of itemstacks that could not be successfully fully taken, empty list otherwise + * @return the operation results */ - public @NotNull List takeItemStacks(@NotNull List itemStacks) { - List result = new ArrayList<>(); + public @NotNull List takeItemStacks(@NotNull List itemStacks, @NotNull FillOption fillOption) { + List result = new ArrayList<>(itemStacks.size()); itemStacks.forEach(itemStack -> { - if (!takeItemStack(itemStack)) { - result.add(itemStack); - } + T fillResult = takeItemStack(itemStack, fillOption); + result.add(fillResult); }); return result; } - /** - * Checks whether {@link ItemStack} can be fully taken from the inventory. - * - * @param itemStack the item to be checked - * @return true if the item can be fully taken from the inventory, false otherwise - */ - public boolean canTakeItemStack(@NotNull ItemStack itemStack) { - final StackingRule stackingRule = itemStack.getStackingRule(); - int amountLeft = stackingRule.getAmount(itemStack); - for (int i = 0; i < getInnerSize(); i++) { - ItemStack inventoryItem = getItemStack(i); - if (inventoryItem.isAir()) { - continue; - } - if (stackingRule.canBeStacked(itemStack, inventoryItem)) { - final int itemAmount = stackingRule.getAmount(inventoryItem); - if (amountLeft <= itemAmount) { - return true; - } - amountLeft -= itemAmount; - } - } - return false; - } - - /** - * Checks whether {@link ItemStack}s can be fully taken from the inventory. - * - * @param itemStacks items to be checked - * @return true if all the items can be fully taken from the inventory, false otherwise - */ - public boolean canTakeItemStacks(@NotNull List itemStacks) { - return itemStacks.stream().allMatch(this::canTakeItemStack); - } - public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { var currentItem = getItemStack(slot); setItemStack(slot, operator.apply(currentItem)); diff --git a/src/main/java/net/minestom/server/inventory/FillOption.java b/src/main/java/net/minestom/server/inventory/FillOption.java new file mode 100644 index 000000000..3713c5f5e --- /dev/null +++ b/src/main/java/net/minestom/server/inventory/FillOption.java @@ -0,0 +1,32 @@ +package net.minestom.server.inventory; + +import net.minestom.server.item.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +@FunctionalInterface +public interface FillOption { + + FillOption ALL = (inventory, result, itemChangesMap) -> { + itemChangesMap.forEach(inventory::safeItemInsert); + return result; + }; + + FillOption ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> { + if (result.isAir()) { + // Item can be fully placed inside the inventory, do so + itemChangesMap.forEach(inventory::safeItemInsert); + return true; + } else { + // Inventory cannot accept the item fully + return false; + } + }; + + FillOption DRY_RUN = (inventory, result, itemChangesMap) -> !result.isAir(); + + T fill(@NotNull AbstractInventory inventory, + @NotNull ItemStack result, + @NotNull Map<@NotNull Integer, @NotNull ItemStack> itemChangesMap); +} diff --git a/src/test/java/demo/Main.java b/src/test/java/demo/Main.java index c357c124d..e6886fcf3 100644 --- a/src/test/java/demo/Main.java +++ b/src/test/java/demo/Main.java @@ -49,6 +49,7 @@ public class Main { commandManager.register(new EchoCommand()); commandManager.register(new SummonCommand()); commandManager.register(new RemoveCommand()); + commandManager.register(new GiveCommand()); commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED))); diff --git a/src/test/java/demo/commands/GiveCommand.java b/src/test/java/demo/commands/GiveCommand.java new file mode 100644 index 000000000..73f747213 --- /dev/null +++ b/src/test/java/demo/commands/GiveCommand.java @@ -0,0 +1,56 @@ +package demo.commands; + +import net.kyori.adventure.text.Component; +import net.minestom.server.command.builder.Command; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.Player; +import net.minestom.server.inventory.FillOption; +import net.minestom.server.item.ItemStack; +import net.minestom.server.utils.entity.EntityFinder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static net.minestom.server.command.builder.arguments.ArgumentType.Integer; +import static net.minestom.server.command.builder.arguments.ArgumentType.*; + +public class GiveCommand extends Command { + public GiveCommand() { + super("give"); + + setDefaultExecutor((sender, context) -> + sender.sendMessage(Component.text("Usage: /give []"))); + + addSyntax((sender, context) -> { + final EntityFinder entityFinder = context.get("target"); + int count = context.get("count"); + ItemStack itemStack = context.get("item"); + + List itemStacks; + if (count <= 64) { + itemStack = itemStack.withAmount(count); + itemStacks = Collections.singletonList(itemStack); + } else { + itemStacks = new ArrayList<>(); + while (count > 64) { + itemStacks.add(itemStack.withAmount(64)); + count -= 64; + } + itemStacks.add(itemStack.withAmount(count)); + } + + final List targets = entityFinder.find(sender); + for (Entity target : targets) { + if (target instanceof Player) { + Player player = (Player) target; + player.getInventory().addItemStacks(itemStacks, FillOption.ALL_OR_NOTHING); + } + } + + sender.sendMessage(Component.text("Items have been given successfully!")); + + }, Entity("target").onlyPlayers(true), ItemStack("item"), Integer("count").setDefaultValue(() -> 1)); + + } +} From 17fcd23c77b819480d457e70924bf45b0a807620 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 11 Apr 2021 23:52:12 +0200 Subject: [PATCH 70/77] Fix condition, add documentation --- .../minestom/server/inventory/FillOption.java | 17 ++++++++++++++++- .../minestom/server/thread/ThreadProvider.java | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/FillOption.java b/src/main/java/net/minestom/server/inventory/FillOption.java index 3713c5f5e..6eb74b6d2 100644 --- a/src/main/java/net/minestom/server/inventory/FillOption.java +++ b/src/main/java/net/minestom/server/inventory/FillOption.java @@ -8,11 +8,21 @@ import java.util.Map; @FunctionalInterface public interface FillOption { + /** + * Place as much as the item as possible. + *

+ * The remaining, can be air. + */ FillOption ALL = (inventory, result, itemChangesMap) -> { itemChangesMap.forEach(inventory::safeItemInsert); return result; }; + /** + * Only place the item if can be fully added. + *

+ * Returns true if the item has been added, false if nothing changed. + */ FillOption ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> { if (result.isAir()) { // Item can be fully placed inside the inventory, do so @@ -24,7 +34,12 @@ public interface FillOption { } }; - FillOption DRY_RUN = (inventory, result, itemChangesMap) -> !result.isAir(); + /** + * Loop through the inventory items without changing anything. + *

+ * Returns true if the item can be fully added, false otherwise. + */ + FillOption DRY_RUN = (inventory, result, itemChangesMap) -> result.isAir(); T fill(@NotNull AbstractInventory inventory, @NotNull ItemStack result, diff --git a/src/main/java/net/minestom/server/thread/ThreadProvider.java b/src/main/java/net/minestom/server/thread/ThreadProvider.java index 937fb3237..8640736ab 100644 --- a/src/main/java/net/minestom/server/thread/ThreadProvider.java +++ b/src/main/java/net/minestom/server/thread/ThreadProvider.java @@ -38,7 +38,7 @@ public abstract class ThreadProvider { { // Default thread count in the pool (cores * 2) - setThreadCount(NettyRuntime.availableProcessors() * 2); + setThreadCount(1); } /** From 1100aa98a5042cda87c8567c2381f7adf3e4fa73 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 12 Apr 2021 00:04:40 +0200 Subject: [PATCH 71/77] Annotation & comment --- .../server/inventory/AbstractInventory.java | 22 ++++++++++++------- .../minestom/server/inventory/FillOption.java | 12 +++++----- src/test/java/demo/commands/GiveCommand.java | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 4f32dc1bf..d90300c01 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -53,13 +53,16 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo /** * Adds an {@link ItemStack} to the inventory and sends relevant update to the viewer(s). * - * @param itemStack the item to add + * @param itemStack the item to add + * @param fillOption the filling option * @return true if the item has been successfully added, false otherwise */ - public synchronized T addItemStack(@NotNull ItemStack itemStack, FillOption fillOption) { + public synchronized @NotNull T addItemStack(@NotNull ItemStack itemStack, @NotNull FillOption fillOption) { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); final StackingRule stackingRule = itemStack.getStackingRule(); + + // Check filled slot (not air) for (int i = 0; i < getInnerSize(); i++) { ItemStack inventoryItem = getItemStack(i); if (inventoryItem.isAir()) { @@ -78,11 +81,13 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo } else { // Slot can accept the whole item itemChangesMap.put(i, stackingRule.apply(inventoryItem, totalAmount)); - itemStack = ItemStack.AIR; + itemStack = stackingRule.apply(itemStack, 0); break; } } } + + // Check air slot to fill for (int i = 0; i < getInnerSize(); i++) { ItemStack inventoryItem = getItemStack(i); if (!inventoryItem.isAir()) { @@ -90,7 +95,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo } // Fill the slot itemChangesMap.put(i, itemStack); - itemStack = ItemStack.AIR; + itemStack = stackingRule.apply(itemStack, 0); break; } @@ -105,9 +110,10 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * Adds {@link ItemStack}s to the inventory and sends relevant updates to the viewer(s). * * @param itemStacks items to add + * @param fillOption the filling option * @return the operation results */ - public @NotNull List addItemStacks(@NotNull List itemStacks, @NotNull FillOption fillOption) { + public @NotNull List<@NotNull T> addItemStacks(@NotNull List itemStacks, @NotNull FillOption fillOption) { List result = new ArrayList<>(itemStacks.size()); itemStacks.forEach(itemStack -> { T fillResult = addItemStack(itemStack, fillOption); @@ -135,13 +141,13 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo final int itemStackAmount = stackingRule.getAmount(itemStack); if (itemStackAmount < itemAmount) { itemChangesMap.put(i, stackingRule.apply(inventoryItem, itemAmount - itemStackAmount)); - itemStack = ItemStack.AIR; + itemStack = stackingRule.apply(itemStack, 0); break; } - itemChangesMap.put(i, ItemStack.AIR); + itemChangesMap.put(i, stackingRule.apply(inventoryItem, 0)); itemStack = stackingRule.apply(itemStack, itemStackAmount - itemAmount); if (stackingRule.getAmount(itemStack) == 0) { - itemStack = ItemStack.AIR; + itemStack = stackingRule.apply(itemStack, 0); break; } } diff --git a/src/main/java/net/minestom/server/inventory/FillOption.java b/src/main/java/net/minestom/server/inventory/FillOption.java index 6eb74b6d2..3d8b46086 100644 --- a/src/main/java/net/minestom/server/inventory/FillOption.java +++ b/src/main/java/net/minestom/server/inventory/FillOption.java @@ -13,7 +13,7 @@ public interface FillOption { *

* The remaining, can be air. */ - FillOption ALL = (inventory, result, itemChangesMap) -> { + FillOption<@NotNull ItemStack> ALL = (inventory, result, itemChangesMap) -> { itemChangesMap.forEach(inventory::safeItemInsert); return result; }; @@ -23,7 +23,7 @@ public interface FillOption { *

* Returns true if the item has been added, false if nothing changed. */ - FillOption ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> { + FillOption<@NotNull Boolean> ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> { if (result.isAir()) { // Item can be fully placed inside the inventory, do so itemChangesMap.forEach(inventory::safeItemInsert); @@ -39,9 +39,9 @@ public interface FillOption { *

* Returns true if the item can be fully added, false otherwise. */ - FillOption DRY_RUN = (inventory, result, itemChangesMap) -> result.isAir(); + FillOption<@NotNull Boolean> DRY_RUN = (inventory, result, itemChangesMap) -> result.isAir(); - T fill(@NotNull AbstractInventory inventory, - @NotNull ItemStack result, - @NotNull Map<@NotNull Integer, @NotNull ItemStack> itemChangesMap); + @NotNull T fill(@NotNull AbstractInventory inventory, + @NotNull ItemStack result, + @NotNull Map<@NotNull Integer, @NotNull ItemStack> itemChangesMap); } diff --git a/src/test/java/demo/commands/GiveCommand.java b/src/test/java/demo/commands/GiveCommand.java index 73f747213..a10373666 100644 --- a/src/test/java/demo/commands/GiveCommand.java +++ b/src/test/java/demo/commands/GiveCommand.java @@ -44,7 +44,7 @@ public class GiveCommand extends Command { for (Entity target : targets) { if (target instanceof Player) { Player player = (Player) target; - player.getInventory().addItemStacks(itemStacks, FillOption.ALL_OR_NOTHING); + player.getInventory().addItemStacks(itemStacks, FillOption.ALL); } } From ecb77fc84703c943597c8aeb7fd0f8bd5fa1fa21 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 12 Apr 2021 00:07:38 +0200 Subject: [PATCH 72/77] Rename FillOption to TransactionOption --- .../server/inventory/AbstractInventory.java | 30 +++++++++---------- ...FillOption.java => TransactionOption.java} | 8 ++--- src/test/java/demo/commands/GiveCommand.java | 4 +-- 3 files changed, 21 insertions(+), 21 deletions(-) rename src/main/java/net/minestom/server/inventory/{FillOption.java => TransactionOption.java} (78%) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index d90300c01..1385a7c4d 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -53,11 +53,11 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo /** * Adds an {@link ItemStack} to the inventory and sends relevant update to the viewer(s). * - * @param itemStack the item to add - * @param fillOption the filling option + * @param itemStack the item to add + * @param transactionOption the transaction option * @return true if the item has been successfully added, false otherwise */ - public synchronized @NotNull T addItemStack(@NotNull ItemStack itemStack, @NotNull FillOption fillOption) { + public synchronized @NotNull T addItemStack(@NotNull ItemStack itemStack, @NotNull TransactionOption transactionOption) { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); final StackingRule stackingRule = itemStack.getStackingRule(); @@ -99,25 +99,25 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo break; } - return fillOption.fill(this, itemStack, itemChangesMap); + return transactionOption.fill(this, itemStack, itemChangesMap); } public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { - return addItemStack(itemStack, FillOption.ALL_OR_NOTHING); + return addItemStack(itemStack, TransactionOption.ALL_OR_NOTHING); } /** * Adds {@link ItemStack}s to the inventory and sends relevant updates to the viewer(s). * - * @param itemStacks items to add - * @param fillOption the filling option + * @param itemStacks items to add + * @param transactionOption the transaction option * @return the operation results */ - public @NotNull List<@NotNull T> addItemStacks(@NotNull List itemStacks, @NotNull FillOption fillOption) { + public @NotNull List<@NotNull T> addItemStacks(@NotNull List itemStacks, @NotNull TransactionOption transactionOption) { List result = new ArrayList<>(itemStacks.size()); itemStacks.forEach(itemStack -> { - T fillResult = addItemStack(itemStack, fillOption); - result.add(fillResult); + T transactionResult = addItemStack(itemStack, transactionOption); + result.add(transactionResult); }); return result; } @@ -128,7 +128,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param itemStack the item to take * @return true if the item has been successfully fully taken, false otherwise */ - public T takeItemStack(@NotNull ItemStack itemStack, @NotNull FillOption fillOption) { + public T takeItemStack(@NotNull ItemStack itemStack, @NotNull TransactionOption transactionOption) { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); final StackingRule stackingRule = itemStack.getStackingRule(); for (int i = 0; i < getInnerSize(); i++) { @@ -153,7 +153,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo } } - return fillOption.fill(this, itemStack, itemChangesMap); + return transactionOption.fill(this, itemStack, itemChangesMap); } /** @@ -162,11 +162,11 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param itemStacks items to take * @return the operation results */ - public @NotNull List takeItemStacks(@NotNull List itemStacks, @NotNull FillOption fillOption) { + public @NotNull List takeItemStacks(@NotNull List itemStacks, @NotNull TransactionOption transactionOption) { List result = new ArrayList<>(itemStacks.size()); itemStacks.forEach(itemStack -> { - T fillResult = takeItemStack(itemStack, fillOption); - result.add(fillResult); + T transactionResult = takeItemStack(itemStack, transactionOption); + result.add(transactionResult); }); return result; } diff --git a/src/main/java/net/minestom/server/inventory/FillOption.java b/src/main/java/net/minestom/server/inventory/TransactionOption.java similarity index 78% rename from src/main/java/net/minestom/server/inventory/FillOption.java rename to src/main/java/net/minestom/server/inventory/TransactionOption.java index 3d8b46086..313f9a3ed 100644 --- a/src/main/java/net/minestom/server/inventory/FillOption.java +++ b/src/main/java/net/minestom/server/inventory/TransactionOption.java @@ -6,14 +6,14 @@ import org.jetbrains.annotations.NotNull; import java.util.Map; @FunctionalInterface -public interface FillOption { +public interface TransactionOption { /** * Place as much as the item as possible. *

* The remaining, can be air. */ - FillOption<@NotNull ItemStack> ALL = (inventory, result, itemChangesMap) -> { + TransactionOption<@NotNull ItemStack> ALL = (inventory, result, itemChangesMap) -> { itemChangesMap.forEach(inventory::safeItemInsert); return result; }; @@ -23,7 +23,7 @@ public interface FillOption { *

* Returns true if the item has been added, false if nothing changed. */ - FillOption<@NotNull Boolean> ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> { + TransactionOption<@NotNull Boolean> ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> { if (result.isAir()) { // Item can be fully placed inside the inventory, do so itemChangesMap.forEach(inventory::safeItemInsert); @@ -39,7 +39,7 @@ public interface FillOption { *

* Returns true if the item can be fully added, false otherwise. */ - FillOption<@NotNull Boolean> DRY_RUN = (inventory, result, itemChangesMap) -> result.isAir(); + TransactionOption<@NotNull Boolean> DRY_RUN = (inventory, result, itemChangesMap) -> result.isAir(); @NotNull T fill(@NotNull AbstractInventory inventory, @NotNull ItemStack result, diff --git a/src/test/java/demo/commands/GiveCommand.java b/src/test/java/demo/commands/GiveCommand.java index a10373666..e4d03307c 100644 --- a/src/test/java/demo/commands/GiveCommand.java +++ b/src/test/java/demo/commands/GiveCommand.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.command.builder.Command; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; -import net.minestom.server.inventory.FillOption; +import net.minestom.server.inventory.TransactionOption; import net.minestom.server.item.ItemStack; import net.minestom.server.utils.entity.EntityFinder; @@ -44,7 +44,7 @@ public class GiveCommand extends Command { for (Entity target : targets) { if (target instanceof Player) { Player player = (Player) target; - player.getInventory().addItemStacks(itemStacks, FillOption.ALL); + player.getInventory().addItemStacks(itemStacks, TransactionOption.ALL); } } From 8e9d7098e5a77f0cc2e85b708eb946b7600ca006 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 12 Apr 2021 00:33:27 +0200 Subject: [PATCH 73/77] Allow custom transaction type, simplify inventory superclasses --- .../event/player/PlayerAddItemStackEvent.java | 51 ------- .../event/player/PlayerSetItemStackEvent.java | 72 ---------- .../server/inventory/AbstractInventory.java | 129 +++++------------- .../minestom/server/inventory/Inventory.java | 10 -- .../server/inventory/PlayerInventory.java | 25 ---- .../server/inventory/TransactionType.java | 101 ++++++++++++++ src/test/java/demo/commands/GiveCommand.java | 2 + 7 files changed, 140 insertions(+), 250 deletions(-) delete mode 100644 src/main/java/net/minestom/server/event/player/PlayerAddItemStackEvent.java delete mode 100644 src/main/java/net/minestom/server/event/player/PlayerSetItemStackEvent.java create mode 100644 src/main/java/net/minestom/server/inventory/TransactionType.java diff --git a/src/main/java/net/minestom/server/event/player/PlayerAddItemStackEvent.java b/src/main/java/net/minestom/server/event/player/PlayerAddItemStackEvent.java deleted file mode 100644 index 3adbb1e6f..000000000 --- a/src/main/java/net/minestom/server/event/player/PlayerAddItemStackEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.minestom.server.event.player; - -import net.minestom.server.entity.Player; -import net.minestom.server.event.CancellableEvent; -import net.minestom.server.event.PlayerEvent; -import net.minestom.server.item.ItemStack; -import org.jetbrains.annotations.NotNull; - -/** - * Called as a result of {@link net.minestom.server.inventory.PlayerInventory#addItemStack(ItemStack)}. - */ -public class PlayerAddItemStackEvent extends PlayerEvent implements CancellableEvent { - - private ItemStack itemStack; - - private boolean cancelled; - - public PlayerAddItemStackEvent(@NotNull Player player, @NotNull ItemStack itemStack) { - super(player); - this.itemStack = itemStack; - } - - /** - * Gets the item stack which will be added. - * - * @return the item stack - */ - @NotNull - public ItemStack getItemStack() { - return itemStack; - } - - /** - * Changes the item stack which will be added. - * - * @param itemStack the new item stack - */ - public void setItemStack(@NotNull ItemStack itemStack) { - this.itemStack = itemStack; - } - - @Override - public boolean isCancelled() { - return cancelled; - } - - @Override - public void setCancelled(boolean cancel) { - this.cancelled = cancel; - } -} diff --git a/src/main/java/net/minestom/server/event/player/PlayerSetItemStackEvent.java b/src/main/java/net/minestom/server/event/player/PlayerSetItemStackEvent.java deleted file mode 100644 index f0e9e0574..000000000 --- a/src/main/java/net/minestom/server/event/player/PlayerSetItemStackEvent.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.minestom.server.event.player; - -import net.minestom.server.entity.Player; -import net.minestom.server.event.CancellableEvent; -import net.minestom.server.event.PlayerEvent; -import net.minestom.server.item.ItemStack; -import org.jetbrains.annotations.NotNull; - -/** - * Called as a result of {@link net.minestom.server.inventory.PlayerInventory#setItemStack(int, ItemStack)} - * and player click in his inventory. - */ -public class PlayerSetItemStackEvent extends PlayerEvent implements CancellableEvent { - - private int slot; - private ItemStack itemStack; - - private boolean cancelled; - - public PlayerSetItemStackEvent(@NotNull Player player, int slot, @NotNull ItemStack itemStack) { - super(player); - this.slot = slot; - this.itemStack = itemStack; - } - - /** - * Gets the slot where the item will be set. - * - * @return the slot - */ - public int getSlot() { - return slot; - } - - /** - * Changes the slot where the item will be set. - * - * @param slot the new slot - */ - public void setSlot(int slot) { - this.slot = slot; - } - - /** - * Gets the item stack which will be set. - * - * @return the item stack - */ - @NotNull - public ItemStack getItemStack() { - return itemStack; - } - - /** - * Changes the item stack which will be set. - * - * @param itemStack the new item stack - */ - public void setItemStack(@NotNull ItemStack itemStack) { - this.itemStack = itemStack; - } - - @Override - public boolean isCancelled() { - return cancelled; - } - - @Override - public void setCancelled(boolean cancel) { - this.cancelled = cancel; - } -} diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 1385a7c4d..140af5d85 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -1,13 +1,11 @@ package net.minestom.server.inventory; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minestom.server.data.Data; import net.minestom.server.data.DataContainer; import net.minestom.server.inventory.click.InventoryClickProcessor; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; -import net.minestom.server.item.StackingRule; +import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,80 +44,56 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param slot the slot to set the item * @param itemStack the item to set */ - public abstract void setItemStack(int slot, @NotNull ItemStack itemStack); + public synchronized void setItemStack(int slot, @NotNull ItemStack itemStack) { + Check.argCondition(!MathUtils.isBetween(slot, 0, getSize()), + "Inventory does not have the slot " + slot); + safeItemInsert(slot, itemStack); + } protected abstract void safeItemInsert(int slot, @NotNull ItemStack itemStack); + public synchronized @NotNull T processItemStack(@NotNull ItemStack itemStack, + @NotNull TransactionType type, + @NotNull TransactionOption option) { + var pair = type.process(this, itemStack); + return option.fill(this, pair.left(), pair.right()); + } + + public synchronized @NotNull List<@NotNull T> processItemStacks(@NotNull List itemStacks, + @NotNull TransactionType type, + @NotNull TransactionOption option) { + List result = new ArrayList<>(itemStacks.size()); + itemStacks.forEach(itemStack -> { + T transactionResult = processItemStack(itemStack, type, option); + result.add(transactionResult); + }); + return result; + } + /** * Adds an {@link ItemStack} to the inventory and sends relevant update to the viewer(s). * - * @param itemStack the item to add - * @param transactionOption the transaction option + * @param itemStack the item to add + * @param option the transaction option * @return true if the item has been successfully added, false otherwise */ - public synchronized @NotNull T addItemStack(@NotNull ItemStack itemStack, @NotNull TransactionOption transactionOption) { - Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); - - final StackingRule stackingRule = itemStack.getStackingRule(); - - // Check filled slot (not air) - for (int i = 0; i < getInnerSize(); i++) { - ItemStack inventoryItem = getItemStack(i); - if (inventoryItem.isAir()) { - continue; - } - if (stackingRule.canBeStacked(itemStack, inventoryItem)) { - final int itemAmount = stackingRule.getAmount(inventoryItem); - if (itemAmount == stackingRule.getMaxSize()) - continue; - final int itemStackAmount = stackingRule.getAmount(itemStack); - final int totalAmount = itemStackAmount + itemAmount; - if (!stackingRule.canApply(itemStack, totalAmount)) { - // Slot cannot accept the whole item, reduce amount to 'itemStack' - itemChangesMap.put(i, stackingRule.apply(inventoryItem, stackingRule.getMaxSize())); - itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); - } else { - // Slot can accept the whole item - itemChangesMap.put(i, stackingRule.apply(inventoryItem, totalAmount)); - itemStack = stackingRule.apply(itemStack, 0); - break; - } - } - } - - // Check air slot to fill - for (int i = 0; i < getInnerSize(); i++) { - ItemStack inventoryItem = getItemStack(i); - if (!inventoryItem.isAir()) { - continue; - } - // Fill the slot - itemChangesMap.put(i, itemStack); - itemStack = stackingRule.apply(itemStack, 0); - break; - } - - return transactionOption.fill(this, itemStack, itemChangesMap); + public @NotNull T addItemStack(@NotNull ItemStack itemStack, @NotNull TransactionOption option) { + return processItemStack(itemStack, TransactionType.ADD, option); } - public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { + public boolean addItemStack(@NotNull ItemStack itemStack) { return addItemStack(itemStack, TransactionOption.ALL_OR_NOTHING); } /** * Adds {@link ItemStack}s to the inventory and sends relevant updates to the viewer(s). * - * @param itemStacks items to add - * @param transactionOption the transaction option + * @param itemStacks items to add + * @param option the transaction option * @return the operation results */ - public @NotNull List<@NotNull T> addItemStacks(@NotNull List itemStacks, @NotNull TransactionOption transactionOption) { - List result = new ArrayList<>(itemStacks.size()); - itemStacks.forEach(itemStack -> { - T transactionResult = addItemStack(itemStack, transactionOption); - result.add(transactionResult); - }); - return result; + public @NotNull List<@NotNull T> addItemStacks(@NotNull List itemStacks, @NotNull TransactionOption option) { + return processItemStacks(itemStacks, TransactionType.ADD, option); } /** @@ -128,32 +102,8 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param itemStack the item to take * @return true if the item has been successfully fully taken, false otherwise */ - public T takeItemStack(@NotNull ItemStack itemStack, @NotNull TransactionOption transactionOption) { - Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); - final StackingRule stackingRule = itemStack.getStackingRule(); - for (int i = 0; i < getInnerSize(); i++) { - ItemStack inventoryItem = getItemStack(i); - if (inventoryItem.isAir()) { - continue; - } - if (stackingRule.canBeStacked(itemStack, inventoryItem)) { - final int itemAmount = stackingRule.getAmount(inventoryItem); - final int itemStackAmount = stackingRule.getAmount(itemStack); - if (itemStackAmount < itemAmount) { - itemChangesMap.put(i, stackingRule.apply(inventoryItem, itemAmount - itemStackAmount)); - itemStack = stackingRule.apply(itemStack, 0); - break; - } - itemChangesMap.put(i, stackingRule.apply(inventoryItem, 0)); - itemStack = stackingRule.apply(itemStack, itemStackAmount - itemAmount); - if (stackingRule.getAmount(itemStack) == 0) { - itemStack = stackingRule.apply(itemStack, 0); - break; - } - } - } - - return transactionOption.fill(this, itemStack, itemChangesMap); + public @NotNull T takeItemStack(@NotNull ItemStack itemStack, @NotNull TransactionOption option) { + return processItemStack(itemStack, TransactionType.TAKE, option); } /** @@ -162,13 +112,8 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param itemStacks items to take * @return the operation results */ - public @NotNull List takeItemStacks(@NotNull List itemStacks, @NotNull TransactionOption transactionOption) { - List result = new ArrayList<>(itemStacks.size()); - itemStacks.forEach(itemStack -> { - T transactionResult = takeItemStack(itemStack, transactionOption); - result.add(transactionResult); - }); - return result; + public @NotNull List<@NotNull T> takeItemStacks(@NotNull List itemStacks, @NotNull TransactionOption option) { + return processItemStacks(itemStacks, TransactionType.TAKE, option); } public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index 27d396a8b..528586f43 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -12,9 +12,7 @@ import net.minestom.server.network.packet.server.play.SetSlotPacket; import net.minestom.server.network.packet.server.play.WindowItemsPacket; import net.minestom.server.network.packet.server.play.WindowPropertyPacket; import net.minestom.server.network.player.PlayerConnection; -import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.inventory.PlayerInventoryUtils; -import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; import java.util.Collections; @@ -123,14 +121,6 @@ public class Inventory extends AbstractInventory implements Viewable { return id; } - @Override - public void setItemStack(int slot, @NotNull ItemStack itemStack) { - Check.argCondition(!MathUtils.isBetween(slot, 0, getSize()), - inventoryType.toString() + " does not have slot " + slot); - - safeItemInsert(slot, itemStack); - } - /** * Refreshes the inventory for all viewers. */ diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 1cfc7aa37..dced78497 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -2,8 +2,6 @@ package net.minestom.server.inventory; import net.minestom.server.entity.Player; import net.minestom.server.event.item.ArmorEquipEvent; -import net.minestom.server.event.player.PlayerAddItemStackEvent; -import net.minestom.server.event.player.PlayerSetItemStackEvent; import net.minestom.server.inventory.click.ClickType; import net.minestom.server.inventory.click.InventoryClickLoopHandler; import net.minestom.server.inventory.click.InventoryClickResult; @@ -45,29 +43,6 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl super.addInventoryCondition(condition); } - @Override - public synchronized void setItemStack(int slot, @NotNull ItemStack itemStack) { - PlayerSetItemStackEvent setItemStackEvent = new PlayerSetItemStackEvent(player, slot, itemStack); - player.callEvent(PlayerSetItemStackEvent.class, setItemStackEvent); - if (setItemStackEvent.isCancelled()) - return; - slot = setItemStackEvent.getSlot(); - itemStack = setItemStackEvent.getItemStack(); - - safeItemInsert(slot, itemStack); - } - - @Override - public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { - PlayerAddItemStackEvent addItemStackEvent = new PlayerAddItemStackEvent(player, itemStack); - player.callEvent(PlayerAddItemStackEvent.class, addItemStackEvent); - if (addItemStackEvent.isCancelled()) - return false; - - itemStack = addItemStackEvent.getItemStack(); - return super.addItemStack(itemStack); - } - @Override public synchronized void clear() { super.clear(); diff --git a/src/main/java/net/minestom/server/inventory/TransactionType.java b/src/main/java/net/minestom/server/inventory/TransactionType.java new file mode 100644 index 000000000..80f2fe97d --- /dev/null +++ b/src/main/java/net/minestom/server/inventory/TransactionType.java @@ -0,0 +1,101 @@ +package net.minestom.server.inventory; + +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.StackingRule; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +/** + * Represents a type of transaction that you can apply to an {@link AbstractInventory}. + */ +public interface TransactionType { + + /** + * Adds an item to the inventory. + * Can either take an air slot or be stacked. + */ + TransactionType ADD = (inventory, itemStack) -> { + Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); + + final StackingRule stackingRule = itemStack.getStackingRule(); + + // Check filled slot (not air) + for (int i = 0; i < inventory.getInnerSize(); i++) { + ItemStack inventoryItem = inventory.getItemStack(i); + if (inventoryItem.isAir()) { + continue; + } + if (stackingRule.canBeStacked(itemStack, inventoryItem)) { + final int itemAmount = stackingRule.getAmount(inventoryItem); + if (itemAmount == stackingRule.getMaxSize()) + continue; + final int itemStackAmount = stackingRule.getAmount(itemStack); + final int totalAmount = itemStackAmount + itemAmount; + if (!stackingRule.canApply(itemStack, totalAmount)) { + // Slot cannot accept the whole item, reduce amount to 'itemStack' + itemChangesMap.put(i, stackingRule.apply(inventoryItem, stackingRule.getMaxSize())); + itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize()); + } else { + // Slot can accept the whole item + itemChangesMap.put(i, stackingRule.apply(inventoryItem, totalAmount)); + itemStack = stackingRule.apply(itemStack, 0); + break; + } + } + } + + // Check air slot to fill + for (int i = 0; i < inventory.getInnerSize(); i++) { + ItemStack inventoryItem = inventory.getItemStack(i); + if (!inventoryItem.isAir()) { + continue; + } + // Fill the slot + itemChangesMap.put(i, itemStack); + itemStack = stackingRule.apply(itemStack, 0); + break; + } + + return Pair.of(itemStack, itemChangesMap); + }; + + /** + * Takes an item from the inventory. + * Can either transform items to air or reduce their amount. + */ + TransactionType TAKE = (inventory, itemStack) -> { + Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); + final StackingRule stackingRule = itemStack.getStackingRule(); + for (int i = 0; i < inventory.getInnerSize(); i++) { + ItemStack inventoryItem = inventory.getItemStack(i); + if (inventoryItem.isAir()) { + continue; + } + if (stackingRule.canBeStacked(itemStack, inventoryItem)) { + final int itemAmount = stackingRule.getAmount(inventoryItem); + final int itemStackAmount = stackingRule.getAmount(itemStack); + if (itemStackAmount < itemAmount) { + itemChangesMap.put(i, stackingRule.apply(inventoryItem, itemAmount - itemStackAmount)); + itemStack = stackingRule.apply(itemStack, 0); + break; + } + itemChangesMap.put(i, stackingRule.apply(inventoryItem, 0)); + itemStack = stackingRule.apply(itemStack, itemStackAmount - itemAmount); + if (stackingRule.getAmount(itemStack) == 0) { + itemStack = stackingRule.apply(itemStack, 0); + break; + } + } + } + + return Pair.of(itemStack, itemChangesMap); + }; + + @NotNull Pair> process(@NotNull AbstractInventory inventory, + @NotNull ItemStack itemStack); + +} diff --git a/src/test/java/demo/commands/GiveCommand.java b/src/test/java/demo/commands/GiveCommand.java index e4d03307c..5e5baba26 100644 --- a/src/test/java/demo/commands/GiveCommand.java +++ b/src/test/java/demo/commands/GiveCommand.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.command.builder.Command; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; +import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.inventory.TransactionOption; import net.minestom.server.item.ItemStack; import net.minestom.server.utils.entity.EntityFinder; @@ -25,6 +26,7 @@ public class GiveCommand extends Command { addSyntax((sender, context) -> { final EntityFinder entityFinder = context.get("target"); int count = context.get("count"); + count = Math.min(count, PlayerInventory.INVENTORY_SIZE * 64); ItemStack itemStack = context.get("item"); List itemStacks; From 7e3035709fd9c3a3f0468f2262be27a2ca06ac5c Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 12 Apr 2021 00:42:32 +0200 Subject: [PATCH 74/77] Annotation, fix cursor item not being cleared --- .../server/inventory/AbstractInventory.java | 10 +++++---- .../minestom/server/inventory/Inventory.java | 22 +++++++++++++------ .../server/inventory/PlayerInventory.java | 2 ++ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 140af5d85..a95114d5b 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -59,7 +59,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo return option.fill(this, pair.left(), pair.right()); } - public synchronized @NotNull List<@NotNull T> processItemStacks(@NotNull List itemStacks, + public synchronized @NotNull List<@NotNull T> processItemStacks(@NotNull List<@NotNull ItemStack> itemStacks, @NotNull TransactionType type, @NotNull TransactionOption option) { List result = new ArrayList<>(itemStacks.size()); @@ -92,7 +92,8 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param option the transaction option * @return the operation results */ - public @NotNull List<@NotNull T> addItemStacks(@NotNull List itemStacks, @NotNull TransactionOption option) { + public @NotNull List<@NotNull T> addItemStacks(@NotNull List<@NotNull ItemStack> itemStacks, + @NotNull TransactionOption option) { return processItemStacks(itemStacks, TransactionType.ADD, option); } @@ -112,7 +113,8 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * @param itemStacks items to take * @return the operation results */ - public @NotNull List<@NotNull T> takeItemStacks(@NotNull List itemStacks, @NotNull TransactionOption option) { + public @NotNull List<@NotNull T> takeItemStacks(@NotNull List<@NotNull ItemStack> itemStacks, + @NotNull TransactionOption option) { return processItemStacks(itemStacks, TransactionType.TAKE, option); } @@ -178,7 +180,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo * * @return a modifiable {@link List} containing all the inventory conditions */ - public @NotNull List getInventoryConditions() { + public @NotNull List<@NotNull InventoryCondition> getInventoryConditions() { return inventoryConditions; } diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index 528586f43..61e783412 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -121,6 +121,14 @@ public class Inventory extends AbstractInventory implements Viewable { return id; } + @Override + public synchronized void clear() { + super.clear(); + // Clear cursor + getViewers().forEach(player -> + setCursorItem(player, ItemStack.AIR)); + } + /** * Refreshes the inventory for all viewers. */ @@ -265,7 +273,7 @@ public class Inventory extends AbstractInventory implements Viewable { * @param player the player to change the cursor item * @param itemStack the cursor item */ - private void setCursorPlayerItem(@NotNull Player player, @NotNull ItemStack itemStack) { + private void refreshPlayerCursorItem(@NotNull Player player, @NotNull ItemStack itemStack) { this.cursorPlayersItem.put(player, itemStack); } @@ -292,7 +300,7 @@ public class Inventory extends AbstractInventory implements Viewable { } else { playerInventory.setItemStack(clickSlot, clickResult.getClicked()); } - setCursorPlayerItem(player, clickResult.getCursor()); + refreshPlayerCursorItem(player, clickResult.getCursor()); if (!clickResult.isCancel()) callClickEvent(player, isInWindow ? this : null, slot, ClickType.LEFT_CLICK, clicked, cursor); @@ -319,7 +327,7 @@ public class Inventory extends AbstractInventory implements Viewable { } else { playerInventory.setItemStack(clickSlot, clickResult.getClicked()); } - setCursorPlayerItem(player, clickResult.getCursor()); + refreshPlayerCursorItem(player, clickResult.getCursor()); if (!clickResult.isCancel()) callClickEvent(player, isInWindow ? this : null, slot, ClickType.RIGHT_CLICK, clicked, cursor); @@ -377,7 +385,7 @@ public class Inventory extends AbstractInventory implements Viewable { updateFromClick(clickResult, player); } - setCursorPlayerItem(player, clickResult.getCursor()); + refreshPlayerCursorItem(player, clickResult.getCursor()); playerInventory.update(); update(); @@ -446,7 +454,7 @@ public class Inventory extends AbstractInventory implements Viewable { } } - setCursorPlayerItem(player, clickResult.getCursor()); + refreshPlayerCursorItem(player, clickResult.getCursor()); return !clickResult.isCancel(); } @@ -484,7 +492,7 @@ public class Inventory extends AbstractInventory implements Viewable { updateFromClick(clickResult, player); } - setCursorPlayerItem(player, clickResult.getCursor()); + refreshPlayerCursorItem(player, clickResult.getCursor()); return !clickResult.isCancel(); } @@ -513,7 +521,7 @@ public class Inventory extends AbstractInventory implements Viewable { if (clickResult.doRefresh()) updateFromClick(clickResult, player); - setCursorPlayerItem(player, clickResult.getCursor()); + refreshPlayerCursorItem(player, clickResult.getCursor()); return !clickResult.isCancel(); } diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index dced78497..a1eb77b30 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -46,6 +46,8 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl @Override public synchronized void clear() { super.clear(); + // Reset cursor + setCursorItem(ItemStack.AIR); // Update equipments this.player.sendPacketToViewersAndSelf(player.getEquipmentsPacket()); } From bba9c70586fb5f00c32973120ca8ed3cce56e494 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 12 Apr 2021 00:45:37 +0200 Subject: [PATCH 75/77] Fix merge --- src/test/java/demo/PlayerInit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 579d10c4e..3a99035b9 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -5,7 +5,6 @@ import demo.generator.NoiseTestGenerator; import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; import net.minestom.server.adventure.audience.Audiences; -import net.minestom.server.benchmark.BenchmarkManager; import net.minestom.server.chat.ColoredText; import net.minestom.server.entity.Entity; import net.minestom.server.entity.GameMode; @@ -30,6 +29,7 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemTag; import net.minestom.server.item.Material; import net.minestom.server.item.metadata.CompassMeta; +import net.minestom.server.monitoring.BenchmarkManager; import net.minestom.server.network.ConnectionManager; import net.minestom.server.ping.ResponseDataConsumer; import net.minestom.server.utils.Position; From aac32420def3046a5b56e925876240e5653c82d4 Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 12 Apr 2021 01:07:05 +0200 Subject: [PATCH 76/77] Annotation cleanup --- .../net/minestom/server/inventory/TransactionOption.java | 6 +++--- .../java/net/minestom/server/inventory/TransactionType.java | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/TransactionOption.java b/src/main/java/net/minestom/server/inventory/TransactionOption.java index 313f9a3ed..0fa871d87 100644 --- a/src/main/java/net/minestom/server/inventory/TransactionOption.java +++ b/src/main/java/net/minestom/server/inventory/TransactionOption.java @@ -13,7 +13,7 @@ public interface TransactionOption { *

* The remaining, can be air. */ - TransactionOption<@NotNull ItemStack> ALL = (inventory, result, itemChangesMap) -> { + TransactionOption ALL = (inventory, result, itemChangesMap) -> { itemChangesMap.forEach(inventory::safeItemInsert); return result; }; @@ -23,7 +23,7 @@ public interface TransactionOption { *

* Returns true if the item has been added, false if nothing changed. */ - TransactionOption<@NotNull Boolean> ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> { + TransactionOption ALL_OR_NOTHING = (inventory, result, itemChangesMap) -> { if (result.isAir()) { // Item can be fully placed inside the inventory, do so itemChangesMap.forEach(inventory::safeItemInsert); @@ -39,7 +39,7 @@ public interface TransactionOption { *

* Returns true if the item can be fully added, false otherwise. */ - TransactionOption<@NotNull Boolean> DRY_RUN = (inventory, result, itemChangesMap) -> result.isAir(); + TransactionOption DRY_RUN = (inventory, result, itemChangesMap) -> result.isAir(); @NotNull T fill(@NotNull AbstractInventory inventory, @NotNull ItemStack result, diff --git a/src/main/java/net/minestom/server/inventory/TransactionType.java b/src/main/java/net/minestom/server/inventory/TransactionType.java index 80f2fe97d..fa0bafc67 100644 --- a/src/main/java/net/minestom/server/inventory/TransactionType.java +++ b/src/main/java/net/minestom/server/inventory/TransactionType.java @@ -12,6 +12,7 @@ import java.util.Map; /** * Represents a type of transaction that you can apply to an {@link AbstractInventory}. */ +@FunctionalInterface public interface TransactionType { /** From 8f6a651bda2cf721706d6261b0bb21829b3dc5bf Mon Sep 17 00:00:00 2001 From: TheMode Date: Mon, 12 Apr 2021 01:27:33 +0200 Subject: [PATCH 77/77] Added StackingRule#apply with unary operator for amount --- .../server/inventory/click/InventoryClickProcessor.java | 8 ++++---- src/main/java/net/minestom/server/item/StackingRule.java | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java index afc1881ad..d18b2e7af 100644 --- a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java +++ b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java @@ -95,18 +95,17 @@ public class InventoryClickProcessor { if (!clickedRule.canApply(clicked, amount)) { return clickResult; } else { - resultCursor = cursorRule.apply(cursor, cursorRule.getAmount(cursor) - 1); + resultCursor = cursorRule.apply(cursor, operand -> operand - 1); resultClicked = clickedRule.apply(clicked, amount); } } else { if (cursor.isAir()) { final int amount = (int) Math.ceil((double) clickedRule.getAmount(clicked) / 2d); resultCursor = cursorRule.apply(clicked, amount); - resultClicked = clickedRule.apply(clicked, clickedRule.getAmount(clicked) / 2); + resultClicked = clickedRule.apply(clicked, operand -> operand / 2); } else { if (clicked.isAir()) { - final int amount = cursorRule.getAmount(cursor); - resultCursor = cursorRule.apply(cursor, amount - 1); + resultCursor = cursorRule.apply(cursor, operand -> operand - 1); resultClicked = clickedRule.apply(cursor, 1); } else { resultCursor = clicked; @@ -573,6 +572,7 @@ public class InventoryClickProcessor { @NotNull ClickType clickType, @NotNull ItemStack clicked, @NotNull ItemStack cursor) { InventoryClickEvent inventoryClickEvent = new InventoryClickEvent(inventory, player, slot, clickType, clicked, cursor); player.callEvent(InventoryClickEvent.class, inventoryClickEvent); + System.out.println("click"); } public void clearCache(@NotNull Player player) { diff --git a/src/main/java/net/minestom/server/item/StackingRule.java b/src/main/java/net/minestom/server/item/StackingRule.java index cf6bcbbab..68c22862e 100644 --- a/src/main/java/net/minestom/server/item/StackingRule.java +++ b/src/main/java/net/minestom/server/item/StackingRule.java @@ -3,6 +3,8 @@ package net.minestom.server.item; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import java.util.function.IntUnaryOperator; + /** * Represents the stacking rule of an {@link ItemStack}. * This can be used to mimic the vanilla one (using the displayed item quantity) @@ -46,6 +48,11 @@ public abstract class StackingRule { @Contract("_, _ -> new") public abstract @NotNull ItemStack apply(@NotNull ItemStack item, int newAmount); + @Contract("_, _ -> new") + public @NotNull ItemStack apply(@NotNull ItemStack item, @NotNull IntUnaryOperator amountOperator) { + return apply(item, amountOperator.applyAsInt(getAmount(item))); + } + /** * Used to determine the current stack size of an {@link ItemStack}. * It is possible to have it stored in its {@link net.minestom.server.data.Data} object, lore, etc...