Merge pull request #315 from Minestom/adventure-4.8.0

Adventure 4.8.0
This commit is contained in:
TheMode 2021-06-15 15:14:42 +02:00 committed by GitHub
commit a4e18b95dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 510 additions and 55 deletions

View File

@ -5,4 +5,4 @@ asmVersion=9.0
mixinVersion=0.8.1
hephaistosVersion=v1.1.8
kotlinVersion=1.5.0
adventureVersion=4.7.0
adventureVersion=4.8.1

View File

@ -3,6 +3,7 @@ package net.minestom.server.adventure;
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.sound.SoundStop;
import net.kyori.adventure.text.format.NamedTextColor;
@ -14,6 +15,7 @@ import net.minestom.server.network.packet.server.play.SoundEffectPacket;
import net.minestom.server.network.packet.server.play.StopSoundPacket;
import net.minestom.server.registry.Registries;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.utils.Position;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@ -44,6 +46,7 @@ public class AdventurePacketConvertor {
/**
* Gets the int value of a boss bar overlay.
*
* @param overlay the overlay
* @return the value
*/
@ -53,6 +56,7 @@ public class AdventurePacketConvertor {
/**
* Gets the byte value of a collection of boss bar flags.
*
* @param flags the flags
* @return the value
*/
@ -66,6 +70,7 @@ public class AdventurePacketConvertor {
/**
* Gets the int value of a boss bar color.
*
* @param color the color
* @return the value
*/
@ -75,6 +80,7 @@ public class AdventurePacketConvertor {
/**
* Gets the int value of a sound source.
*
* @param source the source
* @return the value
*/
@ -84,6 +90,7 @@ public class AdventurePacketConvertor {
/**
* Gets the int value from a named text color.
*
* @param color the color
* @return the int value
*/
@ -93,17 +100,18 @@ public class AdventurePacketConvertor {
/**
* Creates a sound packet from a sound and a location.
*
* @param sound the sound
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @return the sound packet
*/
public static ServerPacket createSoundPacket(@NotNull Sound sound, double x, double y, double z) {
SoundEvent minestomSound = Registries.getSoundEvent(sound.name());
public static @NotNull ServerPacket createSoundPacket(@NotNull Sound sound, double x, double y, double z) {
final SoundEvent minestomSound = Registries.getSoundEvent(sound.name());
if (minestomSound == null) {
NamedSoundEffectPacket packet = new NamedSoundEffectPacket();
final NamedSoundEffectPacket packet = new NamedSoundEffectPacket();
packet.soundName = sound.name().asString();
packet.soundSource = sound.source();
packet.x = (int) x;
@ -113,7 +121,7 @@ public class AdventurePacketConvertor {
packet.pitch = sound.pitch();
return packet;
} else {
SoundEffectPacket packet = new SoundEffectPacket();
final SoundEffectPacket packet = new SoundEffectPacket();
packet.soundId = minestomSound.getId();
packet.soundSource = sound.source();
packet.x = (int) x;
@ -126,29 +134,60 @@ public class AdventurePacketConvertor {
}
/**
* Creates an entity sound packet from an Adventure sound.
* Creates a sound effect packet from a sound and an emitter.
*
* @param sound the sound
* @param entity the entity the sound is coming from
* @return the packet
* @param emitter the emitter, must be an {@link Entity}
* @return the sound packet
*/
public static ServerPacket createEntitySoundPacket(@NotNull Sound sound, @NotNull Entity entity) {
SoundEvent soundEvent = Registries.getSoundEvent(sound.name());
public static @NotNull ServerPacket createSoundPacket(@NotNull Sound sound, Sound.@NotNull Emitter emitter) {
if (emitter == Sound.Emitter.self())
throw new IllegalArgumentException("you must replace instances of Emitter.self() before calling this method");
if (!(emitter instanceof Entity))
throw new IllegalArgumentException("you can only call this method with entities");
if (soundEvent == null) {
throw new IllegalArgumentException("Sound must be a valid sound event.");
} else {
EntitySoundEffectPacket packet = new EntitySoundEffectPacket();
packet.soundId = soundEvent.getId();
final Entity entity = (Entity) emitter;
final SoundEvent minestomSound = Registries.getSoundEvent(sound.name());
if (minestomSound != null) {
final EntitySoundEffectPacket packet = new EntitySoundEffectPacket();
packet.soundId = minestomSound.getId();
packet.soundSource = sound.source();
packet.entityId = entity.getEntityId();
packet.volume = sound.volume();
packet.pitch = sound.pitch();
return packet;
} else {
final Position pos = entity.getPosition();
final NamedSoundEffectPacket packet = new NamedSoundEffectPacket();
packet.soundName = sound.name().asString();
packet.soundSource = sound.source();
packet.x = (int) pos.getX();
packet.y = (int) pos.getY();
packet.z = (int) pos.getX();
packet.volume = sound.volume();
packet.pitch = sound.pitch();
return packet;
}
}
/**
* Creates an entity sound packet from an Adventure sound.
*
* @param sound the sound
* @param entity the entity the sound is coming from
* @return the packet
* @deprecated Use {@link #createSoundPacket(Sound, Sound.Emitter)}
*/
@Deprecated(forRemoval = true)
public static ServerPacket createEntitySoundPacket(@NotNull Sound sound, @NotNull Entity entity) {
return createSoundPacket(sound, entity);
}
/**
* Creates a sound stop packet from a sound stop.
*
* @param stop the sound stop
* @return the sound stop packet
*/
@ -156,14 +195,16 @@ public class AdventurePacketConvertor {
StopSoundPacket packet = new StopSoundPacket();
packet.flags = 0x0;
if (stop.source() != null) {
final Sound.Source source = stop.source();
if (source != null) {
packet.flags |= 0x1;
packet.source = AdventurePacketConvertor.getSoundSourceValue(stop.source());
packet.source = AdventurePacketConvertor.getSoundSourceValue(source);
}
if (stop.sound() != null) {
final Key sound = stop.sound();
if (sound != null) {
packet.flags |= 0x2;
packet.sound = stop.sound().asString();
packet.sound = sound.asString();
}
return packet;

View File

@ -6,6 +6,7 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.translation.GlobalTranslator;
import net.kyori.adventure.translation.TranslationRegistry;
import net.kyori.adventure.translation.Translator;
import net.minestom.server.utils.ComponentUtils;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@ -13,6 +14,8 @@ import java.util.Locale;
import java.util.Objects;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
/**
* Manager class for handling Adventure serialization. By default AdventureSerializer will simply
* serialize components to Strings using {@link GsonComponentSerializer}. However, AdventureSerializer
@ -25,17 +28,19 @@ import java.util.function.Function;
* of specific players, or other elements which implement {@link Localizable}. To add your
* own translations, use {@link GlobalTranslator#addSource(Translator)} with a
* {@link TranslationRegistry} or your own implementation of {@link Translator}.
*
* @deprecated Use {@link MinestomAdventure}
*/
@Deprecated(forRemoval = true)
public class AdventureSerializer {
/**
* If components should be automatically translated in outgoing packets.
* @deprecated Use {@link MinestomAdventure#AUTOMATIC_COMPONENT_TRANSLATION}
*/
public static final boolean AUTOMATIC_COMPONENT_TRANSLATION = false;
protected static final Localizable NULL_LOCALIZABLE = () -> null;
@Deprecated(forRemoval = true)
public static final boolean AUTOMATIC_COMPONENT_TRANSLATION = MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION;
private static Function<Component, String> serializer = component -> GsonComponentSerializer.gson().serialize(component);
private static Locale defaultLocale = Locale.US;
private AdventureSerializer() {}
@ -43,7 +48,9 @@ public class AdventureSerializer {
* Gets the root serializer that is used to convert components into strings.
*
* @return the serializer
* @deprecated The serializer is no longer in use, use the adventure-provided serializers
*/
@Deprecated(forRemoval = true)
public static @NotNull Function<Component, String> getSerializer() {
return AdventureSerializer.serializer;
}
@ -52,7 +59,9 @@ public class AdventureSerializer {
* Sets the root serializer that is used to convert components into strings.
*
* @param serializer the serializer
* @deprecated The serializer is no longer in use
*/
@Deprecated
public static void setSerializer(@NotNull Function<Component, String> serializer) {
AdventureSerializer.serializer = serializer;
}
@ -63,9 +72,11 @@ public class AdventureSerializer {
* does not have a locale.
*
* @return the default locale
* @deprecated Use {@link MinestomAdventure#getDefaultLocale()}
*/
@Deprecated(forRemoval = true)
public static @NotNull Locale getDefaultLocale() {
return defaultLocale;
return MinestomAdventure.getDefaultLocale();
}
/**
@ -73,10 +84,12 @@ public class AdventureSerializer {
* {@link #translate(Component, Localizable)} is called with a localizable that
* does not have a locale.
*
* @param defaultLocale the new default locale
* @param defaultLocale the new default locale, or {@code null} to return to the default
* @deprecated Use {@link MinestomAdventure#setDefaultLocale(Locale)}}
*/
public static void setDefaultLocale(@NotNull Locale defaultLocale) {
AdventureSerializer.defaultLocale = defaultLocale;
@Deprecated(forRemoval = true)
public static void setDefaultLocale(@Nullable Locale defaultLocale) {
MinestomAdventure.setDefaultLocale(defaultLocale);
}
/**
@ -84,7 +97,9 @@ public class AdventureSerializer {
* {@link GlobalTranslator#get()}.
*
* @return the global translator
* @deprecated Use {@link GlobalTranslator#get()}
*/
@Deprecated(forRemoval = true)
public static @NotNull GlobalTranslator getTranslator() {
return GlobalTranslator.get();
}
@ -97,7 +112,9 @@ public class AdventureSerializer {
* @param localizable the localizable
*
* @return the prepared component
* @deprecated Use {@link GlobalTranslator#translate(String, Locale)}
*/
@Deprecated(forRemoval = true)
public static @NotNull Component translate(@NotNull Component component, @NotNull Localizable localizable) {
return GlobalTranslator.renderer().render(component, Objects.requireNonNullElse(localizable.getLocale(), AdventureSerializer.getDefaultLocale()));
}
@ -110,7 +127,9 @@ public class AdventureSerializer {
* @param locale the locale
*
* @return the prepared component
* @deprecated Use {@link GlobalTranslator#translate(String, Locale)}
*/
@Deprecated(forRemoval = true)
public static @NotNull Component translate(@NotNull Component component, @NotNull Locale locale) {
return GlobalTranslator.renderer().render(component, locale);
}
@ -121,7 +140,9 @@ public class AdventureSerializer {
* @param component the component
*
* @return the serialized string
* @deprecated Use the Adventure serializers directly
*/
@Deprecated(forRemoval = true)
public static @NotNull String serialize(@NotNull Component component) {
return AdventureSerializer.serializer.apply(component);
}
@ -133,7 +154,9 @@ public class AdventureSerializer {
* @param localizable the localisable
*
* @return the string
* @deprecated Use {@link GlobalTranslator#translate(String, Locale)} and the Adventure serializers
*/
@Deprecated(forRemoval = true)
public static String translateAndSerialize(@NotNull Component component, @NotNull Localizable localizable) {
return AdventureSerializer.translateAndSerialize(component, Objects.requireNonNullElse(localizable.getLocale(), AdventureSerializer.getDefaultLocale()));
}
@ -145,7 +168,9 @@ public class AdventureSerializer {
* @param locale the locale
*
* @return the string
* @deprecated Use {@link GlobalTranslator#translate(String, Locale)} and the Adventure serializers
*/
@Deprecated(forRemoval = true)
public static String translateAndSerialize(@NotNull Component component, @NotNull Locale locale) {
return AdventureSerializer.serialize(AdventureSerializer.translate(component, locale));
}
@ -157,9 +182,11 @@ public class AdventureSerializer {
* @param component the component
* @return {@code true} if the component can be translated server-side,
* {@code false} otherwise
* @deprecated Use {@link ComponentUtils#isTranslatable(Component)}
*/
@Deprecated(forRemoval = true)
public static boolean isTranslatable(@NotNull Component component) {
return !component.equals(AdventureSerializer.translate(component, AdventureSerializer.getDefaultLocale()));
return ComponentUtils.isTranslatable(component);
}
/**
@ -167,14 +194,10 @@ public class AdventureSerializer {
* @param components the components
* @return {@code true} if any of the components can be translated server-side,
* {@code false} otherwise
* @deprecated Use {@link ComponentUtils#areAnyTranslatable(Collection)}
*/
@Deprecated(forRemoval = true)
public static boolean areAnyTranslatable(@NotNull Collection<Component> components) {
for (Component component : components) {
if (AdventureSerializer.isTranslatable(component)) {
return true;
}
}
return false;
return ComponentUtils.areAnyTranslatable(components);
}
}

View File

@ -16,7 +16,7 @@ public interface Localizable {
* @return the empty localizable
*/
static @NotNull Localizable empty() {
return AdventureSerializer.NULL_LOCALIZABLE;
return MinestomAdventure.NULL_LOCALIZABLE;
}
/**

View File

@ -0,0 +1,55 @@
package net.minestom.server.adventure;
import java.io.StringReader;
import net.kyori.adventure.util.Codec;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
import java.util.Objects;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.nbt.SNBTParser;
/**
* Adventure related constants, etc.
*/
public final class MinestomAdventure {
/**
* A codec to convert between strings and NBT.
*/
public static final Codec<NBT, String, NBTException, RuntimeException> NBT_CODEC
= Codec.of(encoded -> new SNBTParser(new StringReader(encoded)).parse(), NBT::toSNBT);
/**
* If components should be automatically translated in outgoing packets.
*/
public static final boolean AUTOMATIC_COMPONENT_TRANSLATION = false;
static final Localizable NULL_LOCALIZABLE = () -> null;
private static Locale defaultLocale = Locale.getDefault();
private MinestomAdventure() {
}
/**
* Gets the default locale used to translate components when no overriding locale has been provided.
*
* @return the default locale
*/
public static @NotNull Locale getDefaultLocale() {
return defaultLocale;
}
/**
* Sets the default locale used to translate components when no overriding locale has been provided.
*
* @param defaultLocale the new default, or {@code null} to return to {@link Locale#getDefault()}
*/
public static void setDefaultLocale(@Nullable Locale defaultLocale) {
MinestomAdventure.defaultLocale = Objects.requireNonNullElseGet(defaultLocale, Locale::getDefault);
}
}

View File

@ -90,11 +90,25 @@ public interface PacketGroupingAudience extends ForwardingAudience {
PacketUtils.sendGroupedPacket(this.getPlayers(), AdventurePacketConvertor.createSoundPacket(sound, x, y, z));
}
@Override
default void playSound(@NotNull Sound sound, Sound.@NotNull Emitter emitter) {
if (emitter != Sound.Emitter.self()) {
PacketUtils.sendGroupedPacket(this.getPlayers(), AdventurePacketConvertor.createSoundPacket(sound, emitter));
} else {
// if we're playing on self, we need to delegate to each audience member
for (Audience audience : this.audiences()) {
audience.playSound(sound, emitter);
}
}
}
@Override
default void stopSound(@NotNull SoundStop stop) {
PacketUtils.sendGroupedPacket(this.getPlayers(), AdventurePacketConvertor.createSoundStopPacket(stop));
}
@Override
default @NotNull Iterable<? extends Audience> audiences() {
return this.getPlayers();

View File

@ -0,0 +1,22 @@
package net.minestom.server.adventure.provider;
import net.kyori.adventure.text.TranslatableComponent;
import net.kyori.adventure.text.flattener.ComponentFlattener;
import net.kyori.adventure.translation.GlobalTranslator;
import net.minestom.server.adventure.MinestomAdventure;
final class MinestomFlattenerProvider {
static final ComponentFlattener INSTANCE;
static {
final ComponentFlattener.Builder builder = ComponentFlattener.basic().toBuilder();
// handle server-side translations if needed
builder.complexMapper(TranslatableComponent.class, ((component, consumer) -> {
if (MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION) {
consumer.accept(GlobalTranslator.render(component, MinestomAdventure.getDefaultLocale()));
}
}));
INSTANCE = builder.build();
}
}

View File

@ -0,0 +1,29 @@
package net.minestom.server.adventure.provider;
import java.util.function.Consumer;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import org.jetbrains.annotations.NotNull;
@SuppressWarnings("UnstableApiUsage") // we are permitted to provide this
public final class MinestomGsonComponentSerializerProvider implements GsonComponentSerializer.Provider {
@Override
public @NotNull GsonComponentSerializer gson() {
return GsonComponentSerializer.builder()
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.INSTANCE)
.build();
}
@Override
public @NotNull GsonComponentSerializer gsonLegacy() {
return GsonComponentSerializer.builder()
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.INSTANCE)
.downsampleColors()
.build();
}
@Override
public @NotNull Consumer<GsonComponentSerializer.Builder> builder() {
return builder -> {}; // we don't need to touch the builder here
}
}

View File

@ -0,0 +1,31 @@
package net.minestom.server.adventure.provider;
import java.util.function.Consumer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.jetbrains.annotations.NotNull;
@SuppressWarnings("UnstableApiUsage") // we are permitted to provide this
public final class MinestomLegacyComponentSerializerProvider implements LegacyComponentSerializer.Provider {
@Override
public @NotNull LegacyComponentSerializer legacyAmpersand() {
return LegacyComponentSerializer.builder()
.character(LegacyComponentSerializer.AMPERSAND_CHAR)
.flattener(MinestomFlattenerProvider.INSTANCE)
.build();
}
@Override
public @NotNull LegacyComponentSerializer legacySection() {
return LegacyComponentSerializer.builder()
.character(LegacyComponentSerializer.SECTION_CHAR)
.flattener(MinestomFlattenerProvider.INSTANCE)
.build();
}
@Override
public @NotNull Consumer<LegacyComponentSerializer.Builder> legacy() {
// we will provide our flattener to allow for custom translations/etc
return builder -> builder.flattener(MinestomFlattenerProvider.INSTANCE);
}
}

View File

@ -0,0 +1,22 @@
package net.minestom.server.adventure.provider;
import java.util.function.Consumer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.jetbrains.annotations.NotNull;
@SuppressWarnings("UnstableApiUsage") // we are permitted to provide this
public final class MinestomPlainTextComponentSerializerProvider implements PlainTextComponentSerializer.Provider {
@Override
public @NotNull PlainTextComponentSerializer plainTextSimple() {
return PlainTextComponentSerializer.builder()
.flattener(MinestomFlattenerProvider.INSTANCE)
.build();
}
@Override
public @NotNull Consumer<PlainTextComponentSerializer.Builder> plainText() {
// we will provide our flattener to allow for custom translations/etc
return builder -> builder.flattener(MinestomFlattenerProvider.INSTANCE);
}
}

View File

@ -0,0 +1,101 @@
package net.minestom.server.adventure.provider;
import java.util.UUID;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.serializer.gson.LegacyHoverEventSerializer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.kyori.adventure.util.Codec;
import net.minestom.server.adventure.MinestomAdventure;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import java.io.IOException;
import java.util.Objects;
final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer {
static final NBTLegacyHoverEventSerializer INSTANCE = new NBTLegacyHoverEventSerializer();
private static final String ITEM_TYPE = "id", ITEM_COUNT = "Count", ITEM_TAG = "tag";
private static final String ENTITY_TYPE = "type", ENTITY_NAME = "name", ENTITY_ID = "id";
private NBTLegacyHoverEventSerializer() {
}
@Override
public HoverEvent.@NotNull ShowItem deserializeShowItem(@NotNull Component input) throws IOException {
final String raw = PlainTextComponentSerializer.plainText().serialize(input);
try {
// attempt the parse
final NBT nbt = MinestomAdventure.NBT_CODEC.decode(raw);
if (!(nbt instanceof NBTCompound)) throw new IOException("contents were not a compound");
final NBTCompound contents = (NBTCompound) nbt, tag = contents.getCompound(ITEM_TAG);
// create the event
return HoverEvent.ShowItem.of(
Key.key(Objects.requireNonNullElse(contents.getString(ITEM_TYPE), "")),
Objects.requireNonNullElse(contents.getByte(ITEM_COUNT), (byte) 1),
tag == null ? null : BinaryTagHolder.encode(tag, MinestomAdventure.NBT_CODEC)
);
} catch (final NBTException e) {
throw new IOException(e);
}
}
@Override
public HoverEvent.@NotNull ShowEntity deserializeShowEntity(@NotNull Component input, Codec.Decoder<Component, String, ? extends RuntimeException> componentDecoder) throws IOException {
final String raw = PlainTextComponentSerializer.plainText().serialize(input);
try {
final NBT nbt = MinestomAdventure.NBT_CODEC.decode(raw);
if (!(nbt instanceof NBTCompound)) throw new IOException("contents were not a compound");
final NBTCompound contents = (NBTCompound) nbt;
return HoverEvent.ShowEntity.of(
Key.key(Objects.requireNonNullElse(contents.getString(ENTITY_TYPE), "")),
UUID.fromString(Objects.requireNonNullElse(contents.getString(ENTITY_ID), "")),
componentDecoder.decode(Objects.requireNonNullElse(contents.getString(ENTITY_NAME), ""))
);
} catch (NBTException e) {
throw new IOException(e);
}
}
@Override
public @NotNull Component serializeShowItem(HoverEvent.@NotNull ShowItem input) throws IOException {
final NBTCompound tag = new NBTCompound();
tag.setString(ITEM_TYPE, input.item().asString());
tag.setByte(ITEM_COUNT, (byte) input.count());
final BinaryTagHolder nbt = input.nbt();
if (nbt != null) {
try {
tag.set(ITEM_TAG, nbt.get(MinestomAdventure.NBT_CODEC));
} catch (NBTException e) {
throw new IOException(e);
}
}
return Component.text(MinestomAdventure.NBT_CODEC.encode(tag));
}
@Override
public @NotNull Component serializeShowEntity(HoverEvent.@NotNull ShowEntity input, Codec.Encoder<Component, String, ? extends RuntimeException> componentEncoder) throws IOException {
final NBTCompound tag = new NBTCompound();
tag.setString(ENTITY_ID, input.id().toString());
tag.setString(ENTITY_TYPE, input.type().asString());
final Component name = input.name();
if (name != null) {
tag.setString(ENTITY_NAME, componentEncoder.encode(name));
}
return Component.text(MinestomAdventure.NBT_CODEC.encode(tag));
}
}

View File

@ -2,6 +2,7 @@ package net.minestom.server.entity;
import com.google.common.annotations.Beta;
import com.google.common.collect.Queues;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.event.HoverEvent.ShowEntity;
@ -64,7 +65,7 @@ import java.util.function.UnaryOperator;
* <p>
* To create your own entity you probably want to extends {@link LivingEntity} or {@link EntityCreature} instead.
*/
public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, DataContainer, PermissionHandler, HoverEventSource<ShowEntity> {
public class Entity implements Viewable, Tickable, EventHandler<EntityEvent>, DataContainer, PermissionHandler, HoverEventSource<ShowEntity>, Sound.Emitter {
private static final Map<Integer, Entity> ENTITY_BY_ID = new ConcurrentHashMap<>();
private static final Map<UUID, Entity> ENTITY_BY_UUID = new ConcurrentHashMap<>();

View File

@ -1,6 +1,7 @@
package net.minestom.server.entity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.chat.JsonMessage;

View File

@ -6,6 +6,7 @@ import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.identity.Identified;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.inventory.Book;
import net.kyori.adventure.pointer.Pointers;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.sound.SoundStop;
import net.kyori.adventure.text.Component;
@ -182,6 +183,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
// Adventure
private Identity identity;
private final Pointers pointers;
public Player(@NotNull UUID uuid, @NotNull String username, @NotNull PlayerConnection playerConnection) {
super(EntityType.PLAYER, uuid);
@ -210,6 +212,11 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
playerConnectionInit();
this.identity = Identity.identity(uuid);
this.pointers = Pointers.builder()
.withDynamic(Identity.UUID, this::getUuid)
.withDynamic(Identity.NAME, this::getUsername)
.withDynamic(Identity.DISPLAY_NAME, this::getDisplayName)
.build();
}
/**
@ -834,7 +841,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
@Override
public void playSound(@NotNull Sound sound) {
playerConnection.sendPacket(AdventurePacketConvertor.createEntitySoundPacket(sound, this));
this.playSound(sound, this.position.getX(), this.position.getY(), this.position.getZ());
}
@Override
@ -842,6 +849,19 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
playerConnection.sendPacket(AdventurePacketConvertor.createSoundPacket(sound, x, y, z));
}
@Override
public void playSound(@NotNull Sound sound, Sound.@NotNull Emitter emitter) {
final ServerPacket packet;
if (emitter == Sound.Emitter.self()) {
packet = AdventurePacketConvertor.createSoundPacket(sound, this);
} else {
packet = AdventurePacketConvertor.createSoundPacket(sound, emitter);
}
playerConnection.sendPacket(packet);
}
@Override
public void stopSound(@NotNull SoundStop stop) {
playerConnection.sendPacket(AdventurePacketConvertor.createSoundStopPacket(stop));
@ -2533,6 +2553,11 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
return this.identity;
}
@Override
public @NotNull Pointers pointers() {
return this.pointers;
}
@Override
public void setUuid(@NotNull UUID uuid) {
super.setUuid(uuid);

View File

@ -1,6 +1,8 @@
package net.minestom.server.instance;
import com.google.common.collect.Queues;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.pointer.Pointers;
import net.minestom.server.MinecraftServer;
import net.minestom.server.Tickable;
import net.minestom.server.UpdateManager;
@ -107,6 +109,9 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler<
// Pathfinder
private final PFInstanceSpace instanceSpace = new PFInstanceSpace(this);
// Adventure
private final Pointers pointers;
/**
* Creates a new instance.
*
@ -122,6 +127,10 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler<
this.worldBorder = new WorldBorder(this);
this.eventNode = EventNode.value("instance-" + uniqueId, EventFilter.INSTANCE, this::equals);
this.pointers = Pointers.builder()
.withDynamic(Identity.UUID, this::getUniqueId)
.build();
}
/**
@ -1114,4 +1123,9 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler<
public PFInstanceSpace getInstanceSpace() {
return instanceSpace;
}
@Override
public @NotNull Pointers pointers() {
return this.pointers;
}
}

View File

@ -68,7 +68,7 @@ public abstract class ItemMetaBuilder implements TagWritable {
this.displayName = displayName;
handleCompound("display", nbtCompound -> {
if (displayName != null) {
final String name = AdventureSerializer.serialize(displayName);
final String name = GsonComponentSerializer.gson().serialize(displayName);
nbtCompound.setString("Name", name);
} else {
nbtCompound.removeTag("Name");

View File

@ -71,7 +71,7 @@ public class WritableBookMeta extends ItemMeta implements ItemMetaBuilder.Provid
handleCollection(pages, "pages", nbt, () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
for (Component page : pages) {
list.add(new NBTString(AdventureSerializer.serialize(page)));
list.add(new NBTString(GsonComponentSerializer.gson().serialize(page)));
}
return list;
});

View File

@ -117,7 +117,7 @@ public class WrittenBookMeta extends ItemMeta implements ItemMetaBuilder.Provide
handleCollection(pages, "pages", nbt, () -> {
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
for (Component page : pages) {
list.add(new NBTString(AdventureSerializer.serialize(page)));
list.add(new NBTString(GsonComponentSerializer.gson().serialize(page)));
}
return list;
});

View File

@ -4,8 +4,13 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.socket.SocketChannel;
import java.util.Objects;
import net.kyori.adventure.translation.GlobalTranslator;
import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.AdventureSerializer;
import net.minestom.server.adventure.MinestomAdventure;
import net.minestom.server.entity.PlayerSkin;
import net.minestom.server.extras.mojangAuth.Decrypter;
import net.minestom.server.extras.mojangAuth.Encrypter;
@ -149,8 +154,9 @@ public class NettyPlayerConnection extends PlayerConnection {
} else if (message instanceof ServerPacket) {
ServerPacket serverPacket = (ServerPacket) message;
if ((AdventureSerializer.AUTOMATIC_COMPONENT_TRANSLATION && !skipTranslating) && getPlayer() != null && serverPacket instanceof ComponentHoldingServerPacket) {
serverPacket = ((ComponentHoldingServerPacket) serverPacket).copyWithOperator(component -> AdventureSerializer.translate(component, getPlayer()));
if ((MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION && !skipTranslating) && getPlayer() != null && serverPacket instanceof ComponentHoldingServerPacket) {
serverPacket = ((ComponentHoldingServerPacket) serverPacket).copyWithOperator(component ->
GlobalTranslator.render(component, Objects.requireNonNullElseGet(getPlayer().getLocale(), MinestomAdventure::getDefaultLocale)));
}
synchronized (tickBufferLock) {

View File

@ -1,6 +1,8 @@
package net.minestom.server.scoreboard;
import com.google.common.collect.MapMaker;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.pointer.Pointers;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
@ -73,6 +75,9 @@ public class Team implements PacketGroupingAudience {
private final Set<Player> playerMembers = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
private boolean isPlayerMembersUpToDate;
// Adventure
private final Pointers pointers;
/**
* Default constructor to creates a team.
*
@ -91,6 +96,11 @@ public class Team implements PacketGroupingAudience {
this.suffix = Component.empty();
this.members = new CopyOnWriteArraySet<>();
this.pointers = Pointers.builder()
.withDynamic(Identity.NAME, this::getTeamName)
.withDynamic(Identity.DISPLAY_NAME, this::getTeamDisplayName)
.build();
}
/**
@ -587,4 +597,9 @@ public class Team implements PacketGroupingAudience {
return this.playerMembers;
}
@Override
public @NotNull Pointers pointers() {
return this.pointers;
}
}

View File

@ -1,14 +1,13 @@
package net.minestom.server.sound;
import net.kyori.adventure.sound.Sound;
import org.jetbrains.annotations.NotNull;
import static net.kyori.adventure.sound.Sound.*;
/**
* @deprecated Use {@link Source}
* @deprecated Use {@link Sound.Source}
*/
@Deprecated
public enum SoundCategory {
public enum SoundCategory implements Sound.Source.Provider {
MASTER,
MUSIC,
RECORDS,
@ -24,8 +23,15 @@ public enum SoundCategory {
* Gets the Adventure source representing this sound category.
*
* @return the source
* @deprecated Use {@link #soundSource()}
*/
public @NotNull Source asSource() {
return Source.values()[this.ordinal()];
@Deprecated
public @NotNull Sound.Source asSource() {
return this.soundSource();
}
@Override
public @NotNull Sound.Source soundSource() {
return Sound.Source.values()[this.ordinal()];
}
}

View File

@ -0,0 +1,41 @@
package net.minestom.server.utils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.translation.GlobalTranslator;
import net.minestom.server.adventure.MinestomAdventure;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* {@link Component} utilities.
*/
public final class ComponentUtils {
/**
* Checks if a component can be translated server-side. This is done by running the
* component through the translator and seeing if the translated component is equal
* to the non translated component.
*
* @param component the component
* @return {@code true} if the component can be translated server-side, {@code false} otherwise
*/
public static boolean isTranslatable(@NotNull Component component) {
return !component.equals(GlobalTranslator.render(component, MinestomAdventure.getDefaultLocale()));
}
/**
* Checks if any of a series of components are translatable server-side.
*
* @param components the components
* @return {@code true} if any of the components can be translated server-side, {@code false} otherwise
*/
public static boolean areAnyTranslatable(@NotNull Collection<Component> components) {
for (Component component : components) {
if (isTranslatable(component)) {
return true;
}
}
return false;
}
}

View File

@ -5,6 +5,7 @@ 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.MinestomAdventure;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.attribute.AttributeOperation;
import net.minestom.server.instance.block.Block;
@ -34,9 +35,11 @@ public final class NBTUtils {
/**
* An Adventure codec to convert between NBT and SNBT.
*
* @deprecated Use {@link MinestomAdventure#NBT_CODEC}
*/
public static final Codec<NBT, String, NBTException, RuntimeException> SNBT_CODEC
= Codec.of(encoded -> new SNBTParser(new StringReader(encoded)).parse(), NBT::toSNBT);
@Deprecated(forRemoval = true)
public static final Codec<NBT, String, NBTException, RuntimeException> SNBT_CODEC = MinestomAdventure.NBT_CODEC;
private NBTUtils() {
@ -54,7 +57,7 @@ public final class NBTUtils {
return null;
}
return BinaryTagHolder.encode(tag, SNBT_CODEC);
return BinaryTagHolder.encode(tag, MinestomAdventure.NBT_CODEC);
}
/**

View File

@ -7,6 +7,7 @@ import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.ForwardingAudience;
import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.AdventureSerializer;
import net.minestom.server.adventure.MinestomAdventure;
import net.minestom.server.adventure.audience.PacketGroupingAudience;
import net.minestom.server.entity.Player;
import net.minestom.server.listener.manager.PacketListenerManager;
@ -84,8 +85,8 @@ public final class PacketUtils {
// work out if the packet needs to be sent individually due to server-side translating
boolean needsTranslating = false;
if (AdventureSerializer.AUTOMATIC_COMPONENT_TRANSLATION && packet instanceof ComponentHoldingServerPacket) {
needsTranslating = AdventureSerializer.areAnyTranslatable(((ComponentHoldingServerPacket) packet).components());
if (MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION && packet instanceof ComponentHoldingServerPacket) {
needsTranslating = ComponentUtils.areAnyTranslatable(((ComponentHoldingServerPacket) packet).components());
}
if (MinecraftServer.hasGroupedPacket() && !needsTranslating) {

View File

@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.AdventureSerializer;
import net.minestom.server.chat.JsonMessage;
@ -71,7 +72,7 @@ public class BinaryWriter extends OutputStream {
* @param component the component
*/
public void writeComponent(@NotNull Component component) {
this.writeSizedString(AdventureSerializer.serialize(component));
this.writeSizedString(GsonComponentSerializer.gson().serialize(component));
}
/**

View File

@ -0,0 +1 @@
net.minestom.server.adventure.provider.MinestomGsonComponentSerializerProvider

View File

@ -0,0 +1 @@
net.minestom.server.adventure.provider.MinestomLegacyComponentSerializerProvider

View File

@ -0,0 +1 @@
net.minestom.server.adventure.provider.MinestomPlainTextComponentSerializerProvider