Solved (1.8) Updating a player's skin

Discussion in 'Spigot Plugin Development' started by tomsoz123, Jul 3, 2021.

  1. Hi, I am making a /skin plugin so people can disguise and I need to update the player so the skin gets changed.
    Right now the player has to relog for the skin to be changed and I'm not sure how to automatically update the player's skin.
    This is what I have at the moment:
    Command:
    Code (Java):
    package tk.Dulcy.Dulcy_CORE.Commands.Rank;

    import org.bukkit.Bukkit;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
    import org.bukkit.entity.Player;

    import net.minecraft.server.v1_8_R3.EntityPlayer;
    import tk.Dulcy.Dulcy_CORE.Main;
    import tk.Dulcy.Dulcy_CORE.Utils;

    public class SetSkin implements CommandExecutor{
        Main main;
        public SetSkin(Main main) {
            this.main=main;
        }
        @SuppressWarnings("deprecation")
        @Override
        public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
            if (label.equalsIgnoreCase("skin")) {
                if (!(sender instanceof Player)) {
                    sender.sendMessage(Utils.chat("&cThis is a player command."));
                    return true;
                }
                Player p = (Player)sender;
                if (!p.hasPermission("rank.skin")) {
                    p.sendMessage(Utils.chat("&cYou need &e&lD&4&lu&e&ll&4&lc&e&ly&f+ &crank or above to perform this command."));
                    return true;
                }
                if (!(args.length > 0)) {
                    p.sendMessage(Utils.chat("&cUsage: /skin <username>"));
                    return true;
                }
                if (args[0].equalsIgnoreCase("reset")||args[0].equalsIgnoreCase("off")) {
                    if (args.length > 1) {
                        Player target = Bukkit.getPlayer(args[1]);
                        if (target==null) {
                            if (Utils.skins.containsKey(p.getUniqueId())) {
                                Utils.skins.replace(p.getUniqueId(), p.getUniqueId().toString());
                            } else {
                                Utils.skins.put(p.getUniqueId(), p.getUniqueId().toString());
                            }
                            p.sendMessage(Utils.chat("&aYour skin has been reset, please relog."));
                            return true;
                        }
                        if (!p.hasPermission("staff.skin.others")) {
                            if (Utils.skins.containsKey(p.getUniqueId())) {
                                Utils.skins.replace(p.getUniqueId(), p.getUniqueId().toString());
                            } else {
                                Utils.skins.put(p.getUniqueId(), p.getUniqueId().toString());
                            }
                            p.sendMessage(Utils.chat("&aYour skin has been reset, please relog."));
                            return true;
                        }
                        if (Utils.skins.containsKey(p.getUniqueId())) {
                            Utils.skins.replace(target.getUniqueId(), target.getUniqueId().toString());
                        } else {
                            Utils.skins.put(target.getUniqueId(), target.getUniqueId().toString());
                        }
                        target.kickPlayer(Utils.chat("&cYou have been kicked as a staff member\nhas had to reset your skin.\nPlease rejoin."));
                        p.sendMessage(Utils.chat("&a"+target.getName()+"&a's skin has been reset."));
                        return true;
                    }else {
                        if (Utils.skins.containsKey(p.getUniqueId())) {
                            Utils.skins.replace(p.getUniqueId(), p.getUniqueId().toString());
                        } else {
                            Utils.skins.put(p.getUniqueId(), p.getUniqueId().toString());
                        }
                        p.sendMessage(Utils.chat("&aYour skin has been reset, please relog."));
                        return true;
                    }
                }
                if (!Utils.doesPlayerExist(args[0])) {
                    p.sendMessage(Utils.chat("&cThis player dosen't exist."));
                    return true;
                }
                if (Utils.skins.containsKey(p.getUniqueId())) {
                    Utils.skins.replace(p.getUniqueId(), Utils.getPlayerUUID(args[0]));
                } else {
                    Utils.skins.put(p.getUniqueId(), Utils.getPlayerUUID(args[0]));
                }
                Utils.setSkin(((CraftPlayer)p).getProfile(), Utils.getPlayerUUID(args[0]));
                Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(main, new Runnable() {
                    @Override
                    public void run() {
                        EntityPlayer ep = (EntityPlayer) ((CraftPlayer) p).getHandle();
                        ep.server.getPlayerList().moveToWorld(ep, 0, false, p.getLocation(), true);
                    }
                }, 1*20);
                p.sendMessage(Utils.chat("&aSuccess! Skin changed"));
            }
            return false;
        }
    }
     
    Utils setSkin() function:
    Code (Java):
    public static boolean setSkin(GameProfile profile, String uuid) {
            try {
                URL url = new URL("https://sessionserver.mojang.com/session/minecraft/profile/"+uuid+"?unsigned=false");
                InputStreamReader reader = new InputStreamReader(url.openStream());
                JsonObject properties = new JsonParser().parse(reader).getAsJsonObject().get("properties").getAsJsonArray().get(0).getAsJsonObject();
                String texture = properties.get("value").getAsString();
                String signature = properties.get("signature").getAsString();
                profile.getProperties().removeAll("textures");
                profile.getProperties().put("textures", new Property("textures", texture, signature));
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
     
  2. You need to hide and show the player that has had their skin changed to every other player with Player#hidePlayer & Player#showPlayer respectively.
     
  3. Send the respawn packet to the player to update it for them without having to relog (PacketPlayOutRespawn)
     
  4. Didn't work,
    Heres how i did it:
    Code (Java):
    EntityPlayer ep = (EntityPlayer) ((CraftPlayer) p).getHandle();
    WorldServer ws = (WorldServer) ((CraftWorld)p.getWorld()).getHandle();
    PacketPlayOutRespawn packet = new PacketPlayOutRespawn(ws.getWorld().getEnvironment().getId(), ws.getDifficulty(), ws.getWorldData().getType(), ep.playerInteractManager.getGameMode());                    
    ep.playerConnection.sendPacket(packet);
    ep.spawnIn(((WorldServer)p.getWorld()));
    ep.dead = false;
     
  5. Didnt work:
    Code (Java):
    for (Player lp : Bukkit.getOnlinePlayers()) {
        lp.hidePlayer(p);
        lp.showPlayer(p);
    }
     
  6. You could try sending the player to another dimension/world, then teleporting him back to his previous location. It's not a very good solution, but should work for now until you find a real one.
     
  7. Did you use this inside a for loop? You have to send this packet to all players
     
  8. Strange, try it with a delay? This is what I have for updating a player and it works fine for me.
    Code (Java):
            Bukkit.getOnlinePlayers().forEach(p -> p.hidePlayer(player));
            Bukkit.getOnlinePlayers().forEach(p -> p.showPlayer(player));
    Alternatively, you could send packets to remove and add the player, but that gets messy.
     
  9. This works but is there any way to make it so it shows the skin for the player themselfs and not just others.
     
  10. Log back in
     
  11. other than relogging
     
  12. Not possible, the user’s skin is cached on the client
     
  13. isn't it possible to reload the skin for the player themselfs like i did for the other players
     
  14. No, the user’s own skin is cached on the client
     
  15. Okay, thanks to everyone who helped!
     
  16. This isn't actually entirely true, you can infact change the player's skin for themself with packets, its just a bit weird and I can't remember but it might not work for older versions.

    You might need to do some research, you can also look at the source code of libs disguises I believe they have that feature, but here is what I have. One issue you'll encounter is the client failing to load chunks which might not be an issue on later versions but is very much an issue on 1.8.8.

    Code (Java):
    public void updatePlayer (Player player) {

            Bukkit.getOnlinePlayers().forEach(p -> p.hidePlayer(player));
            Bukkit.getOnlinePlayers().forEach(p -> p.showPlayer(player));

            WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn();
            respawn.setDefaults(player);
            WrapperPlayServerPlayerInfo remove = new WrapperPlayServerPlayerInfo();
            remove.setDefaults(player, EnumWrappers.PlayerInfoAction.REMOVE_PLAYER);
            WrapperPlayServerPlayerInfo add = new WrapperPlayServerPlayerInfo();
            add.setDefaults(player, EnumWrappers.PlayerInfoAction.ADD_PLAYER);


            try {
                protocolManager.sendServerPacket(player, remove.getHandle());
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }

            final boolean flying = player.isFlying();
            final Location location = player.getLocation();
            final int level = player.getLevel();
            final float xp = player.getExp();
            final double maxHealth = player.getMaxHealth();
            final double health = player.getHealth();

            Bukkit.getScheduler().runTaskLater(plugin, () -> {

                try {

                    protocolManager.sendServerPacket(player, respawn.getHandle());

                    player.setFlying(flying);
                    player.teleport(location);
                    player.updateInventory();
                    player.setLevel(level);
                    player.setExp(xp);
                    player.setMaxHealth(maxHealth);
                    player.setHealth(health);

                    protocolManager.sendServerPacket(player, add.getHandle());

                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }

            }, 1);

        }
    You essentially need to remove the player (just for themself) off the tab list, send a respawn packet then send an add packet right after.