diff --git a/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java b/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java index 690dde34..0ac351f0 100644 --- a/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java +++ b/src/main/java/me/libraryaddict/disguise/DisguiseConfig.java @@ -93,6 +93,15 @@ public class DisguiseConfig { private static int playerDisguisesTablistExpires; private static boolean dynamicExpiry; private static boolean playerHideArmor; + private static boolean extendedDisguisesNames; + + public static boolean isExtendedDisguiseNames() { + return extendedDisguisesNames; + } + + public static void setExtendedDisguiseNames(boolean extendedDisguiseNames) { + extendedDisguisesNames = extendedDisguiseNames; + } public static boolean isPlayerHideArmor() { return playerHideArmor; @@ -388,6 +397,7 @@ public class DisguiseConfig { setPlayerDisguisesTablistExpires(config.getInt("PlayerDisguisesTablistExpires")); setDynamicExpiry(config.getBoolean("DynamicExpiry")); setPlayerHideArmor(config.getBoolean("PlayerHideArmor")); + setExtendedDisguiseNames(config.getBoolean("ExtendedNames")); if (!LibsPremium.isPremium() && (isSavePlayerDisguises() || isSaveEntityDisguises())) { DisguiseUtilities.getLogger().warning("You must purchase the plugin to use saved disguises!"); diff --git a/src/main/java/me/libraryaddict/disguise/DisguiseListener.java b/src/main/java/me/libraryaddict/disguise/DisguiseListener.java index df6b025d..3caf8732 100644 --- a/src/main/java/me/libraryaddict/disguise/DisguiseListener.java +++ b/src/main/java/me/libraryaddict/disguise/DisguiseListener.java @@ -343,6 +343,10 @@ public class DisguiseListener implements Listener { } DisguiseUtilities.registerNoName(event.getPlayer().getScoreboard()); + + if (event.getPlayer().getScoreboard() != Bukkit.getScoreboardManager().getMainScoreboard()) { + DisguiseUtilities.registerExtendedNames(event.getPlayer().getScoreboard()); + } } }.runTaskLater(LibsDisguises.getInstance(), 20); } diff --git a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java index 510d612e..cc3fe26e 100644 --- a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java +++ b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java @@ -1,36 +1,24 @@ package me.libraryaddict.disguise; -import com.comphenix.protocol.reflect.FieldAccessException; -import com.comphenix.protocol.wrappers.WrappedDataWatcher; -import com.comphenix.protocol.wrappers.WrappedWatchableObject; import me.libraryaddict.disguise.commands.*; -import me.libraryaddict.disguise.disguisetypes.DisguiseType; -import me.libraryaddict.disguise.disguisetypes.FlagWatcher; -import me.libraryaddict.disguise.disguisetypes.MetaIndex; -import me.libraryaddict.disguise.disguisetypes.watchers.*; -import me.libraryaddict.disguise.utilities.DisguiseSound; import me.libraryaddict.disguise.utilities.DisguiseUtilities; import me.libraryaddict.disguise.utilities.LibsPremium; import me.libraryaddict.disguise.utilities.metrics.MetricsInitalizer; import me.libraryaddict.disguise.utilities.packets.PacketsManager; import me.libraryaddict.disguise.utilities.parser.DisguiseParser; -import me.libraryaddict.disguise.utilities.reflection.DisguiseValues; -import me.libraryaddict.disguise.utilities.reflection.FakeBoundingBox; import me.libraryaddict.disguise.utilities.reflection.ReflectionManager; -import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; import org.bukkit.command.CommandExecutor; import org.bukkit.command.PluginCommand; import org.bukkit.command.TabCompleter; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.*; +import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; import java.io.File; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; public class LibsDisguises extends JavaPlugin { private static LibsDisguises instance; diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/Disguise.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/Disguise.java index fcaaf14b..9b86f5c8 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/Disguise.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/Disguise.java @@ -531,7 +531,7 @@ public abstract class Disguise { deleteTab.getPlayerInfoAction().write(0, PlayerInfoAction.REMOVE_PLAYER); deleteTab.getPlayerInfoDataLists().write(0, Collections.singletonList( new PlayerInfoData(disguise.getGameProfile(), 0, NativeGameMode.SURVIVAL, - WrappedChatComponent.fromText(disguise.getName())))); + WrappedChatComponent.fromText(disguise.getProfileName())))); try { for (Player player : Bukkit.getOnlinePlayers()) { @@ -820,7 +820,7 @@ public abstract class Disguise { addTab.getPlayerInfoAction().write(0, PlayerInfoAction.ADD_PLAYER); addTab.getPlayerInfoDataLists().write(0, Collections.singletonList( new PlayerInfoData(disguise.getGameProfile(), 0, NativeGameMode.SURVIVAL, - WrappedChatComponent.fromText(disguise.getName())))); + WrappedChatComponent.fromText(disguise.getProfileName())))); try { for (Player player : Bukkit.getOnlinePlayers()) { diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java index 413fc4a6..458c3f7c 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java @@ -8,6 +8,7 @@ import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction; import com.comphenix.protocol.wrappers.PlayerInfoData; import com.comphenix.protocol.wrappers.WrappedChatComponent; import com.comphenix.protocol.wrappers.WrappedGameProfile; +import me.libraryaddict.disguise.DisguiseConfig; import me.libraryaddict.disguise.LibsDisguises; import me.libraryaddict.disguise.disguisetypes.watchers.PlayerWatcher; import me.libraryaddict.disguise.utilities.DisguiseUtilities; @@ -18,6 +19,7 @@ import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; @@ -30,6 +32,7 @@ public class PlayerDisguise extends TargetedDisguise { private String skinToUse; private boolean nameVisible = true; private UUID uuid = UUID.randomUUID(); + private volatile String[] extendedName; private PlayerDisguise() { super(DisguiseType.PLAYER); @@ -83,6 +86,28 @@ public class PlayerDisguise extends TargetedDisguise { createDisguise(); } + public boolean hasExtendedName() { + return getName().length() > 16; + } + + public boolean hasExtendedNameCreated() { + return extendedName != null; + } + + public String[] getExtendedName() { + if (!hasExtendedName() || hasExtendedNameCreated()) { + return extendedName; + } + + extendedName = DisguiseUtilities.getSplitName(getName()); + + return extendedName; + } + + public String getProfileName() { + return hasExtendedName() ? getExtendedName()[1] : getName(); + } + public UUID getUUID() { return uuid; } @@ -158,10 +183,10 @@ public class PlayerDisguise extends TargetedDisguise { public WrappedGameProfile getGameProfile() { if (gameProfile == null) { if (getSkin() != null) { - gameProfile = ReflectionManager.getGameProfile(uuid, getName()); + gameProfile = ReflectionManager.getGameProfile(uuid, getProfileName()); } else { - gameProfile = ReflectionManager - .getGameProfileWithThisSkin(uuid, getName(), DisguiseUtilities.getProfileFromMojang(this)); + gameProfile = ReflectionManager.getGameProfileWithThisSkin(uuid, getProfileName(), + DisguiseUtilities.getProfileFromMojang(this)); } } @@ -244,14 +269,14 @@ public class PlayerDisguise extends TargetedDisguise { } public void setName(String name) { - if (name.length() > 16) { - name = name.substring(0, 16); - } - if (name.equals(playerName)) { return; } + if (!DisguiseConfig.isExtendedDisguiseNames() && name.length() > 16) { + name = name.substring(0, 16); + } + if (isDisguiseInUse()) { if (stopDisguise()) { playerName = name; @@ -264,6 +289,7 @@ public class PlayerDisguise extends TargetedDisguise { } } else { playerName = name; + extendedName = null; } // Scare monger for the pirates of a certain site. @@ -279,28 +305,38 @@ public class PlayerDisguise extends TargetedDisguise { @Override public boolean startDisguise() { - if (!isDisguiseInUse() && skinToUse != null && gameProfile == null) { - currentLookup = new LibsProfileLookup() { - @Override - public void onLookup(WrappedGameProfile gameProfile) { - if (currentLookup != this || gameProfile == null || gameProfile.getProperties().isEmpty()) - return; + if (!isDisguiseInUse()) { + if (skinToUse != null && gameProfile == null) { + currentLookup = new LibsProfileLookup() { + @Override + public void onLookup(WrappedGameProfile gameProfile) { + if (currentLookup != this || gameProfile == null || gameProfile.getProperties().isEmpty()) + return; + setSkin(gameProfile); + + currentLookup = null; + } + }; + + WrappedGameProfile gameProfile = DisguiseUtilities.getProfileFromMojang(this.skinToUse, currentLookup, + LibsDisguises.getInstance().getConfig().getBoolean("ContactMojangServers", true)); + + if (gameProfile != null) { setSkin(gameProfile); - - currentLookup = null; } - }; - - WrappedGameProfile gameProfile = DisguiseUtilities.getProfileFromMojang(this.skinToUse, currentLookup, - LibsDisguises.getInstance().getConfig().getBoolean("ContactMojangServers", true)); - - if (gameProfile != null) { - setSkin(gameProfile); } + + extendedName = null; } - return super.startDisguise(); + boolean result = super.startDisguise(); + + if (result && hasExtendedName()) { + DisguiseUtilities.registerExtendedName(getExtendedName()); + } + + return result; } public PlayerDisguise setSkin(String newSkin) { @@ -346,7 +382,7 @@ public class PlayerDisguise extends TargetedDisguise { currentLookup = null; this.skinToUse = gameProfile.getName(); - this.gameProfile = ReflectionManager.getGameProfileWithThisSkin(uuid, getName(), gameProfile); + this.gameProfile = ReflectionManager.getGameProfileWithThisSkin(uuid, getProfileName(), gameProfile); if (DisguiseUtilities.isDisguiseInUse(this)) { if (isDisplayedInTab()) { @@ -354,7 +390,7 @@ public class PlayerDisguise extends TargetedDisguise { addTab.getPlayerInfoAction().write(0, PlayerInfoAction.ADD_PLAYER); addTab.getPlayerInfoDataLists().write(0, Arrays.asList( new PlayerInfoData(getGameProfile(), 0, NativeGameMode.SURVIVAL, - WrappedChatComponent.fromText(getName())))); + WrappedChatComponent.fromText(getProfileName())))); PacketContainer deleteTab = addTab.shallowClone(); deleteTab.getPlayerInfoAction().write(0, PlayerInfoAction.REMOVE_PLAYER); @@ -403,4 +439,24 @@ public class PlayerDisguise extends TargetedDisguise { public PlayerDisguise silentlyRemovePlayer(String playername) { return (PlayerDisguise) super.silentlyRemovePlayer(playername); } + + @Override + public boolean removeDisguise(boolean disguiseBeingReplaced) { + boolean result = super.removeDisguise(disguiseBeingReplaced); + + if (result && hasExtendedNameCreated()) { + if (disguiseBeingReplaced) { + new BukkitRunnable() { + @Override + public void run() { + DisguiseUtilities.unregisterAttemptExtendedName(PlayerDisguise.this); + } + }.runTaskLater(LibsDisguises.getInstance(), 5); + } else { + DisguiseUtilities.unregisterAttemptExtendedName(this); + } + } + + return result; + } } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java b/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java index 8a8656cf..07c5b046 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java @@ -21,22 +21,21 @@ import me.libraryaddict.disguise.utilities.json.*; import me.libraryaddict.disguise.utilities.mineskin.MineSkinAPI; import me.libraryaddict.disguise.utilities.packets.LibsPackets; import me.libraryaddict.disguise.utilities.packets.PacketsManager; +import me.libraryaddict.disguise.utilities.parser.DisguiseParseException; import me.libraryaddict.disguise.utilities.reflection.DisguiseValues; import me.libraryaddict.disguise.utilities.reflection.FakeBoundingBox; import me.libraryaddict.disguise.utilities.reflection.LibsProfileLookup; import me.libraryaddict.disguise.utilities.reflection.ReflectionManager; import me.libraryaddict.disguise.utilities.translations.LibsMsg; import org.apache.logging.log4j.util.Strings; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.craftbukkit.libs.org.apache.commons.io.FileUtils; import org.bukkit.entity.*; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scoreboard.Score; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.Team; import org.bukkit.scoreboard.Team.Option; @@ -255,7 +254,7 @@ public class DisguiseUtilities { disguises[i] = dis; } - PrintWriter writer = new PrintWriter(disguiseFile); + PrintWriter writer = new PrintWriter(disguiseFile, "UTF-8"); writer.write(gson.toJson(disguises)); writer.close(); @@ -905,10 +904,18 @@ public class DisguiseUtilities { } } - registerNoName(Bukkit.getScoreboardManager().getMainScoreboard()); + // Clear the old scoreboard teams for extended names! + for (Scoreboard board : getAllScoreboards()) { + for (Team team : board.getTeams()) { + if (!team.getName().matches("LD_[0-9]{10,}")) { + continue; + } - for (Player player : Bukkit.getOnlinePlayers()) { - registerNoName(player.getScoreboard()); + team.unregister(); + } + + registerExtendedNames(board); + registerNoName(board); } } @@ -1214,6 +1221,107 @@ public class DisguiseUtilities { player.updateInventory(); } + public static List getAllScoreboards() { + List boards = new ArrayList<>(); + + boards.add(Bukkit.getScoreboardManager().getMainScoreboard()); + + for (Player player : Bukkit.getOnlinePlayers()) { + if (boards.contains(player.getScoreboard())) { + continue; + } + + boards.add(player.getScoreboard()); + } + + return boards; + } + + public static void registerExtendedName(String[] extended) { + for (Scoreboard board : getAllScoreboards()) { + Team team = board.getEntryTeam(extended[1]); + + if (team != null) { + if (team.getName().startsWith("LD_")) { + if (!extended[0].equals(team.getPrefix())) { + team.setPrefix(extended[0]); + } + + if (!extended[2].equals(team.getSuffix())) { + team.setSuffix(extended[2]); + } + } + } else { + // Ugly! But.. + while (team == null) { + String name = System.currentTimeMillis() + ""; + + if (name.length() > 13) { + name = name.substring(name.length() - 13); + } + + name = "LD_" + name; + + if (board.getTeam(name) != null) { + continue; + } + + team = board.registerNewTeam(name); + team.setPrefix(extended[0]); + team.addEntry(extended[1]); + team.setSuffix(extended[2]); + } + } + } + } + + public static void registerExtendedNames(Scoreboard scoreboard) { + for (Set disguises : getDisguises().values()) { + for (Disguise disguise : disguises) { + if (!disguise.isPlayerDisguise()) { + continue; + } + + if (!((PlayerDisguise) disguise).hasExtendedName()) { + continue; + } + + String[] extended = ((PlayerDisguise) disguise).getExtendedName(); + + registerExtendedName(extended); + } + } + } + + public static void unregisterAttemptExtendedName(PlayerDisguise removed) { + for (Set disguises : getDisguises().values()) { + for (Disguise disguise : disguises) { + if (!disguise.isPlayerDisguise()) { + continue; + } + + if (!((PlayerDisguise) disguise).hasExtendedName()) { + continue; + } + + if (!((PlayerDisguise) disguise).getExtendedName()[1].equals(removed.getExtendedName()[1])) + continue; + + return; + } + } + + for (Scoreboard board : getAllScoreboards()) { + Team team = board.getEntryTeam(removed.getExtendedName()[1]); + + if (team == null || !team.getName().startsWith("LD_")) { + continue; + } + + team.unregister(); + } + } + public static void registerNoName(Scoreboard scoreboard) { Team mainTeam = scoreboard.getTeam("LD_NoName"); @@ -1226,6 +1334,97 @@ public class DisguiseUtilities { } } + public static String[] getSplitName(String name) { + if (name.length() <= 16) { + throw new IllegalStateException("This can only be used for names longer than 16 characters!"); + } + + if (name.length() > 48) { + name = name.substring(0, 48); + } + + for (Set disguises : getDisguises().values()) { + for (Disguise disguise : disguises) { + if (!disguise.isPlayerDisguise()) { + continue; + } + + if (!((PlayerDisguise) disguise).getName().equals(name) || + !((PlayerDisguise) disguise).hasExtendedNameCreated()) { + continue; + } + + return ((PlayerDisguise) disguise).getExtendedName(); + } + } + + Scoreboard board = Bukkit.getScoreboardManager().getMainScoreboard(); + + for (int prefixLen = 16; prefixLen >= 0; prefixLen--) { + String prefix = name.substring(0, prefixLen); + + if (prefix.endsWith("" + ChatColor.COLOR_CHAR)) { + continue; + } + + String colors = ChatColor.getLastColors(prefix); + + // We found our prefix. Now we check about seperating it between name and suffix + for (int nameLen = Math.min(name.length() - (prefixLen + colors.length()), 16 - colors.length()); + nameLen > 0; nameLen--) { + String nName = colors + name.substring(prefixLen, nameLen + prefixLen); + + if (nName.endsWith("" + ChatColor.COLOR_CHAR)) { + continue; + } + + String suffix = name.substring(nameLen + prefixLen); + + if (suffix.length() > 16) { + suffix = suffix.substring(0, 16); + } + + String[] extended = new String[]{prefix, nName, suffix}; + + if (!isValidPlayerName(board, extended)) { + continue; + } + + return extended; + } + } + + // Failed to find a unique name.. Ah well. + + String prefix = name.substring(0, 16); + + if (prefix.endsWith(ChatColor.COLOR_CHAR + "")) { + prefix = prefix.substring(0, 15); + } + + String nName = name.substring(prefix.length(), prefix.length() + Math.min(16, prefix.length())); + + if (nName.endsWith(ChatColor.COLOR_CHAR + "") && nName.length() > 1) { + nName = nName.substring(0, nName.length() - 1); + } + + String suffix = name.substring(prefix.length() + nName.length()); + + if (suffix.length() > 16) { + suffix = suffix.substring(0, 16); + } + + return new String[]{prefix, nName, suffix}; + } + + private static boolean isValidPlayerName(Scoreboard board, String[] name) { + Team team; + + return ((team = board.getEntryTeam(name[1])) == null || + (team.getName().startsWith("LD_") && team.getPrefix().equals(name[0]) && + team.getSuffix().equals(name[2]))) && Bukkit.getPlayerExact(name[1]) == null; + } + public static void removeSelfDisguiseScoreboard(Player player) { String originalTeam = preDisguiseTeam.remove(player.getUniqueId()); String teamDisguise = disguiseTeam.remove(player.getUniqueId()); 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 c4cf9472..6e68fe46 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 @@ -155,9 +155,9 @@ public class PacketHandlerSpawn implements IPacketHandler { } else if (disguise.getType().isPlayer()) { PlayerDisguise playerDisguise = (PlayerDisguise) disguise; - String name = playerDisguise.getName(); WrappedGameProfile spawnProfile = playerDisguise.isNameVisible() ? playerDisguise.getGameProfile() : - ReflectionManager.getGameProfileWithThisSkin(UUID.randomUUID(), "", + ReflectionManager.getGameProfileWithThisSkin(UUID.randomUUID(), + playerDisguise.isNameVisible() ? playerDisguise.getProfileName() : "", playerDisguise.getGameProfile()); int entityId = disguisedEntity.getEntityId(); diff --git a/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java b/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java index 6cda560a..5f39b9b1 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java @@ -136,7 +136,7 @@ public class DisguiseParser { stringBuilder.append(disguise.getType().name()); if (disguise.isPlayerDisguise()) { - stringBuilder.append(" ").append(((PlayerDisguise) disguise).getName()); + stringBuilder.append(" ").append(DisguiseUtilities.quote(((PlayerDisguise) disguise).getName())); } for (Method m : ParamInfoManager.getDisguiseWatcherMethods(disguise.getType().getWatcherClass())) { diff --git a/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java b/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java index b3251e00..c0bd1f6a 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java @@ -49,8 +49,6 @@ public class ReflectionManager { private static Field trackedEntitiesField; public static void init() { - bukkitVersion = Bukkit.getServer().getClass().getName().split("\\.")[3]; - try { Object entity = createEntityInstance(DisguiseType.COW, "Cow"); @@ -286,6 +284,10 @@ public class ReflectionManager { } public static String getBukkitVersion() { + if (bukkitVersion == null) { + bukkitVersion = Bukkit.getServer().getClass().getName().split("\\.")[3]; + } + return bukkitVersion; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 934b37b2..9401f458 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -42,6 +42,9 @@ SaveDisguises: Players: false Entities: false +# Do names go beyond the 16 char limit for player disguises? +ExtendedNames: true + # Does the player keep their disguise after they die? KeepDisguises: PlayerDeath: false