From 1b4c537c8148e9112f5a37067143e50143061082 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Sat, 25 Aug 2018 15:22:09 +0300 Subject: [PATCH 1/5] Add PlayerSettings API --- .../player/PlayerSettingsChangedEvent.java | 24 ++++++++ .../api/playersettings/PlayerSettings.java | 29 ++++++++++ .../api/playersettings/SkinParts.java | 39 +++++++++++++ .../com/velocitypowered/api/proxy/Player.java | 5 +- .../client/ClientPlaySessionHandler.java | 6 +- .../client/ClientSettingsWrapper.java | 56 +++++++++++++++++++ .../connection/client/ConnectedPlayer.java | 19 +++++-- .../proxy/protocol/packet/ClientSettings.java | 29 +++++++--- 8 files changed, 188 insertions(+), 19 deletions(-) create mode 100644 api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java create mode 100644 api/src/main/java/com/velocitypowered/api/playersettings/PlayerSettings.java create mode 100644 api/src/main/java/com/velocitypowered/api/playersettings/SkinParts.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java new file mode 100644 index 000000000..4bb433ec2 --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java @@ -0,0 +1,24 @@ +package com.velocitypowered.api.event.player; + +import com.google.common.base.Preconditions; +import com.velocitypowered.api.playersettings.PlayerSettings; +import com.velocitypowered.api.proxy.Player; + +public class PlayerSettingsChangedEvent { + private final Player player; + private final PlayerSettings playerSettings; + + public PlayerSettingsChangedEvent(Player player, PlayerSettings playerSettings) { + this.player = Preconditions.checkNotNull(player, "player"); + this.playerSettings = Preconditions.checkNotNull(playerSettings, "playerSettings"); + } + + public Player getPlayer() { + return player; + } + + //New settings + public PlayerSettings getPlayerSettings() { + return playerSettings; + } +} diff --git a/api/src/main/java/com/velocitypowered/api/playersettings/PlayerSettings.java b/api/src/main/java/com/velocitypowered/api/playersettings/PlayerSettings.java new file mode 100644 index 000000000..0bed204c3 --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/playersettings/PlayerSettings.java @@ -0,0 +1,29 @@ +package com.velocitypowered.api.playersettings; + +import java.util.Locale; + +public interface PlayerSettings { + + Locale getLocate(); + + byte getViewDistance(); + + ChatMode getChatMode(); + + boolean hasChatColors(); + + SkinParts getSkinParts(); + + MainHand getMainHand(); + + public enum ChatMode { + SHOWN, + COMMANDS_ONLY, + HIDDEN + } + + public enum MainHand { + LEFT, + RIGHT + } +} diff --git a/api/src/main/java/com/velocitypowered/api/playersettings/SkinParts.java b/api/src/main/java/com/velocitypowered/api/playersettings/SkinParts.java new file mode 100644 index 000000000..4ec3d305b --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/playersettings/SkinParts.java @@ -0,0 +1,39 @@ +package com.velocitypowered.api.playersettings; + +public class SkinParts { + + static final SkinParts SKIN_SHOW_ALL = new SkinParts((byte) 127); + private final byte bitmask; + + public SkinParts(byte skinBitmask) { + this.bitmask = skinBitmask; + } + + public boolean hasCape() { + return ((bitmask >> 0) & 1) == 1; + } + + public boolean hasJacket() { + return ((bitmask >> 1) & 1) == 1; + } + + public boolean hasLeftSleeve() { + return ((bitmask >> 2) & 1) == 1; + } + + public boolean hasRightSleeve() { + return ((bitmask >> 3) & 1) == 1; + } + + public boolean hasLeftPants() { + return ((bitmask >> 4) & 1) == 1; + } + + public boolean hasRightPants() { + return ((bitmask >> 5) & 1) == 1; + } + + public boolean hasHat() { + return ((bitmask >> 6) & 1) == 1; + } +} 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 dc56e527e..c6a1a8fa0 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/Player.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/Player.java @@ -1,6 +1,7 @@ package com.velocitypowered.api.proxy; import com.velocitypowered.api.command.CommandSource; +import com.velocitypowered.api.playersettings.PlayerSettings; import com.velocitypowered.api.proxy.messages.ChannelMessageSink; import com.velocitypowered.api.proxy.messages.ChannelMessageSource; import com.velocitypowered.api.proxy.server.ServerInfo; @@ -32,7 +33,9 @@ public interface Player extends CommandSource, InboundConnection, ChannelMessage * @return an {@link Optional} the server that the player is connected to, which may be empty */ Optional getCurrentServer(); - + + PlayerSettings getPlayerSettings(); + /** * Sends a chat message to the player's client. * @param component the chat message to send diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index d5f040d2c..f74ae2b5a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -12,16 +12,12 @@ import com.velocitypowered.proxy.protocol.remap.EntityIdRemapper; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import com.velocitypowered.proxy.util.ThrowableUtils; import io.netty.buffer.ByteBuf; -import io.netty.channel.EventLoop; import net.kyori.text.TextComponent; import net.kyori.text.format.TextColor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.*; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; /** * Handles communication with the connected Minecraft client. This is effectively the primary nerve center that @@ -65,7 +61,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } if (packet instanceof ClientSettings) { - player.setClientSettings((ClientSettings) packet); + player.setPlayerSettings((ClientSettings) packet); // forward it on } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java new file mode 100644 index 000000000..cd3d5e0ec --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java @@ -0,0 +1,56 @@ +package com.velocitypowered.proxy.connection.client; + +import com.velocitypowered.api.playersettings.PlayerSettings; +import com.velocitypowered.api.playersettings.SkinParts; +import com.velocitypowered.proxy.protocol.packet.ClientSettings; +import java.util.Locale; + +public class ClientSettingsWrapper implements PlayerSettings { + + public static PlayerSettings DEFAULT = new ClientSettingsWrapper(new ClientSettings("en_US", (byte) 10, 0, true, (short)127, 1)); + + private final ClientSettings settings; + private final SkinParts parts; + private Locale locale = null; + + public ClientSettingsWrapper(ClientSettings settings) { + this.settings = settings; + this.parts = new SkinParts((byte) settings.getSkinParts()); + } + + @Override + public Locale getLocate() { + return locale == null ? locale = Locale.forLanguageTag(settings.getLocale().replaceAll("_", "-")) : locale; //Will throw error if locale not found + } + + @Override + public byte getViewDistance() { + return settings.getViewDistance(); + } + + @Override + public ChatMode getChatMode() { + int chat = settings.getChatVisibility(); + if (chat < 0 || chat > 2) { + return ChatMode.SHOWN; + } + return ChatMode.values()[chat]; + } + + @Override + public boolean hasChatColors() { + return settings.isChatColors(); + } + + @Override + public SkinParts getSkinParts() { + return parts; + } + + @Override + public MainHand getMainHand() { + return settings.getMainHand() == 1 ? MainHand.RIGHT : MainHand.LEFT; + } + + +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 1660f68b4..9b39e30df 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -2,9 +2,11 @@ package com.velocitypowered.proxy.connection.client; import com.google.common.base.Preconditions; import com.google.gson.JsonObject; +import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent; import com.velocitypowered.api.event.player.ServerPreConnectEvent; import com.velocitypowered.api.permission.PermissionFunction; import com.velocitypowered.api.permission.PermissionProvider; +import com.velocitypowered.api.playersettings.PlayerSettings; import com.velocitypowered.api.proxy.ConnectionRequestBuilder; import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.messages.ChannelIdentifier; @@ -55,7 +57,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { private VelocityServerConnection connectedServer; private ClientSettings clientSettings; private VelocityServerConnection connectionInFlight; - + private PlayerSettings settings; + public ConnectedPlayer(GameProfile profile, MinecraftConnection connection, InetSocketAddress virtualHost) { this.profile = profile; this.connection = connection; @@ -85,6 +88,16 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { return connection; } + @Override + public PlayerSettings getPlayerSettings() { + return settings == null ? ClientSettingsWrapper.DEFAULT : this.settings; + } + + public void setPlayerSettings(ClientSettings settings) { + this.settings = new ClientSettingsWrapper(settings); + VelocityServer.getServer().getEventManager().fireAndForget(new PlayerSettingsChangedEvent(this, this.settings)); + } + @Override public InetSocketAddress getRemoteAddress() { return (InetSocketAddress) connection.getChannel().remoteAddress(); @@ -162,10 +175,6 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { return clientSettings; } - public void setClientSettings(ClientSettings clientSettings) { - this.clientSettings = clientSettings; - } - public void handleConnectionException(ServerInfo info, Throwable throwable) { String error = ThrowableUtils.briefDescription(throwable); String userMessage; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java index cd5a92bab..0637cf3fe 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java @@ -6,6 +6,7 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; public class ClientSettings implements MinecraftPacket { + private String locale; private byte viewDistance; private int chatVisibility; @@ -13,6 +14,18 @@ public class ClientSettings implements MinecraftPacket { private short skinParts; private int mainHand; + public ClientSettings() { + } + + public ClientSettings(String locale, byte viewDistance, int chatVisibility, boolean chatColors, short skinParts, int mainHand) { + this.locale = locale; + this.viewDistance = viewDistance; + this.chatVisibility = chatVisibility; + this.chatColors = chatColors; + this.skinParts = skinParts; + this.mainHand = mainHand; + } + public String getLocale() { return locale; } @@ -63,14 +76,14 @@ public class ClientSettings implements MinecraftPacket { @Override public String toString() { - return "ClientSettings{" + - "locale='" + locale + '\'' + - ", viewDistance=" + viewDistance + - ", chatVisibility=" + chatVisibility + - ", chatColors=" + chatColors + - ", skinParts=" + skinParts + - ", mainHand=" + mainHand + - '}'; + return "ClientSettings{" + + "locale='" + locale + '\'' + + ", viewDistance=" + viewDistance + + ", chatVisibility=" + chatVisibility + + ", chatColors=" + chatColors + + ", skinParts=" + skinParts + + ", mainHand=" + mainHand + + '}'; } @Override From c1b1e71075ead96f2297d982b386747d9b9855ec Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 25 Aug 2018 10:56:32 -0400 Subject: [PATCH 2/5] Fix a typo. --- .../com/velocitypowered/api/event/connection/package-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/package-info.java b/api/src/main/java/com/velocitypowered/api/event/connection/package-info.java index 44e41f8d5..8f02c2b15 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/package-info.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/package-info.java @@ -1,4 +1,4 @@ /** - * Provides events for handling incoming connections to the proxy and loigns. + * Provides events for handling incoming connections to the proxy and logins. */ package com.velocitypowered.api.event.connection; \ No newline at end of file From d0ecc2b62384abdb3520a1351f901ad466017a53 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 25 Aug 2018 10:59:42 -0400 Subject: [PATCH 3/5] Allow making the "players" response null. --- .../api/proxy/server/ServerPing.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java index f48fbc3a8..525cd2bc9 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java @@ -18,9 +18,9 @@ public class ServerPing { private final Component description; private final @Nullable Favicon favicon; - public ServerPing(@NonNull Version version, @NonNull Players players, @NonNull Component description, @Nullable Favicon favicon) { + public ServerPing(Version version, @Nullable Players players, Component description, @Nullable Favicon favicon) { this.version = Preconditions.checkNotNull(version, "version"); - this.players = Preconditions.checkNotNull(players, "players"); + this.players = players; this.description = Preconditions.checkNotNull(description, "description"); this.favicon = favicon; } @@ -29,8 +29,8 @@ public class ServerPing { return version; } - public Players getPlayers() { - return players; + public Optional getPlayers() { + return Optional.ofNullable(players); } public Component getDescription() { @@ -76,6 +76,7 @@ public class ServerPing { private final List samplePlayers = new ArrayList<>(); private Component description; private Favicon favicon; + private boolean nullOutPlayers; private Builder() { @@ -106,6 +107,11 @@ public class ServerPing { return this; } + public Builder nullPlayers() { + this.nullOutPlayers = true; + return this; + } + public Builder description(Component description) { this.description = Preconditions.checkNotNull(description, "description"); return this; @@ -117,7 +123,7 @@ public class ServerPing { } public ServerPing build() { - return new ServerPing(version, new Players(onlinePlayers, maximumPlayers, samplePlayers), description, favicon); + return new ServerPing(version, nullOutPlayers ? null : new Players(onlinePlayers, maximumPlayers, samplePlayers), description, favicon); } public Version getVersion() { From 09153ae620634dcdfdc95a27beae1e3ad512e941 Mon Sep 17 00:00:00 2001 From: Leymooo Date: Sat, 25 Aug 2018 18:02:19 +0300 Subject: [PATCH 4/5] oops --- .../com/velocitypowered/api/playersettings/PlayerSettings.java | 2 +- .../proxy/connection/client/ClientSettingsWrapper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/playersettings/PlayerSettings.java b/api/src/main/java/com/velocitypowered/api/playersettings/PlayerSettings.java index 0bed204c3..0c04ac44d 100644 --- a/api/src/main/java/com/velocitypowered/api/playersettings/PlayerSettings.java +++ b/api/src/main/java/com/velocitypowered/api/playersettings/PlayerSettings.java @@ -4,7 +4,7 @@ import java.util.Locale; public interface PlayerSettings { - Locale getLocate(); + Locale getLocale(); byte getViewDistance(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java index cd3d5e0ec..854e6c7d8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientSettingsWrapper.java @@ -19,7 +19,7 @@ public class ClientSettingsWrapper implements PlayerSettings { } @Override - public Locale getLocate() { + public Locale getLocale() { return locale == null ? locale = Locale.forLanguageTag(settings.getLocale().replaceAll("_", "-")) : locale; //Will throw error if locale not found } From 2b3503e2df3202595c403d93845cc0979ccf69b4 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 25 Aug 2018 11:02:20 -0400 Subject: [PATCH 5/5] Fix compile. --- .../proxy/protocol/packet/LegacyPingResponse.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingResponse.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingResponse.java index 2b733f5ef..36cbe7845 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingResponse.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingResponse.java @@ -1,9 +1,11 @@ package com.velocitypowered.proxy.protocol.packet; +import com.google.common.collect.ImmutableList; import com.velocitypowered.api.proxy.server.ServerPing; import net.kyori.text.serializer.ComponentSerializers; public class LegacyPingResponse { + private static final ServerPing.Players FAKE_PLAYERS = new ServerPing.Players(0, 0, ImmutableList.of()); private int protocolVersion; private String serverVersion; private String motd; @@ -76,7 +78,7 @@ public class LegacyPingResponse { return new LegacyPingResponse(ping.getVersion().getProtocol(), ping.getVersion().getName(), ComponentSerializers.LEGACY.serialize(ping.getDescription()), - ping.getPlayers().getOnline(), - ping.getPlayers().getMax()); + ping.getPlayers().orElse(FAKE_PLAYERS).getOnline(), + ping.getPlayers().orElse(FAKE_PLAYERS).getMax()); } }