diff --git a/pom.xml b/pom.xml index 0772c78d..a3e3398b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 LibsDisguises LibsDisguises - 8.2.4 + 8.2.4-SNAPSHOT src diff --git a/src/me/libraryaddict/disguise/disguisetypes/Disguise.java b/src/me/libraryaddict/disguise/disguisetypes/Disguise.java index 7d0ee8b7..cf6b01aa 100644 --- a/src/me/libraryaddict/disguise/disguisetypes/Disguise.java +++ b/src/me/libraryaddict/disguise/disguisetypes/Disguise.java @@ -439,7 +439,7 @@ public abstract class Disguise { } } } - DisguiseUtilities.removeGameprofile(name); + DisguiseUtilities.getGameProfiles().remove(name); } } } diff --git a/src/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java b/src/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java index aa5f9028..42d4d16a 100644 --- a/src/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java +++ b/src/me/libraryaddict/disguise/disguisetypes/PlayerDisguise.java @@ -1,7 +1,15 @@ package me.libraryaddict.disguise.disguisetypes; +import me.libraryaddict.disguise.utilities.DisguiseUtilities; +import me.libraryaddict.disguise.utilities.LibsProfileLookup; +import me.libraryaddict.disguise.utilities.ReflectionManager; +import me.libraryaddict.disguise.utilities.ReflectionManager.LibVersion; + public class PlayerDisguise extends TargetedDisguise { + private LibsProfileLookup currentLookup; + private Object gameProfile; private String playerName; + private String skinToUse; public PlayerDisguise(String name) { if (name.length() > 16) @@ -16,9 +24,21 @@ public class PlayerDisguise extends TargetedDisguise { this.setReplaceSounds(replaceSounds); } + @Deprecated + public PlayerDisguise(String name, String skinToUse) { + this(name); + setSkin(skinToUse); + } + @Override public PlayerDisguise clone() { PlayerDisguise disguise = new PlayerDisguise(getName()); + if (disguise.currentLookup == null && disguise.gameProfile != null) { + disguise.skinToUse = getSkin(); + disguise.gameProfile = gameProfile; + } else { + disguise.setSkin(getSkin()); + } disguise.setReplaceSounds(isSoundsReplaced()); disguise.setViewSelfDisguise(isSelfDisguiseVisible()); disguise.setHearSelfDisguise(isSelfDisguiseSoundsReplaced()); @@ -30,13 +50,66 @@ public class PlayerDisguise extends TargetedDisguise { return disguise; } + @Deprecated + public Object getGameProfile() { + if (getSkin() != null) { + if (gameProfile != null) { + return gameProfile; + } + return ReflectionManager.getGameProfile(null, getName()); + } else { + return DisguiseUtilities.getProfileFromMojang(getName()); + } + } + public String getName() { return playerName; } + @Deprecated + public String getSkin() { + return skinToUse; + } + @Override public boolean isPlayerDisguise() { return true; } + @Deprecated + public void setGameProfile(Object gameProfile) { + this.gameProfile = ReflectionManager.getGameProfileWithThisSkin(null, getName(), gameProfile); + } + + @Deprecated + public void setSkin(String skinToUse) { + this.skinToUse = skinToUse; + if (skinToUse == null) { + this.currentLookup = null; + this.gameProfile = null; + } else { + if (skinToUse.length() > 16) { + this.skinToUse = skinToUse.substring(0, 16); + } + if (LibVersion.is1_7()) { + currentLookup = new LibsProfileLookup() { + + @Override + public void onLookup(Object gameProfile) { + if (currentLookup == this && gameProfile != null) { + setGameProfile(gameProfile); + if (DisguiseUtilities.isDisguiseInUse(PlayerDisguise.this)) { + DisguiseUtilities.refreshTrackers(PlayerDisguise.this); + } + } + } + }; + Object obj = DisguiseUtilities.getProfileFromMojang(this.skinToUse, currentLookup); + if (obj != null) { + setGameProfile(obj); + } + } + } + } + } \ No newline at end of file diff --git a/src/me/libraryaddict/disguise/disguisetypes/watchers/PlayerWatcher.java b/src/me/libraryaddict/disguise/disguisetypes/watchers/PlayerWatcher.java index 038024d8..7a3bff28 100644 --- a/src/me/libraryaddict/disguise/disguisetypes/watchers/PlayerWatcher.java +++ b/src/me/libraryaddict/disguise/disguisetypes/watchers/PlayerWatcher.java @@ -10,6 +10,7 @@ import com.comphenix.protocol.reflect.StructureModifier; import me.libraryaddict.disguise.DisguiseConfig; import me.libraryaddict.disguise.disguisetypes.Disguise; +import me.libraryaddict.disguise.disguisetypes.PlayerDisguise; import me.libraryaddict.disguise.utilities.DisguiseUtilities; import me.libraryaddict.disguise.utilities.ReflectionManager.LibVersion; @@ -39,6 +40,10 @@ public class PlayerWatcher extends LivingWatcher { sendData(9); } + public void setSkin(String playerName) { + ((PlayerDisguise) getDisguise()).setSkin(playerName); + } + /** * The facing direction for the bed is the block metadata. 0 - 90 degrees. 1 - 0 degrees. 2 - 270 degrees. 3 - 180 degrees. */ diff --git a/src/me/libraryaddict/disguise/utilities/DisguiseUtilities.java b/src/me/libraryaddict/disguise/utilities/DisguiseUtilities.java index 449549ac..87b95847 100644 --- a/src/me/libraryaddict/disguise/utilities/DisguiseUtilities.java +++ b/src/me/libraryaddict/disguise/utilities/DisguiseUtilities.java @@ -19,7 +19,6 @@ import me.libraryaddict.disguise.disguisetypes.TargetedDisguise; import me.libraryaddict.disguise.disguisetypes.watchers.AgeableWatcher; import me.libraryaddict.disguise.disguisetypes.watchers.ZombieWatcher; import me.libraryaddict.disguise.disguisetypes.TargetedDisguise.TargetType; - import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -57,6 +56,7 @@ public class DisguiseUtilities { */ private static HashMap gameProfiles = new HashMap(); private static LibsDisguises libsDisguises; + private static HashMap> runnables = new HashMap>(); /** * A internal storage of fake entity ID's each entity has. Realistically I could probably use a ID like "4" for everyone, * seeing as no one sees each others entity ID @@ -81,6 +81,11 @@ public class DisguiseUtilities { futureDisguises.get(entityId).add(disguise); } + public static void addGameProfile(String string, Object gameProfile) { + getGameProfiles().put(string, gameProfile); + addedByPlugins.add(string); + } + /** * If name isn't null. Make sure that the name doesn't see any other disguise. Else if name is null. Make sure that the * observers in the disguise don't see any other disguise. @@ -245,6 +250,10 @@ public class DisguiseUtilities { return gameProfiles.get(playerName); } + public static HashMap getGameProfiles() { + return gameProfiles; + } + public static TargetedDisguise getMainDisguise(UUID entityId) { TargetedDisguise toReturn = null; if (getDisguises().containsKey(entityId)) { @@ -286,8 +295,11 @@ public class DisguiseUtilities { } public static Object getProfileFromMojang(final String playerName) { - return getProfileFromMojang(playerName, new Runnable() { - public void run() { + return getProfileFromMojang(playerName, new LibsProfileLookup() { + + @Override + public void onLookup(Object gameProfile) { + getAddedByPlugins().remove(playerName); for (HashSet disguises : DisguiseUtilities.getDisguises().values()) { for (TargetedDisguise disguise : disguises) { if (disguise.getType() == DisguiseType.PLAYER && ((PlayerDisguise) disguise).getName().equals(playerName)) { @@ -306,7 +318,11 @@ public class DisguiseUtilities { * Thread safe to use. This returns a GameProfile. And if its GameProfile doesn't have a skin blob. Then it does a lookup * using schedulers. The runnable is run once the GameProfile has been successfully dealt with */ - public static Object getProfileFromMojang(final String playerName, final Runnable runnable) { + public static Object getProfileFromMojang(String playerName, LibsProfileLookup runnableIfCantReturn) { + return getProfileFromMojang(playerName, (Object) runnableIfCantReturn); + } + + private static Object getProfileFromMojang(final String playerName, final Object runnable) { if (gameProfiles.containsKey(playerName)) { if (gameProfiles.get(playerName) != null) { return gameProfiles.get(playerName); @@ -331,8 +347,14 @@ public class DisguiseUtilities { public void run() { if (gameProfiles.containsKey(playerName) && gameProfiles.get(playerName) == null) { gameProfiles.put(playerName, gameProfile); - if (runnable != null) { - runnable.run(); + } + if (runnables.containsKey(playerName)) { + for (Object obj : runnables.remove(playerName)) { + if (obj instanceof Runnable) { + ((Runnable) obj).run(); + } else if (obj instanceof LibsProfileLookup) { + ((LibsProfileLookup) obj).onLookup(gameProfile); + } } } } @@ -348,9 +370,23 @@ public class DisguiseUtilities { } }); } + if (runnable != null) { + if (!runnables.containsKey(playerName)) { + runnables.put(playerName, new ArrayList()); + } + runnables.get(playerName).add(runnable); + } return ReflectionManager.getGameProfile(null, playerName); } + /** + * Thread safe to use. This returns a GameProfile. And if its GameProfile doesn't have a skin blob. Then it does a lookup + * using schedulers. The runnable is run once the GameProfile has been successfully dealt with + */ + public static Object getProfileFromMojang(String playerName, Runnable runnableIfCantReturn) { + return getProfileFromMojang(playerName, (Object) runnableIfCantReturn); + } + public static List getSeenDisguises(String viewer) { List dis = new ArrayList(); for (HashSet disguises : getDisguises().values()) { @@ -521,10 +557,15 @@ public class DisguiseUtilities { return false; } + @Deprecated public static void removeGameprofile(String string) { gameProfiles.remove(string); } + public static void removeGameProfile(String string) { + gameProfiles.remove(string); + } + public static void removeSelfDisguise(Player player) { if (selfDisguisesIds.containsKey(player.getUniqueId())) { // Send a packet to destroy the fake entity diff --git a/src/me/libraryaddict/disguise/utilities/LibsProfileLookup.java b/src/me/libraryaddict/disguise/utilities/LibsProfileLookup.java new file mode 100644 index 00000000..003eafcf --- /dev/null +++ b/src/me/libraryaddict/disguise/utilities/LibsProfileLookup.java @@ -0,0 +1,6 @@ +package me.libraryaddict.disguise.utilities; + +public interface LibsProfileLookup { + public void onLookup(Object gameProfile); + +} diff --git a/src/me/libraryaddict/disguise/utilities/PacketsManager.java b/src/me/libraryaddict/disguise/utilities/PacketsManager.java index 42962b46..1570e606 100644 --- a/src/me/libraryaddict/disguise/utilities/PacketsManager.java +++ b/src/me/libraryaddict/disguise/utilities/PacketsManager.java @@ -186,7 +186,7 @@ public class PacketsManager { if (!DisguiseUtilities.hasGameProfile(name)) { removeName = !DisguiseUtilities.getAddedByPlugins().contains(name); } - gameProfile = DisguiseUtilities.getProfileFromMojang(name); + gameProfile = ((PlayerDisguise) disguise).getGameProfile(); if (removeName) { DisguiseUtilities.getAddedByPlugins().remove(name); } diff --git a/src/me/libraryaddict/disguise/utilities/ReflectionManager.java b/src/me/libraryaddict/disguise/utilities/ReflectionManager.java index aab74da6..2709db8b 100644 --- a/src/me/libraryaddict/disguise/utilities/ReflectionManager.java +++ b/src/me/libraryaddict/disguise/utilities/ReflectionManager.java @@ -233,6 +233,27 @@ public class ReflectionManager { return null; } + public static Object getGameProfileWithThisSkin(UUID uuid, String playerName, Object profileWithSkin) { + try { + Object gameProfile; + try { + gameProfile = Class.forName("net.minecraft.util.com.mojang.authlib.GameProfile") + .getConstructor(UUID.class, String.class) + .newInstance(uuid != null ? uuid : UUID.randomUUID(), playerName); + } catch (NoSuchMethodException ex) { + gameProfile = Class.forName("net.minecraft.util.com.mojang.authlib.GameProfile") + .getConstructor(String.class, String.class).newInstance(uuid != null ? uuid.toString() : "", playerName); + } + Field properties = gameProfile.getClass().getDeclaredField("properties"); + properties.setAccessible(true); + properties.set(gameProfile, properties.get(profileWithSkin)); + return gameProfile; + } catch (Exception ex) { + ex.printStackTrace(); + } + return null; + } + public static Class getNmsClass(String className) { try { return Class.forName("net.minecraft.server." + getBukkitVersion() + "." + className);