From 359484b3bec2770961719cbd8cf26a879f284d86 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 31 Aug 2022 10:32:20 -0700 Subject: [PATCH] SkinApplier now only applies a skin if a player doesn't already have one (#330) * SkinApplier now only applies a skin if a player doesn't already have one * add `hasSkin` method to SkinApplier and check for exising skins before overwriting * remove the use of Streams and Optionals * correct delay in SpigotSkinApplier to use ticks instead of milliseconds * Minor changes Co-authored-by: Tim203 --- .../floodgate/listener/BungeeListener.java | 2 +- .../pluginmessage/BungeeSkinApplier.java | 44 ++++++++++++++++--- .../pluginmessage/channel/SkinChannel.java | 2 +- .../geysermc/floodgate/skin/SkinApplier.java | 15 +++++++ .../floodgate/skin/SkinUploadSocket.java | 2 +- .../pluginmessage/SpigotSkinApplier.java | 27 +++++++++++- .../floodgate/util/VelocitySkinApplier.java | 18 ++++++++ 7 files changed, 100 insertions(+), 10 deletions(-) diff --git a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java index e62a1776..5aa717f8 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java +++ b/bungee/src/main/java/org/geysermc/floodgate/listener/BungeeListener.java @@ -130,7 +130,7 @@ public final class BungeeListener implements Listener { // To fix the February 2 2022 Mojang authentication changes if (!config.isSendFloodgateData()) { FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId()); - if (player != null && !player.isLinked()) { + if (player != null && !player.isLinked() && !skinApplier.hasSkin(player)) { skinApplier.applySkin(player, new SkinData("", "")); } } diff --git a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java index 5c0dce97..3e360615 100644 --- a/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java +++ b/bungee/src/main/java/org/geysermc/floodgate/pluginmessage/BungeeSkinApplier.java @@ -39,6 +39,7 @@ import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.connection.LoginResult; +import net.md_5.bungee.protocol.Property; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.skin.SkinApplier; @@ -85,11 +86,8 @@ public final class BungeeSkinApplier implements SkinApplier { return; } - InitialHandler handler; - try { - handler = (InitialHandler) player.getPendingConnection(); - } catch (Exception exception) { - logger.error("Incompatible Bungeecord fork detected", exception); + InitialHandler handler = getHandler(player); + if (handler == null) { return; } @@ -114,4 +112,40 @@ public final class BungeeSkinApplier implements SkinApplier { ReflectionUtils.invoke(loginResult, SET_PROPERTIES_METHOD, propertyArray); } + + @Override + public boolean hasSkin(FloodgatePlayer fPlayer) { + ProxiedPlayer player = ProxyServer.getInstance().getPlayer(fPlayer.getCorrectUniqueId()); + if (player == null) { + return false; + } + + InitialHandler handler = getHandler(player); + if (handler == null) { + return false; + } + + LoginResult loginResult = handler.getLoginProfile(); + if (loginResult == null) { + return false; + } + + for (Property property : loginResult.getProperties()) { + if (property.getName().equals("textures")) { + if (!property.getValue().isEmpty()) { + return true; + } + } + } + return false; + } + + private InitialHandler getHandler(ProxiedPlayer player) { + try { + return (InitialHandler) player.getPendingConnection(); + } catch (Exception exception) { + logger.error("Incompatible Bungeecord fork detected", exception); + return null; + } + } } diff --git a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java index 8b5b0a2d..02f0161b 100644 --- a/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java +++ b/core/src/main/java/org/geysermc/floodgate/pluginmessage/channel/SkinChannel.java @@ -89,7 +89,7 @@ public class SkinChannel implements PluginMessageChannel { return Result.kick("Got invalid skin data"); } - if (floodgatePlayer.isLinked()) { + if (floodgatePlayer.isLinked() || skinApplier.hasSkin(floodgatePlayer)) { return Result.handled(); } diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java index 0386b723..93dc3cb4 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinApplier.java @@ -28,5 +28,20 @@ package org.geysermc.floodgate.skin; import org.geysermc.floodgate.api.player.FloodgatePlayer; public interface SkinApplier { + /** + * Apply a skin to a {@link FloodgatePlayer player} + * + * @param floodgatePlayer player to apply skin to + * @param skinData data for skin to apply to player + */ void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData); + + /** + * Check if a {@link FloodgatePlayer player} currently + * has a skin applied. + * + * @param floodgatePlayer player to check skin of + * @return if player has a skin + */ + boolean hasSkin(FloodgatePlayer floodgatePlayer); } diff --git a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java index 87c04459..c933d7f0 100644 --- a/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java +++ b/core/src/main/java/org/geysermc/floodgate/skin/SkinUploadSocket.java @@ -114,7 +114,7 @@ final class SkinUploadSocket extends WebSocketClient { player.getCorrectUsername()); return; } - if (!player.isLinked()) { + if (!player.isLinked() && !applier.hasSkin(player)) { SkinData skinData = SkinData.from(message.getAsJsonObject("data")); player.addProperty(PropertyKey.SKIN_UPLOADED, skinData); applier.applySkin(player, skinData); diff --git a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java index 86f64c96..7ac668fe 100644 --- a/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java +++ b/spigot/src/main/java/org/geysermc/floodgate/pluginmessage/SpigotSkinApplier.java @@ -25,6 +25,7 @@ package org.geysermc.floodgate.pluginmessage; +import com.destroystokyo.paper.profile.ProfileProperty; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; @@ -54,6 +55,24 @@ public final class SpigotSkinApplier implements SkinApplier { applySkin0(floodgatePlayer, skinData, true); } + @Override + public boolean hasSkin(FloodgatePlayer floodgatePlayer) { + Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId()); + + if (player == null) { + return false; + } + + for (ProfileProperty property : player.getPlayerProfile().getProperties()) { + if (property.getName().equals("textures")) { + if (!property.getValue().isEmpty()) { + return true; + } + } + } + return false; + } + private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, boolean firstTry) { Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId()); @@ -61,8 +80,12 @@ public final class SpigotSkinApplier implements SkinApplier { if (player == null) { if (firstTry) { Bukkit.getScheduler().runTaskLater(plugin, - () -> applySkin0(floodgatePlayer, skinData, false), - 10 * 1000); + () -> { + if (hasSkin(floodgatePlayer)) { + applySkin0(floodgatePlayer, skinData, false); + } + }, + 10 * 20); } return; } diff --git a/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java b/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java index 2d925725..c2c66d2f 100644 --- a/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java +++ b/velocity/src/main/java/org/geysermc/floodgate/util/VelocitySkinApplier.java @@ -25,10 +25,12 @@ package org.geysermc.floodgate.util; +import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.util.GameProfile.Property; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.skin.SkinApplier; @@ -46,4 +48,20 @@ public class VelocitySkinApplier implements SkinApplier { player.setGameProfileProperties(properties); }); } + + @Override + public boolean hasSkin(FloodgatePlayer floodgatePlayer) { + Optional player = server.getPlayer(floodgatePlayer.getCorrectUniqueId()); + + if (player.isPresent()) { + for (Property property : player.get().getGameProfileProperties()) { + if (property.getName().equals("textures")) { + if (!property.getValue().isEmpty()) { + return true; + } + } + } + } + return false; + } }