I'm currently working on a plugin that lets you assume the identity of another player. It does this almost flawlessly: Your UUID and username are changed to that of the user whose identity you are assuming serverside, and as far as the server and plugins can tell, you appear to be that player. You will have the same rank as them, same permissions, everything. The one thing I haven't been able to get is the skin. I had thought that a player's skin would be changed for other players when the UUID was, but this doesn't seem to be the case. I'm using reflection to change the UUID in both the GameProfile and the EntityPlayer (the uniqueID field is inherited from Entity), and all methods of getting the player's UUID return the one that the plugin has set. I've dug through decompiled NMS and Bukkit/Spigot forums, but all of them seem to indicate that the skin should change with the UUID. I'm sending a PlayerQuitEvent and PlayerJoinEvent to plugins to simulate the real player leaving and the assumed player joining, and sending packets to all players to remove the old player from tab and ingame, then add the new one. I'd prefer to not use ProtocolLib if it can be avoided. Any help would be appreciated, can anyone point me in the right direction?
Thanks in advance!
I figured it out myself. It turns out that a GameProfile contains a skin texture. This texture has to be requested from the Mojang session server. Here's the code:
public static boolean setSkin(GameProfile profile, UUID uuid) {
try {
HttpsURLConnection connection = (HttpsURLConnection) new URL(String.format("https://sessionserver.mojang.com/session/minecraft/profile/%s?unsigned=false", UUIDTypeAdapter.fromUUID(uuid))).openConnection();
if (connection.getResponseCode() == HttpsURLConnection.HTTP_OK) {
String reply = new BufferedReader(new InputStreamReader(connection.getInputStream())).readLine();
String skin = reply.split("\"value\":\"")[1].split("\"")[0];
String signature = reply.split("\"signature\":\"")[1].split("\"")[0];
profile.getProperties().put("textures", new Property("textures", skin, signature));
return true;
} else {
System.out.println("Connection could not be opened (Response code " + connection.getResponseCode() + ", " + connection.getResponseMessage() + ")");
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}