fix: make new packets ComponentHolding

This commit is contained in:
mworzala 2024-11-02 19:20:12 -04:00 committed by Matt Worzala
parent b7d89c84a7
commit 2df89f23c9
11 changed files with 256 additions and 49 deletions

View File

@ -22,6 +22,8 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability; import org.jetbrains.annotations.UnknownNullability;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.IntUnaryOperator; import java.util.function.IntUnaryOperator;
@ -150,9 +152,9 @@ public sealed interface ItemStack extends TagReadable, DataComponent.Holder, Hov
* Applies a transformation to the value of a component, only if present. * Applies a transformation to the value of a component, only if present.
* *
* @param component The component type to modify * @param component The component type to modify
* @param operator The transformation function * @param operator The transformation function
* @param <T> The component type
* @return A new ItemStack if the component was transformed, otherwise this. * @return A new ItemStack if the component was transformed, otherwise this.
* @param <T> The component type
*/ */
default <T> @NotNull ItemStack with(@NotNull DataComponent<T> component, @NotNull UnaryOperator<T> operator) { default <T> @NotNull ItemStack with(@NotNull DataComponent<T> component, @NotNull UnaryOperator<T> operator) {
T value = get(component); T value = get(component);
@ -238,6 +240,7 @@ public sealed interface ItemStack extends TagReadable, DataComponent.Holder, Hov
/** /**
* Converts this itemstack back into a builder (starting from the current state). * Converts this itemstack back into a builder (starting from the current state).
*
* @return this itemstack, as a builder. * @return this itemstack, as a builder.
*/ */
@NotNull ItemStack.Builder builder(); @NotNull ItemStack.Builder builder();
@ -259,6 +262,29 @@ public sealed interface ItemStack extends TagReadable, DataComponent.Holder, Hov
} }
} }
// These functions are mirrors of ComponentHolder, but we can't actually implement that interface
// because it conflicts with DataComponent.Holder.
static @NotNull Collection<Component> textComponents(@NotNull ItemStack itemStack) {
final var components = new ArrayList<>(itemStack.get(ItemComponent.LORE, List.of()));
final var displayName = itemStack.get(ItemComponent.CUSTOM_NAME);
if (displayName != null) components.add(displayName);
final var itemName = itemStack.get(ItemComponent.ITEM_NAME);
if (itemName != null) components.add(itemName);
return List.copyOf(components);
}
static @NotNull ItemStack copyWithOperator(@NotNull ItemStack itemStack, @NotNull UnaryOperator<Component> operator) {
return itemStack
.with(ItemComponent.CUSTOM_NAME, operator)
.with(ItemComponent.ITEM_NAME, operator)
.with(ItemComponent.LORE, (UnaryOperator<List<Component>>) lines -> {
final var translatedComponents = new ArrayList<Component>();
lines.forEach(component -> translatedComponents.add(operator.apply(component)));
return translatedComponents;
});
}
sealed interface Builder permits ItemStackImpl.Builder { sealed interface Builder permits ItemStackImpl.Builder {
@Contract(value = "_ -> this") @Contract(value = "_ -> this")

View File

@ -2,11 +2,11 @@ package net.minestom.server.listener;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.play.ClientPlaceRecipePacket; import net.minestom.server.network.packet.client.play.ClientPlaceRecipePacket;
import net.minestom.server.network.packet.server.play.PlaceGhostRecipePacket;
public class RecipeListener { public class RecipeListener {
public static void listener(ClientPlaceRecipePacket packet, Player player) { public static void listener(ClientPlaceRecipePacket packet, Player player) {
player.sendPacket(new PlaceGhostRecipePacket(packet.windowId(), packet.recipe())); // TODO(1.21.2)
// player.sendPacket(new PlaceGhostRecipePacket(packet.windowId(), packet.recipe()));
} }
} }

View File

@ -6,15 +6,10 @@ import net.minestom.server.network.packet.client.ClientPacket;
import static net.minestom.server.network.NetworkBuffer.*; import static net.minestom.server.network.NetworkBuffer.*;
public record ClientPlaceRecipePacket(byte windowId, String recipe, boolean makeAll) implements ClientPacket { public record ClientPlaceRecipePacket(byte windowId, int recipeDisplayId, boolean makeAll) implements ClientPacket {
public static final NetworkBuffer.Type<ClientPlaceRecipePacket> SERIALIZER = NetworkBufferTemplate.template( public static final NetworkBuffer.Type<ClientPlaceRecipePacket> SERIALIZER = NetworkBufferTemplate.template(
BYTE, ClientPlaceRecipePacket::windowId, BYTE, ClientPlaceRecipePacket::windowId,
STRING, ClientPlaceRecipePacket::recipe, VAR_INT, ClientPlaceRecipePacket::recipeDisplayId,
BOOLEAN, ClientPlaceRecipePacket::makeAll, BOOLEAN, ClientPlaceRecipePacket::makeAll,
ClientPlaceRecipePacket::new); ClientPlaceRecipePacket::new);
public ClientPlaceRecipePacket {
if (recipe.length() > 256) {
throw new IllegalArgumentException("'recipe' cannot be longer than 256 characters.");
}
}
} }

View File

@ -2,18 +2,13 @@ package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.entity.EquipmentSlot; import net.minestom.server.entity.EquipmentSlot;
import net.minestom.server.item.ItemComponent;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.*;
import java.util.EnumMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import static net.minestom.server.network.NetworkBuffer.BYTE; import static net.minestom.server.network.NetworkBuffer.BYTE;
import static net.minestom.server.network.NetworkBuffer.VAR_INT; import static net.minestom.server.network.NetworkBuffer.VAR_INT;
@ -48,19 +43,18 @@ public record EntityEquipmentPacket(int entityId,
@Override @Override
public @NotNull Collection<Component> components() { public @NotNull Collection<Component> components() {
return this.equipments.values() final var components = new ArrayList<Component>();
.stream() for (var itemStack : this.equipments.values())
.map(item -> item.get(ItemComponent.CUSTOM_NAME)) components.addAll(ItemStack.textComponents(itemStack));
.filter(Objects::nonNull) return List.copyOf(components);
.collect(Collectors.toList());
} }
@Override @Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) { public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
final var map = new EnumMap<EquipmentSlot, ItemStack>(EquipmentSlot.class); final var newEquipment = new EnumMap<EquipmentSlot, ItemStack>(EquipmentSlot.class);
this.equipments.forEach((key, value) -> map.put(key, value.with(ItemComponent.CUSTOM_NAME, operator))); for (var entry : this.equipments.entrySet())
newEquipment.put(entry.getKey(), ItemStack.copyWithOperator(entry.getValue(), operator));
return new EntityEquipmentPacket(this.entityId, map); return new EntityEquipmentPacket(this.entityId, newEquipment);
} }
private static Map<EquipmentSlot, ItemStack> readEquipments(@NotNull NetworkBuffer reader) { private static Map<EquipmentSlot, ItemStack> readEquipments(@NotNull NetworkBuffer reader) {

View File

@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
import static net.minestom.server.network.NetworkBuffer.STRING; import static net.minestom.server.network.NetworkBuffer.STRING;
import static net.minestom.server.network.NetworkBuffer.VAR_INT; import static net.minestom.server.network.NetworkBuffer.VAR_INT;
// TODO: Recipe is now a RecipeDisplay object need to look further into it. // TODO(1.21.2): Recipe is now a RecipeDisplay object need to look further into it.
public record PlaceGhostRecipePacket(int windowId, @NotNull String recipe) implements ServerPacket.Play { public record PlaceGhostRecipePacket(int windowId, @NotNull String recipe) implements ServerPacket.Play {
public static final NetworkBuffer.Type<PlaceGhostRecipePacket> SERIALIZER = NetworkBufferTemplate.template( public static final NetworkBuffer.Type<PlaceGhostRecipePacket> SERIALIZER = NetworkBufferTemplate.template(
VAR_INT, PlaceGhostRecipePacket::windowId, VAR_INT, PlaceGhostRecipePacket::windowId,

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play; package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.NetworkBufferTemplate;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
@ -10,11 +11,14 @@ import net.minestom.server.recipe.display.RecipeDisplay;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.UnaryOperator;
import static net.minestom.server.network.NetworkBuffer.BOOLEAN; import static net.minestom.server.network.NetworkBuffer.BOOLEAN;
public record RecipeBookAddPacket(@NotNull List<Entry> entries, boolean replace) implements ServerPacket.Play { public record RecipeBookAddPacket(@NotNull List<Entry> entries, boolean replace) implements ServerPacket.Play, ServerPacket.ComponentHolding {
public static final byte FLAG_NOTIFICATION = 1; public static final byte FLAG_NOTIFICATION = 1;
public static final byte FLAG_HIGHLIGHT = 1 << 1; public static final byte FLAG_HIGHLIGHT = 1 << 1;
@ -55,4 +59,21 @@ public record RecipeBookAddPacket(@NotNull List<Entry> entries, boolean replace)
} }
} }
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<Component>();
for (Entry entry : entries)
components.addAll(entry.display.components());
return components;
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
final var entries = new ArrayList<Entry>();
for (Entry entry : this.entries) {
entries.add(new Entry(entry.displayId, entry.display.copyWithOperator(operator),
entry.group, entry.category, entry.craftingRequirements, entry.flags));
}
return new RecipeBookAddPacket(entries, replace);
}
} }

View File

@ -1,13 +1,27 @@
package net.minestom.server.network.packet.server.play; package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.NetworkBufferTemplate;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public record SetCursorItemPacket(@NotNull ItemStack itemStack) implements ServerPacket.Play { import java.util.Collection;
import java.util.function.UnaryOperator;
public record SetCursorItemPacket(@NotNull ItemStack itemStack) implements ServerPacket.Play, ServerPacket.ComponentHolding {
public static final NetworkBuffer.Type<SetCursorItemPacket> SERIALIZER = NetworkBufferTemplate.template( public static final NetworkBuffer.Type<SetCursorItemPacket> SERIALIZER = NetworkBufferTemplate.template(
ItemStack.NETWORK_TYPE, SetCursorItemPacket::itemStack, ItemStack.NETWORK_TYPE, SetCursorItemPacket::itemStack,
SetCursorItemPacket::new); SetCursorItemPacket::new);
@Override
public @NotNull Collection<Component> components() {
return ItemStack.textComponents(itemStack);
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new SetCursorItemPacket(ItemStack.copyWithOperator(itemStack, operator));
}
} }

View File

@ -1,16 +1,30 @@
package net.minestom.server.network.packet.server.play; package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.NetworkBufferTemplate;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.function.UnaryOperator;
import static net.minestom.server.network.NetworkBuffer.VAR_INT; import static net.minestom.server.network.NetworkBuffer.VAR_INT;
public record SetPlayerInventorySlotPacket(int slot, @NotNull ItemStack itemStack) implements ServerPacket.Play { public record SetPlayerInventorySlotPacket(int slot, @NotNull ItemStack itemStack) implements ServerPacket.Play, ServerPacket.ComponentHolding {
public static final NetworkBuffer.Type<SetPlayerInventorySlotPacket> SERIALIZER = NetworkBufferTemplate.template( public static final NetworkBuffer.Type<SetPlayerInventorySlotPacket> SERIALIZER = NetworkBufferTemplate.template(
VAR_INT, SetPlayerInventorySlotPacket::slot, VAR_INT, SetPlayerInventorySlotPacket::slot,
ItemStack.NETWORK_TYPE, SetPlayerInventorySlotPacket::itemStack, ItemStack.NETWORK_TYPE, SetPlayerInventorySlotPacket::itemStack,
SetPlayerInventorySlotPacket::new); SetPlayerInventorySlotPacket::new);
@Override
public @NotNull Collection<Component> components() {
return ItemStack.textComponents(itemStack);
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new SetPlayerInventorySlotPacket(slot, ItemStack.copyWithOperator(itemStack, operator));
}
} }

View File

@ -1,16 +1,13 @@
package net.minestom.server.network.packet.server.play; package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.item.ItemComponent;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.NetworkBufferTemplate;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import static net.minestom.server.network.NetworkBuffer.SHORT; import static net.minestom.server.network.NetworkBuffer.SHORT;
@ -27,24 +24,12 @@ public record SetSlotPacket(int windowId, int stateId, short slot,
@Override @Override
public @NotNull Collection<Component> components() { public @NotNull Collection<Component> components() {
final var components = new ArrayList<>(this.itemStack.get(ItemComponent.LORE, List.of())); return ItemStack.textComponents(itemStack);
final var displayName = this.itemStack.get(ItemComponent.CUSTOM_NAME);
if (displayName != null) components.add(displayName);
final var itemName = this.itemStack.get(ItemComponent.ITEM_NAME);
if (itemName != null) components.add(itemName);
return List.copyOf(components);
} }
@Override @Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) { public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new SetSlotPacket(this.windowId, this.stateId, this.slot, this.itemStack return new SetSlotPacket(this.windowId, this.stateId, this.slot, ItemStack.copyWithOperator(this.itemStack, operator));
.with(ItemComponent.CUSTOM_NAME, operator)
.with(ItemComponent.ITEM_NAME, operator)
.with(ItemComponent.LORE, (UnaryOperator<List<Component>>) lines -> {
final var translatedComponents = new ArrayList<Component>();
lines.forEach(component -> translatedComponents.add(operator.apply(component)));
return translatedComponents;
}));
} }
} }

View File

@ -1,12 +1,17 @@
package net.minestom.server.recipe.display; package net.minestom.server.recipe.display;
import net.kyori.adventure.text.Component;
import net.minestom.server.adventure.ComponentHolder;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.NetworkBufferTemplate;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.UnaryOperator;
public sealed interface RecipeDisplay { public sealed interface RecipeDisplay extends ComponentHolder<RecipeDisplay> {
@NotNull NetworkBuffer.Type<RecipeDisplay> NETWORK_TYPE = RecipeDisplayType.NETWORK_TYPE @NotNull NetworkBuffer.Type<RecipeDisplay> NETWORK_TYPE = RecipeDisplayType.NETWORK_TYPE
.unionType(RecipeDisplay::dataSerializer, RecipeDisplay::recipeDisplayToType); .unionType(RecipeDisplay::dataSerializer, RecipeDisplay::recipeDisplayToType);
@ -22,6 +27,24 @@ public sealed interface RecipeDisplay {
SlotDisplay.NETWORK_TYPE, CraftingShapeless::result, SlotDisplay.NETWORK_TYPE, CraftingShapeless::result,
SlotDisplay.NETWORK_TYPE, CraftingShapeless::craftingStation, SlotDisplay.NETWORK_TYPE, CraftingShapeless::craftingStation,
CraftingShapeless::new); CraftingShapeless::new);
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<Component>();
for (SlotDisplay ingredient : ingredients)
components.addAll(ingredient.components());
components.addAll(result.components());
components.addAll(craftingStation.components());
return List.copyOf(components);
}
@Override
public @NotNull RecipeDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
final var newIngredients = new ArrayList<SlotDisplay>();
for (SlotDisplay ingredient : ingredients)
newIngredients.add(ingredient.copyWithOperator(operator));
return new CraftingShapeless(newIngredients, result.copyWithOperator(operator), craftingStation.copyWithOperator(operator));
}
} }
record CraftingShaped( record CraftingShaped(
@ -45,6 +68,24 @@ public sealed interface RecipeDisplay {
throw new IllegalArgumentException("Invalid shaped recipe, ingredients size must be equal to width * height"); throw new IllegalArgumentException("Invalid shaped recipe, ingredients size must be equal to width * height");
ingredients = List.copyOf(ingredients); ingredients = List.copyOf(ingredients);
} }
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<Component>();
for (SlotDisplay ingredient : ingredients)
components.addAll(ingredient.components());
components.addAll(result.components());
components.addAll(craftingStation.components());
return List.copyOf(components);
}
@Override
public @NotNull RecipeDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
final var newIngredients = new ArrayList<SlotDisplay>();
for (SlotDisplay ingredient : ingredients)
newIngredients.add(ingredient.copyWithOperator(operator));
return new CraftingShaped(width, height, newIngredients, result.copyWithOperator(operator), craftingStation.copyWithOperator(operator));
}
} }
record Furnace( record Furnace(
@ -62,6 +103,23 @@ public sealed interface RecipeDisplay {
NetworkBuffer.VAR_INT, Furnace::duration, NetworkBuffer.VAR_INT, Furnace::duration,
NetworkBuffer.FLOAT, Furnace::experience, NetworkBuffer.FLOAT, Furnace::experience,
Furnace::new); Furnace::new);
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<Component>();
components.addAll(ingredient.components());
components.addAll(fuel.components());
components.addAll(result.components());
components.addAll(craftingStation.components());
return List.copyOf(components);
}
@Override
public @NotNull RecipeDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new Furnace(ingredient.copyWithOperator(operator), fuel.copyWithOperator(operator),
result.copyWithOperator(operator), craftingStation.copyWithOperator(operator),
duration, experience);
}
} }
record Stonecutter( record Stonecutter(
@ -74,6 +132,21 @@ public sealed interface RecipeDisplay {
SlotDisplay.NETWORK_TYPE, Stonecutter::result, SlotDisplay.NETWORK_TYPE, Stonecutter::result,
SlotDisplay.NETWORK_TYPE, Stonecutter::craftingStation, SlotDisplay.NETWORK_TYPE, Stonecutter::craftingStation,
Stonecutter::new); Stonecutter::new);
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<Component>();
components.addAll(ingredient.components());
components.addAll(result.components());
components.addAll(craftingStation.components());
return List.copyOf(components);
}
@Override
public @NotNull RecipeDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new Stonecutter(ingredient.copyWithOperator(operator), result.copyWithOperator(operator),
craftingStation.copyWithOperator(operator));
}
} }
record Smithing( record Smithing(
@ -90,6 +163,23 @@ public sealed interface RecipeDisplay {
SlotDisplay.NETWORK_TYPE, Smithing::result, SlotDisplay.NETWORK_TYPE, Smithing::result,
SlotDisplay.NETWORK_TYPE, Smithing::craftingStation, SlotDisplay.NETWORK_TYPE, Smithing::craftingStation,
Smithing::new); Smithing::new);
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<Component>();
components.addAll(template.components());
components.addAll(base.components());
components.addAll(addition.components());
components.addAll(result.components());
components.addAll(craftingStation.components());
return List.copyOf(components);
}
@Override
public @NotNull RecipeDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new Smithing(template.copyWithOperator(operator), base.copyWithOperator(operator),
addition.copyWithOperator(operator), result.copyWithOperator(operator), craftingStation.copyWithOperator(operator));
}
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})

View File

@ -1,14 +1,19 @@
package net.minestom.server.recipe.display; package net.minestom.server.recipe.display;
import net.kyori.adventure.text.Component;
import net.minestom.server.adventure.ComponentHolder;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.NetworkBufferTemplate; import net.minestom.server.network.NetworkBufferTemplate;
import net.minestom.server.utils.Unit; import net.minestom.server.utils.Unit;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.UnaryOperator;
public sealed interface SlotDisplay { public sealed interface SlotDisplay extends ComponentHolder<SlotDisplay> {
@NotNull NetworkBuffer.Type<SlotDisplay> NETWORK_TYPE = SlotDisplayType.NETWORK_TYPE @NotNull NetworkBuffer.Type<SlotDisplay> NETWORK_TYPE = SlotDisplayType.NETWORK_TYPE
.unionType(SlotDisplay::dataSerializer, SlotDisplay::slotDisplayToType); .unionType(SlotDisplay::dataSerializer, SlotDisplay::slotDisplayToType);
@ -41,6 +46,16 @@ public sealed interface SlotDisplay {
public static final NetworkBuffer.Type<ItemStack> NETWORK_TYPE = NetworkBufferTemplate.template( public static final NetworkBuffer.Type<ItemStack> NETWORK_TYPE = NetworkBufferTemplate.template(
net.minestom.server.item.ItemStack.STRICT_NETWORK_TYPE, ItemStack::itemStack, net.minestom.server.item.ItemStack.STRICT_NETWORK_TYPE, ItemStack::itemStack,
ItemStack::new); ItemStack::new);
@Override
public @NotNull Collection<Component> components() {
return net.minestom.server.item.ItemStack.textComponents(itemStack);
}
@Override
public @NotNull SlotDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new ItemStack(net.minestom.server.item.ItemStack.copyWithOperator(itemStack, operator));
}
} }
record Tag(@NotNull String tagKey) implements SlotDisplay { record Tag(@NotNull String tagKey) implements SlotDisplay {
@ -59,6 +74,21 @@ public sealed interface SlotDisplay {
SlotDisplay.NETWORK_TYPE, SmithingTrim::trimMaterial, SlotDisplay.NETWORK_TYPE, SmithingTrim::trimMaterial,
SlotDisplay.NETWORK_TYPE, SmithingTrim::trimPattern, SlotDisplay.NETWORK_TYPE, SmithingTrim::trimPattern,
SmithingTrim::new); SmithingTrim::new);
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<>(base.components());
components.addAll(trimMaterial.components());
components.addAll(trimPattern.components());
return List.copyOf(components);
}
@Override
public @NotNull SlotDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new SmithingTrim(base.copyWithOperator(operator),
trimMaterial.copyWithOperator(operator),
trimPattern.copyWithOperator(operator));
}
} }
record WithRemainder(@NotNull SlotDisplay input, @NotNull SlotDisplay remainder) implements SlotDisplay { record WithRemainder(@NotNull SlotDisplay input, @NotNull SlotDisplay remainder) implements SlotDisplay {
@ -66,6 +96,18 @@ public sealed interface SlotDisplay {
SlotDisplay.NETWORK_TYPE, WithRemainder::input, SlotDisplay.NETWORK_TYPE, WithRemainder::input,
SlotDisplay.NETWORK_TYPE, WithRemainder::remainder, SlotDisplay.NETWORK_TYPE, WithRemainder::remainder,
WithRemainder::new); WithRemainder::new);
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<>(input.components());
components.addAll(remainder.components());
return List.copyOf(components);
}
@Override
public @NotNull SlotDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new WithRemainder(input.copyWithOperator(operator), remainder.copyWithOperator(operator));
}
} }
record Composite(@NotNull List<SlotDisplay> contents) implements SlotDisplay { record Composite(@NotNull List<SlotDisplay> contents) implements SlotDisplay {
@ -76,6 +118,32 @@ public sealed interface SlotDisplay {
public Composite { public Composite {
contents = List.copyOf(contents); contents = List.copyOf(contents);
} }
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<Component>();
for (var display : contents)
components.addAll(display.components());
return List.copyOf(components);
}
@Override
public @NotNull SlotDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
final var newContents = new ArrayList<SlotDisplay>();
for (var display : contents)
newContents.add(display.copyWithOperator(operator));
return new Composite(newContents);
}
}
@Override
default @NotNull Collection<Component> components() {
return List.of();
}
@Override
default @NotNull SlotDisplay copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return this;
} }
private static NetworkBuffer.Type<SlotDisplay> dataSerializer(@NotNull SlotDisplayType type) { private static NetworkBuffer.Type<SlotDisplay> dataSerializer(@NotNull SlotDisplayType type) {