Add ComponentHolderServerPacket to some packets (#1275)

This commit is contained in:
Marfien 2022-09-02 22:23:42 +02:00 committed by GitHub
parent c270712798
commit eef95ae5d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 525 additions and 38 deletions

View File

@ -1,13 +1,18 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
public record ActionBarPacket(@NotNull Component text) implements ServerPacket {
import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator;
public record ActionBarPacket(@NotNull Component text) implements ComponentHoldingServerPacket {
public ActionBarPacket(BinaryReader reader) {
this(reader.readComponent());
}
@ -21,4 +26,14 @@ public record ActionBarPacket(@NotNull Component text) implements ServerPacket {
public int getId() {
return ServerPacketIdentifier.ACTION_BAR;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.text);
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new ActionBarPacket(operator.apply(this.text));
}
}

View File

@ -2,7 +2,9 @@ package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.advancements.FrameType;
import net.minestom.server.adventure.ComponentHolder;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
@ -11,11 +13,13 @@ import net.minestom.server.utils.binary.Writeable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.*;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping> advancementMappings,
@NotNull List<String> identifiersToRemove,
@NotNull List<ProgressMapping> progressMappings) implements ServerPacket {
@NotNull List<ProgressMapping> progressMappings) implements ComponentHoldingServerPacket {
public AdvancementsPacket {
advancementMappings = List.copyOf(advancementMappings);
identifiersToRemove = List.copyOf(identifiersToRemove);
@ -41,10 +45,35 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
return ServerPacketIdentifier.ADVANCEMENTS;
}
// TODO is the display-item needed to be updated?
@Override
public @NotNull Collection<Component> components() {
final var displayData = this.advancementMappings.stream().map(AdvancementMapping::value).map(Advancement::displayData).filter(Objects::nonNull).toList();
final var titles = displayData.stream().map(DisplayData::title).toList();
final var descriptions = displayData.stream().map(DisplayData::description).toList();
final var list = new ArrayList<Component>();
list.addAll(titles);
list.addAll(descriptions);
return List.copyOf(list);
}
@Override
public @NotNull ServerPacket copyWithOperator(final @NotNull UnaryOperator<Component> operator) {
return new AdvancementsPacket(
this.reset,
this.advancementMappings.stream().map(mapping -> mapping.copyWithOperator(operator)).toList(),
this.identifiersToRemove,
this.progressMappings
);
}
/**
* AdvancementMapping maps the namespaced ID to the Advancement.
*/
public record AdvancementMapping(@NotNull String key, @NotNull Advancement value) implements Writeable {
public record AdvancementMapping(@NotNull String key, @NotNull Advancement value) implements Writeable, ComponentHolder<AdvancementMapping> {
public AdvancementMapping(BinaryReader reader) {
this(reader.readSizedString(), new Advancement(reader));
}
@ -54,11 +83,21 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
writer.writeSizedString(key);
writer.write(value);
}
@Override
public @NotNull Collection<Component> components() {
return this.value.components();
}
@Override
public @NotNull AdvancementMapping copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return this.value.displayData == null ? this : new AdvancementMapping(this.key, this.value.copyWithOperator(operator));
}
}
public record Advancement(@Nullable String parentIdentifier, @Nullable DisplayData displayData,
@NotNull List<String> criteria,
@NotNull List<Requirement> requirements) implements Writeable {
@NotNull List<Requirement> requirements) implements Writeable, ComponentHolder<Advancement> {
public Advancement {
criteria = List.copyOf(criteria);
requirements = List.copyOf(requirements);
@ -80,6 +119,16 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
writer.writeVarIntList(criteria, BinaryWriter::writeSizedString);
writer.writeVarIntList(requirements, BinaryWriter::write);
}
@Override
public @NotNull Collection<Component> components() {
return this.displayData != null ? this.displayData.components() : List.of();
}
@Override
public @NotNull Advancement copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return this.displayData == null ? this : new Advancement(this.parentIdentifier, this.displayData.copyWithOperator(operator), this.criteria, this.requirements);
}
}
public record Requirement(@NotNull List<String> requirements) implements Writeable {
@ -100,7 +149,7 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
public record DisplayData(@NotNull Component title, @NotNull Component description,
@NotNull ItemStack icon, @NotNull FrameType frameType,
int flags, @Nullable String backgroundTexture,
float x, float y) implements Writeable {
float x, float y) implements Writeable, ComponentHolder<DisplayData> {
public DisplayData(BinaryReader reader) {
this(read(reader));
}
@ -141,6 +190,16 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
writer.writeFloat(x);
writer.writeFloat(y);
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.title, this.description);
}
@Override
public @NotNull DisplayData copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new DisplayData(operator.apply(this.title), operator.apply(this.description), this.icon, this.frameType, this.flags, this.backgroundTexture, this.x, this.y);
}
}
public record ProgressMapping(@NotNull String key, @NotNull AdvancementProgress progress) implements Writeable {

View File

@ -3,6 +3,8 @@ package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.text.Component;
import net.minestom.server.adventure.AdventurePacketConvertor;
import net.minestom.server.adventure.ComponentHolder;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
@ -10,9 +12,12 @@ import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.Writeable;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.function.UnaryOperator;
public record BossBarPacket(@NotNull UUID uuid, @NotNull Action action) implements ServerPacket {
public record BossBarPacket(@NotNull UUID uuid, @NotNull Action action) implements ComponentHoldingServerPacket {
public BossBarPacket(BinaryReader reader) {
this(reader.readUuid(), switch (reader.readVarInt()) {
case 0 -> new AddAction(reader);
@ -32,13 +37,27 @@ public record BossBarPacket(@NotNull UUID uuid, @NotNull Action action) implemen
writer.write(action);
}
@Override
public @NotNull Collection<Component> components() {
return this.action instanceof ComponentHolder<?> holder
? holder.components()
: List.of();
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return this.action instanceof ComponentHolder<?> holder
? new BossBarPacket(this.uuid, (Action) holder.copyWithOperator(operator))
: this;
}
public sealed interface Action extends Writeable
permits AddAction, RemoveAction, UpdateHealthAction, UpdateTitleAction, UpdateStyleAction, UpdateFlagsAction {
int id();
}
public record AddAction(@NotNull Component title, float health, @NotNull BossBar.Color color,
@NotNull BossBar.Overlay overlay, byte flags) implements Action {
@NotNull BossBar.Overlay overlay, byte flags) implements Action, ComponentHolder<AddAction> {
public AddAction(@NotNull BossBar bar) {
this(bar.name(), bar.progress(), bar.color(), bar.overlay(),
AdventurePacketConvertor.getBossBarFlagValue(bar.flags()));
@ -63,6 +82,16 @@ public record BossBarPacket(@NotNull UUID uuid, @NotNull Action action) implemen
public int id() {
return 0;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.title);
}
@Override
public @NotNull AddAction copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new AddAction(operator.apply(this.title), this.health, this.color, this.overlay, this.flags);
}
}
public record RemoveAction() implements Action {
@ -96,7 +125,7 @@ public record BossBarPacket(@NotNull UUID uuid, @NotNull Action action) implemen
}
}
public record UpdateTitleAction(@NotNull Component title) implements Action {
public record UpdateTitleAction(@NotNull Component title) implements Action, ComponentHolder<UpdateTitleAction> {
public UpdateTitleAction(@NotNull BossBar bar) {
this(bar.name());
}
@ -114,6 +143,16 @@ public record BossBarPacket(@NotNull UUID uuid, @NotNull Action action) implemen
public int id() {
return 3;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.title);
}
@Override
public @NotNull UpdateTitleAction copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new UpdateTitleAction(operator.apply(this.title));
}
}
public record UpdateStyleAction(@NotNull BossBar.Color color,

View File

@ -10,7 +10,7 @@ import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.function.UnaryOperator;
@ -38,7 +38,7 @@ public record ChatMessagePacket(@NotNull Component message, @NotNull ChatPositio
@Override
public @NotNull Collection<Component> components() {
return Collections.singleton(message);
return List.of(message);
}
@Override

View File

@ -1,14 +1,19 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator;
public record DeathCombatEventPacket(int playerId, int entityId,
@NotNull Component message) implements ServerPacket {
@NotNull Component message) implements ComponentHoldingServerPacket {
public DeathCombatEventPacket(BinaryReader reader) {
this(reader.readVarInt(), reader.readInt(), reader.readComponent());
}
@ -24,4 +29,14 @@ public record DeathCombatEventPacket(int playerId, int entityId,
public int getId() {
return ServerPacketIdentifier.DEATH_COMBAT_EVENT;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.message);
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new DeathCombatEventPacket(this.playerId, this.entityId, operator.apply(this.message));
}
}

View File

@ -9,7 +9,7 @@ import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.UnaryOperator;
public record DisconnectPacket(@NotNull Component message) implements ComponentHoldingServerPacket {
@ -29,7 +29,7 @@ public record DisconnectPacket(@NotNull Component message) implements ComponentH
@Override
public @NotNull Collection<Component> components() {
return Collections.singleton(message);
return List.of(message);
}
@Override

View File

@ -1,18 +1,24 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.entity.EquipmentSlot;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.EnumMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
public record EntityEquipmentPacket(int entityId,
@NotNull Map<EquipmentSlot, ItemStack> equipments) implements ServerPacket {
@NotNull Map<EquipmentSlot, ItemStack> equipments) implements ComponentHoldingServerPacket {
public EntityEquipmentPacket {
equipments = Map.copyOf(equipments);
if (equipments.isEmpty())
@ -41,6 +47,23 @@ public record EntityEquipmentPacket(int entityId,
return ServerPacketIdentifier.ENTITY_EQUIPMENT;
}
@Override
public @NotNull Collection<Component> components() {
return this.equipments.values()
.stream()
.map(ItemStack::getDisplayName)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
final var map = new EnumMap<EquipmentSlot, ItemStack>(EquipmentSlot.class);
this.equipments.forEach((key, value) -> map.put(key, value.withDisplayName(operator)));
return new EntityEquipmentPacket(this.entityId, map);
}
private static Map<EquipmentSlot, ItemStack> readEquipments(BinaryReader reader) {
Map<EquipmentSlot, ItemStack> equipments = new EnumMap<>(EquipmentSlot.class);
byte slot;

View File

@ -1,17 +1,21 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.entity.Metadata;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.UnaryOperator;
public record EntityMetaDataPacket(int entityId,
@NotNull Map<Integer, Metadata.Entry<?>> entries) implements ServerPacket {
@NotNull Map<Integer, Metadata.Entry<?>> entries) implements ComponentHoldingServerPacket {
public EntityMetaDataPacket {
entries = Map.copyOf(entries);
}
@ -47,4 +51,27 @@ public record EntityMetaDataPacket(int entityId,
public int getId() {
return ServerPacketIdentifier.ENTITY_METADATA;
}
@Override
public @NotNull Collection<Component> components() {
return this.entries.values()
.stream()
.map(Metadata.Entry::value)
.filter(entry -> entry instanceof Component)
.map(entry -> (Component) entry)
.toList();
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
final var entries = new HashMap<Integer, Metadata.Entry<?>>();
this.entries.forEach((key, value) -> {
final var v = value.value();
entries.put(key, v instanceof Component c ? Metadata.OptChat(operator.apply(c)) : value);
});
return new EntityMetaDataPacket(this.entityId, entries);
}
}

View File

@ -1,14 +1,19 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator;
public record OpenWindowPacket(int windowId, int windowType,
@NotNull Component title) implements ServerPacket {
@NotNull Component title) implements ComponentHoldingServerPacket {
public OpenWindowPacket(BinaryReader reader) {
this(reader.readVarInt(), reader.readVarInt(), reader.readComponent());
}
@ -24,4 +29,14 @@ public record OpenWindowPacket(int windowId, int windowType,
public int getId() {
return ServerPacketIdentifier.OPEN_WINDOW;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.title);
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new OpenWindowPacket(this.windowId, this.windowType, operator.apply(this.title));
}
}

View File

@ -81,7 +81,7 @@ public record PlayerInfoPacket(@NotNull Action action,
}
return components;
default:
return Collections.emptyList();
return List.of();
}
}
@ -152,7 +152,7 @@ public record PlayerInfoPacket(@NotNull Action action,
@Override
public @NotNull Collection<Component> components() {
return displayName != null ? Collections.singleton(displayName) : Collections.emptyList();
return displayName != null ? List.of(displayName) : List.of();
}
@Override
@ -218,7 +218,7 @@ public record PlayerInfoPacket(@NotNull Action action,
@Override
public @NotNull Collection<Component> components() {
return displayName != null ? Collections.singleton(displayName) : Collections.emptyList();
return displayName != null ? List.of(displayName) : List.of();
}
@Override

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.resourcepack.ResourcePack;
@ -8,8 +9,12 @@ import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator;
public record ResourcePackSendPacket(String url, String hash, boolean forced,
Component prompt) implements ServerPacket {
Component prompt) implements ComponentHoldingServerPacket {
public ResourcePackSendPacket(BinaryReader reader) {
this(reader.readSizedString(), reader.readSizedString(), reader.readBoolean(),
reader.readBoolean() ? reader.readComponent() : null);
@ -37,4 +42,14 @@ public record ResourcePackSendPacket(String url, String hash, boolean forced,
public int getId() {
return ServerPacketIdentifier.RESOURCE_PACK_SEND;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.prompt);
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new ResourcePackSendPacket(this.url, this.hash, this.forced, operator.apply(this.prompt));
}
}

View File

@ -11,6 +11,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.UnaryOperator;
public record ScoreboardObjectivePacket(@NotNull String objectiveName, byte mode,
@ -55,8 +56,8 @@ public record ScoreboardObjectivePacket(@NotNull String objectiveName, byte mode
@Override
public @NotNull Collection<Component> components() {
return mode == 0 || mode == 2 ? Collections.singleton(objectiveValue) :
Collections.emptyList();
return mode == 0 || mode == 2 ? List.of(objectiveValue) :
List.of();
}
@Override

View File

@ -1,14 +1,22 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.UnaryOperator;
public record SetSlotPacket(byte windowId, int stateId, short slot,
@NotNull ItemStack itemStack) implements ServerPacket {
@NotNull ItemStack itemStack) implements ComponentHoldingServerPacket {
public SetSlotPacket(BinaryReader reader) {
this(reader.readByte(), reader.readVarInt(), reader.readShort(),
reader.readItemStack());
@ -27,6 +35,24 @@ public record SetSlotPacket(byte windowId, int stateId, short slot,
return ServerPacketIdentifier.SET_SLOT;
}
@Override
public @NotNull Collection<Component> components() {
final var components = new ArrayList<>(this.itemStack.getLore());
final var displayname = this.itemStack.getDisplayName();
if (displayname != null) components.add(displayname);
return List.copyOf(components);
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new SetSlotPacket(this.windowId, this.stateId, this.slot, this.itemStack.withDisplayName(operator).withLore(lines -> {
final var translatedComponents = new ArrayList<Component>();
lines.forEach(component -> translatedComponents.add(operator.apply(component)));
return translatedComponents;
}));
}
/**
* Returns a {@link SetSlotPacket} used to change a player cursor item.
*

View File

@ -1,13 +1,18 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
public record SetTitleSubTitlePacket(@NotNull Component subtitle) implements ServerPacket {
import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator;
public record SetTitleSubTitlePacket(@NotNull Component subtitle) implements ComponentHoldingServerPacket {
public SetTitleSubTitlePacket(BinaryReader reader) {
this(reader.readComponent());
}
@ -21,4 +26,14 @@ public record SetTitleSubTitlePacket(@NotNull Component subtitle) implements Ser
public int getId() {
return ServerPacketIdentifier.SET_TITLE_SUBTITLE;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.subtitle);
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new SetTitleSubTitlePacket(operator.apply(this.subtitle));
}
}

View File

@ -1,13 +1,18 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
public record SetTitleTextPacket(@NotNull Component title) implements ServerPacket {
import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator;
public record SetTitleTextPacket(@NotNull Component title) implements ComponentHoldingServerPacket {
public SetTitleTextPacket(BinaryReader reader) {
this(reader.readComponent());
}
@ -21,4 +26,14 @@ public record SetTitleTextPacket(@NotNull Component title) implements ServerPack
public int getId() {
return ServerPacketIdentifier.SET_TITLE_TEXT;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.title);
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new SetTitleTextPacket(operator.apply(this.title));
}
}

View File

@ -42,7 +42,7 @@ public record TabCompletePacket(int transactionId, int start, int length,
@Override
public @NotNull Collection<Component> components() {
if (matches.isEmpty()) return Collections.emptyList();
if (matches.isEmpty()) return List.of();
List<Component> components = new ArrayList<>(matches.size());
for (Match match : matches) {
if (match.tooltip != null) {
@ -75,7 +75,7 @@ public record TabCompletePacket(int transactionId, int start, int length,
@Override
public @NotNull Collection<Component> components() {
return tooltip != null ? Collections.singletonList(tooltip) : Collections.emptyList();
return tooltip != null ? Collections.singletonList(tooltip) : List.of();
}
@Override

View File

@ -3,6 +3,8 @@ package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.adventure.AdventurePacketConvertor;
import net.minestom.server.adventure.ComponentHolder;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
@ -13,11 +15,12 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator;
/**
* The packet creates or updates teams
*/
public record TeamsPacket(String teamName, Action action) implements ServerPacket {
public record TeamsPacket(String teamName, Action action) implements ComponentHoldingServerPacket {
public TeamsPacket(BinaryReader reader) {
this(reader.readSizedString(), switch (reader.readByte()) {
case 0 -> new CreateTeamAction(reader);
@ -36,6 +39,21 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke
writer.write(action);
}
@Override
public @NotNull Collection<Component> components() {
return this.action instanceof ComponentHolder<?> holder ? holder.components() : List.of();
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new TeamsPacket(
this.teamName,
this.action instanceof ComponentHolder<?> holder
? (Action) holder.copyWithOperator(operator)
: this.action
);
}
public sealed interface Action extends Writeable
permits CreateTeamAction, RemoveTeamAction, UpdateTeamAction, AddEntitiesToTeamAction, RemoveEntitiesToTeamAction {
int id();
@ -44,7 +62,7 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke
public record CreateTeamAction(Component displayName, byte friendlyFlags,
NameTagVisibility nameTagVisibility, CollisionRule collisionRule,
NamedTextColor teamColor, Component teamPrefix, Component teamSuffix,
Collection<String> entities) implements Action {
Collection<String> entities) implements Action, ComponentHolder<CreateTeamAction> {
public CreateTeamAction {
entities = List.copyOf(entities);
}
@ -72,6 +90,25 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke
public int id() {
return 0;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.displayName, this.teamPrefix, this.teamSuffix);
}
@Override
public @NotNull CreateTeamAction copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new CreateTeamAction(
operator.apply(this.displayName),
this.friendlyFlags,
this.nameTagVisibility,
this.collisionRule,
this.teamColor,
operator.apply(this.teamPrefix),
operator.apply(this.teamSuffix),
entities
);
}
}
public record RemoveTeamAction() implements Action {
@ -88,7 +125,7 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke
public record UpdateTeamAction(Component displayName, byte friendlyFlags,
NameTagVisibility nameTagVisibility, CollisionRule collisionRule,
NamedTextColor teamColor,
Component teamPrefix, Component teamSuffix) implements Action {
Component teamPrefix, Component teamSuffix) implements Action, ComponentHolder<UpdateTeamAction> {
public UpdateTeamAction(BinaryReader reader) {
this(reader.readComponent(), reader.readByte(),
@ -112,6 +149,24 @@ public record TeamsPacket(String teamName, Action action) implements ServerPacke
public int id() {
return 2;
}
@Override
public @NotNull Collection<Component> components() {
return List.of(this.displayName, this.teamPrefix, this.teamSuffix);
}
@Override
public @NotNull UpdateTeamAction copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new UpdateTeamAction(
operator.apply(this.displayName),
this.friendlyFlags,
this.nameTagVisibility,
this.collisionRule,
this.teamColor,
operator.apply(this.teamPrefix),
operator.apply(this.teamSuffix)
);
}
}
public record AddEntitiesToTeamAction(Collection<String> entities) implements Action {

View File

@ -1,16 +1,23 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
public record WindowItemsPacket(byte windowId, int stateId, @NotNull List<ItemStack> items,
@NotNull ItemStack carriedItem) implements ServerPacket {
@NotNull ItemStack carriedItem) implements ComponentHoldingServerPacket {
public WindowItemsPacket {
items = List.copyOf(items);
}
@ -32,4 +39,41 @@ public record WindowItemsPacket(byte windowId, int stateId, @NotNull List<ItemSt
public int getId() {
return ServerPacketIdentifier.WINDOW_ITEMS;
}
@Override
public @NotNull Collection<Component> components() {
final var list = new ArrayList<>(this.items);
list.add(this.carriedItem);
final var components = new ArrayList<Component>();
list.forEach(itemStack -> {
components.addAll(itemStack.getLore());
final var displayName = itemStack.getDisplayName();
if (displayName == null) return;
components.add(displayName);
});
return components;
}
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new WindowItemsPacket(
this.windowId,
this.stateId,
this.items.stream().map(stack -> stack.withDisplayName(operator).withLore(lines -> {
final var translatedComponents = new ArrayList<Component>();
lines.forEach(component -> translatedComponents.add(operator.apply(component)));
return translatedComponents;
})).toList(),
this.carriedItem.withDisplayName(operator).withLore(lines -> {
final var translatedComponents = new ArrayList<Component>();
lines.forEach(component -> translatedComponents.add(operator.apply(component)));
return translatedComponents;
})
);
}
}

View File

@ -8,15 +8,16 @@ import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.ForwardingAudience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslatableComponent;
import net.minestom.server.MinecraftServer;
import net.minestom.server.Viewable;
import net.minestom.server.adventure.ComponentHolder;
import net.minestom.server.adventure.MinestomAdventure;
import net.minestom.server.adventure.audience.PacketGroupingAudience;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.CachedPacket;
import net.minestom.server.network.packet.server.FramedPacket;
import net.minestom.server.network.packet.server.SendablePacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.*;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection;
import net.minestom.server.utils.binary.BinaryBuffer;
@ -101,12 +102,47 @@ public final class PacketUtils {
*/
public static void sendGroupedPacket(@NotNull Collection<Player> players, @NotNull ServerPacket packet,
@NotNull Predicate<Player> predicate) {
final SendablePacket sendablePacket = GROUPED_PACKET ? new CachedPacket(packet) : packet;
final var sendablePacket = shouldUseCachePacket(packet) ? new CachedPacket(packet) : packet;
players.forEach(player -> {
if (predicate.test(player)) player.sendPacket(sendablePacket);
});
}
/**
* Checks if the {@link ServerPacket} is suitable to be wrapped into a {@link CachedPacket}.
* Note: {@link ComponentHoldingServerPacket}s are not translated inside a {@link CachedPacket}.
*
* @see CachedPacket#body()
* @see PlayerSocketConnection#writePacketSync(SendablePacket, boolean)
*/
static boolean shouldUseCachePacket(final @NotNull ServerPacket packet) {
if (!MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION) return GROUPED_PACKET;
if (!(packet instanceof ComponentHoldingServerPacket holder)) return GROUPED_PACKET;
return !containsTranslatableComponents(holder);
}
private static boolean containsTranslatableComponents(final @NotNull ComponentHolder<?> holder) {
for (final Component component : holder.components()) {
if (isTranslatable(component)) return true;
}
return false;
}
private static boolean isTranslatable(final @NotNull Component component) {
if (component instanceof TranslatableComponent) return true;
final var children = component.children();
if (children.isEmpty()) return false;
for (final Component child : children) {
if (isTranslatable(child)) return true;
}
return false;
}
/**
* Same as {@link #sendGroupedPacket(Collection, ServerPacket, Predicate)}
* but with the player validator sets to null.

View File

@ -1,10 +1,13 @@
package net.minestom.server.api;
import net.kyori.adventure.translation.GlobalTranslator;
import net.minestom.server.ServerProcess;
import net.minestom.server.adventure.MinestomAdventure;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerLoginEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.SendablePacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.player.PlayerConnection;
@ -13,6 +16,7 @@ import org.jetbrains.annotations.NotNull;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
@ -54,12 +58,26 @@ final class TestConnectionImpl implements TestConnection {
final class PlayerConnectionImpl extends PlayerConnection {
@Override
public void sendPacket(@NotNull SendablePacket packet) {
final var serverPacket = this.extractPacket(packet);
for (var tracker : incomingTrackers) {
final var serverPacket = SendablePacket.extractServerPacket(packet);
if (tracker.type.isAssignableFrom(serverPacket.getClass())) tracker.packets.add(serverPacket);
}
}
private ServerPacket extractPacket(final SendablePacket packet) {
if (!(packet instanceof ServerPacket serverPacket)) return SendablePacket.extractServerPacket(packet);
final Player player = getPlayer();
if (player == null) return serverPacket;
if (MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION && serverPacket instanceof ComponentHoldingServerPacket) {
serverPacket = ((ComponentHoldingServerPacket) serverPacket).copyWithOperator(component ->
GlobalTranslator.render(component, Objects.requireNonNullElseGet(player.getLocale(), MinestomAdventure::getDefaultLocale)));
}
return serverPacket;
}
@Override
public @NotNull SocketAddress getRemoteAddress() {
return new InetSocketAddress("localhost", 25565);

View File

@ -0,0 +1,69 @@
package net.minestom.server.utils;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.translation.GlobalTranslator;
import net.kyori.adventure.translation.TranslationRegistry;
import net.minestom.server.adventure.MinestomAdventure;
import net.minestom.server.api.Env;
import net.minestom.server.api.EnvTest;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.message.ChatPosition;
import net.minestom.server.network.packet.server.play.ChatMessagePacket;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.text.MessageFormat;
import java.util.List;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
@EnvTest
public class TranslationIntegrationTest {
@BeforeAll
static void translator() {
final var translator = TranslationRegistry.create(Key.key("test.reg"));
translator.register("test.key", MinestomAdventure.getDefaultLocale(), new MessageFormat("This is a test message", MinestomAdventure.getDefaultLocale()));
GlobalTranslator.translator().addSource(translator);
}
@Test
public void testTranslationEnabled(final Env env) {
final var instance = env.createFlatInstance();
final var connection = env.createConnection();
final var player = connection.connect(instance, new Pos(0, 40, 0)).join();
final var collector = connection.trackIncoming(ChatMessagePacket.class);
MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION = true;
final var message = Component.translatable("test.key");
final var packet = new ChatMessagePacket(message, ChatPosition.CHAT, UUID.randomUUID());
PacketUtils.sendGroupedPacket(List.of(player), packet);
// the message should not be changed if translations are enabled.
// the translation of the message itself will be proceeded in PlayerConnectionImpl class
collector.assertSingle(received -> {
assertNotEquals(message, received.message());
});
}
@Test
public void testTranslationDisabled(final Env env) {
final var instance = env.createFlatInstance();
final var connection = env.createConnection();
final var player = connection.connect(instance, new Pos(0, 40, 0)).join();
final var collector = connection.trackIncoming(ChatMessagePacket.class);
MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION = false;
final var message = Component.translatable("test.key");
final var packet = new ChatMessagePacket(message, ChatPosition.CHAT, UUID.randomUUID());
PacketUtils.sendGroupedPacket(List.of(player), packet);
collector.assertSingle(received -> {
assertEquals(message, received.message());
});
}
}