diff --git a/src/main/java/me/libraryaddict/disguise/utilities/listeners/PlayerSkinHandler.java b/src/main/java/me/libraryaddict/disguise/utilities/listeners/PlayerSkinHandler.java new file mode 100644 index 00000000..f9b66a7d --- /dev/null +++ b/src/main/java/me/libraryaddict/disguise/utilities/listeners/PlayerSkinHandler.java @@ -0,0 +1,153 @@ +package me.libraryaddict.disguise.utilities.listeners; + +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.EnumWrappers; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalCause; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import me.libraryaddict.disguise.DisguiseConfig; +import me.libraryaddict.disguise.disguisetypes.PlayerDisguise; +import me.libraryaddict.disguise.events.UndisguiseEvent; +import me.libraryaddict.disguise.utilities.DisguiseUtilities; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Created by libraryaddict on 15/09/2020. + */ +public class PlayerSkinHandler implements Listener { + @RequiredArgsConstructor + private static class PlayerSkin { + private final long firstPacketSent = System.currentTimeMillis(); + @Getter + private final WeakReference disguise; + + public boolean canRemove() { + return firstPacketSent + (DisguiseConfig.getTablistRemoveDelay() * 50) < System.currentTimeMillis(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlayerSkin that = (PlayerSkin) o; + return getDisguise().get() == that.getDisguise().get(); + } + } + + @Getter + private final Cache> cache = + CacheBuilder.newBuilder().weakKeys().expireAfterWrite(1, TimeUnit.MINUTES).removalListener((event) -> { + if (event.getCause() != RemovalCause.EXPIRED) { + return; + } + + List skins = (List) event.getValue(); + + for (PlayerSkin skin : skins) { + PlayerDisguise disguise = skin.disguise.get(); + + if (disguise == null) { + return; + } + + doPacketRemoval((Player) event.getKey(), disguise); + } + + skins.clear(); + }).build(); + + public void addPlayerSkin(Player player, PlayerDisguise disguise) { + List skins = getCache().getIfPresent(player); + + if (skins == null) { + skins = new ArrayList<>(); + } + + skins.add(new PlayerSkin(new WeakReference<>(disguise))); + getCache().put(player, skins); + } + + @EventHandler(priority = EventPriority.MONITOR, + ignoreCancelled = true) + private void onUndisguise(UndisguiseEvent event) { + if (!event.getDisguise().isPlayerDisguise()) { + return; + } + + PlayerDisguise disguise = (PlayerDisguise) event.getDisguise(); + + for (Player player : DisguiseUtilities.getPerverts(disguise)) { + List skins = getCache().getIfPresent(player); + + if (skins == null) { + continue; + } + + PlayerSkin skin = skins.stream().filter(s -> s.getDisguise().get() == disguise).findAny().orElse(null); + + if (skin == null) { + continue; + } + + doPacketRemoval(player, disguise); + + if (skins.size() == 1) { + getCache().invalidate(player); + } else { + skins.remove(skin); + } + } + } + + private void doPacketRemoval(Player player, PlayerDisguise disguise) { + PacketContainer packetContainer = + DisguiseUtilities.getTabPacket(disguise, EnumWrappers.PlayerInfoAction.REMOVE_PLAYER); + + try { + ProtocolLibrary.getProtocolManager().sendServerPacket(player, packetContainer); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + + @EventHandler + public void onMove(PlayerMoveEvent event) { + List skins = getCache().getIfPresent(event.getPlayer()); + + if (skins == null) { + return; + } + + skins.removeIf(skin -> { + if (!skin.canRemove()) { + return false; + } + + doPacketRemoval(event.getPlayer(), skin.getDisguise().get()); + return true; + }); + + if (!skins.isEmpty()) { + return; + } + + getCache().invalidate(event.getPlayer()); + } +} diff --git a/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerSpawn.java b/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerSpawn.java index b63cba4f..6fd459e0 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerSpawn.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/packets/packethandlers/PacketHandlerSpawn.java @@ -8,6 +8,7 @@ import com.comphenix.protocol.wrappers.WrappedAttribute; import com.comphenix.protocol.wrappers.WrappedDataWatcher; import com.comphenix.protocol.wrappers.WrappedGameProfile; import com.mojang.datafixers.util.Pair; +import lombok.Getter; import me.libraryaddict.disguise.DisguiseConfig; import me.libraryaddict.disguise.LibsDisguises; import me.libraryaddict.disguise.disguisetypes.*; @@ -16,12 +17,14 @@ import me.libraryaddict.disguise.disguisetypes.watchers.LivingWatcher; import me.libraryaddict.disguise.utilities.DisguiseUtilities; import me.libraryaddict.disguise.utilities.DisguiseValues; import me.libraryaddict.disguise.utilities.LibsPremium; +import me.libraryaddict.disguise.utilities.listeners.PlayerSkinHandler; import me.libraryaddict.disguise.utilities.packets.IPacketHandler; import me.libraryaddict.disguise.utilities.packets.LibsPackets; import me.libraryaddict.disguise.utilities.packets.PacketsHandler; import me.libraryaddict.disguise.utilities.reflection.NmsVersion; import me.libraryaddict.disguise.utilities.reflection.ReflectionManager; import org.bukkit.Art; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.BlockData; @@ -31,7 +34,6 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; -import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.util.Vector; import java.util.ArrayList; @@ -44,9 +46,15 @@ import java.util.UUID; */ public class PacketHandlerSpawn implements IPacketHandler { private PacketsHandler packetsHandler; + @Getter + private PlayerSkinHandler skinHandler; public PacketHandlerSpawn(PacketsHandler packetsHandler) { this.packetsHandler = packetsHandler; + + skinHandler = new PlayerSkinHandler(); + + Bukkit.getPluginManager().registerEvents(skinHandler, LibsDisguises.getInstance()); } @Override @@ -193,22 +201,7 @@ public class PacketHandlerSpawn implements IPacketHandler { if (LibsPremium.getPaidInformation() == null || LibsPremium.getPaidInformation().getBuildNumber().matches("#[0-9]+")) { - if (!observer.hasMetadata("ld_loggedin")) { - ArrayList toSend; - - if (observer.hasMetadata("ld_tabsend") && !observer.getMetadata("ld_tabsend").isEmpty()) { - toSend = (ArrayList) observer.getMetadata("ld_tabsend").get(0).value(); - } else { - toSend = new ArrayList<>(); - - observer.setMetadata("ld_tabsend", - new FixedMetadataValue(LibsDisguises.getInstance(), toSend)); - } - - toSend.add(deleteTab); - } else { - packets.addDelayedPacket(deleteTab, DisguiseConfig.getTablistRemoveDelay()); - } + getSkinHandler().addPlayerSkin(observer, playerDisguise); } }