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..0c04ac44d --- /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 getLocale(); + + 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..854e6c7d8 --- /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 getLocale() { + 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