diff --git a/api/src/main/java/com/velocitypowered/api/proxy/Player.java b/api/src/main/java/com/velocitypowered/api/proxy/Player.java index 456f65417..0fd295acd 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/Player.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/Player.java @@ -39,6 +39,7 @@ import net.kyori.adventure.sound.SoundStop; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEventSource; +import net.kyori.adventure.text.object.PlayerHeadObjectContents; import org.checkerframework.checker.nullness.qual.Nullable; import org.jetbrains.annotations.NotNull; @@ -49,7 +50,8 @@ public interface Player extends /* Fundamental Velocity interfaces */ CommandSource, InboundConnection, ChannelMessageSource, ChannelMessageSink, /* Adventure-specific interfaces */ - Identified, HoverEventSource, Keyed, KeyIdentifiable, Sound.Emitter { + Identified, HoverEventSource, Keyed, KeyIdentifiable, Sound.Emitter, + PlayerHeadObjectContents.SkinSource { /** * Returns the player's current username. @@ -339,6 +341,16 @@ public interface Player extends Component.text(getUsername())))); } + @SuppressWarnings("UnstableApiUsage") // permitted implementation + @Override + default void applySkinToPlayerHeadContents( + final PlayerHeadObjectContents.@NotNull Builder builder) { + builder.skin(this.getGameProfile()); + if (this.hasSentPlayerSettings()) { + builder.hat(this.getPlayerSettings().getSkinParts().hasHat()); + } + } + /** * Gets the player's client brand. * diff --git a/api/src/main/java/com/velocitypowered/api/util/GameProfile.java b/api/src/main/java/com/velocitypowered/api/util/GameProfile.java index e918c8e9e..c99ffe7dd 100644 --- a/api/src/main/java/com/velocitypowered/api/util/GameProfile.java +++ b/api/src/main/java/com/velocitypowered/api/util/GameProfile.java @@ -11,11 +11,14 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; +import net.kyori.adventure.text.object.PlayerHeadObjectContents; +import org.jetbrains.annotations.NotNull; /** * Represents a Mojang game profile. This class is immutable. */ -public final class GameProfile { +public final class GameProfile implements PlayerHeadObjectContents.SkinSource { private final UUID id; private final String undashedId; @@ -169,6 +172,23 @@ public final class GameProfile { ImmutableList.of()); } + @SuppressWarnings("UnstableApiUsage") // permitted implementation + @Override + public void applySkinToPlayerHeadContents( + final PlayerHeadObjectContents.@NotNull Builder builder) { + if (this.properties.isEmpty()) { + builder.id(this.id); + return; + } + + builder.id(this.id) + .name(this.name) + .profileProperties(this.properties.stream() + .map(property -> PlayerHeadObjectContents.property(property.getName(), + property.getValue(), property.getSignature())) + .collect(Collectors.toList())); + } + @Override public String toString() { return "GameProfile{"