How to spawn NPC with skin

Discussion in 'Spigot Plugin Development' started by nitnoq, May 1, 2017.

  1. Hi, I'm actually devlopping a plugin in wich I need to make spawn NPC. I can make them spawn esealy but I can't assign a skin from a real player to them. Thanks for help
     
  2. what have you tried so far? that can be easily handled by updating the GameProfile properties.
     
  3. This is my code:
    I get a random player uuid/name from my database
    Code (Text):
    try {
        MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
        ResultSet data = Database.query("SELECT uuid, lastname FROM pnjserv_players ORDER BY RAND() LIMIT 1;");
        if(data.next()){
            String uuid = data.getString("uuid");
            String name = data.getString("lastname");
            GameProfile gameProfile = new GameProfile(UUID.fromString(uuid), name);
               
            HttpURLConnection connection = (HttpURLConnection) new URL("https://sessionserver.mojang.com/session/minecraft/profile/"+uuid.replace("-", "")).openConnection();
            JSONArray response = (JSONArray)((JSONObject) jsonParser.parse(new InputStreamReader(connection.getInputStream()))).get("properties");
            JSONObject a = (JSONObject) response.get(0);
                   
            gameProfile.getProperties().put("textures", new Property((String) a.get("name"), (String) a.get("value")));
           
            WorldServer world = ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle();
            EntityPlayer npc = new EntityPlayer(server, world, gameProfile, new NPCInteractManager(world));
            npc.setLocation(player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player.getLocation().getYaw(), player.getLocation().getPitch());
           
            for(Player pls : Bukkit.getOnlinePlayers())
            {
                PlayerConnection connection = ((CraftPlayer) pls).getHandle().playerConnection;
                connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, npc));
                connection.sendPacket(new PacketPlayOutNamedEntitySpawn(npc));
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
     
    • Informative Informative x 1
  4. So your issue is that the npc doens't have a skin applied?
    Have you made some outputs for the texture values? Because the sessionservers won't allow requests that are done several times in some seconds
    Edit: And maybe also outputs from your uuid if that is maybe called wrong
     
    • Like Like x 1
    • Informative Informative x 1
  5. I try with me and broadcast the results:
    My uuid is: b8621ff7-bd32-4231-9911-1200ab9a840c
    My username is: nitnoq
    a.get("name") return: "textures"
    a.get("value") return: "eyJ0aW1lc3RhbXAiOjE0OTM2NDcxOTU0MDYsInByb2ZpbGVJZCI6ImI4NjIxZmY3YmQzMjQyMzE5OTExMTIwMGFiOWE4NDBjIiwicHJvZmlsZU5hbWUiOiJuaXRub3EiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWVlMDQ5YjgyZGMyYmNiYmEzYjIxOGU4YTNlOTMzNDI5N2I2MTEzNWM3ODQ5ZGI0NTY5M2Y0Y2QzYyJ9fX0="

    So I don't think there are a problem during the mojang servers request

    EDIT:
    gameProfile.getProperties().put("textures", new Property((String) a.get("name"), (String) a.get("value")));
    I'm not shure about the utilisation of this
     
    #5 nitnoq, May 1, 2017
    Last edited: May 1, 2017
    • Useful Useful x 1
  6. You need a Signature
     
  7. Where can I get it ?
     
  8. I anyone know how to get a signature ?
     
  9. From the profile that you get the value thing
     
  10. I dont know, where do you get the "value" field for the profile?
     
  11. I'm making a request to mojang servers: https://sessionserver.mojang.com/session/minecraft/profile/b8621ff7bd32423199111200ab9a840c
    And it return this:
    Code (Text):
    {
        "id": "b8621ff7bd32423199111200ab9a840c",
        "name": "nitnoq",
        "properties": [{
            "name": "textures",
            "value": "eyJ0aW1lc3RhbXAiOjE0OTM2Njc3NTQ3ODEsInByb2ZpbGVJZCI6ImI4NjIxZmY3YmQzMjQyMzE5OTExMTIwMGFiOWE4NDBjIiwicHJvZmlsZU5hbWUiOiJuaXRub3EiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWVlMDQ5YjgyZGMyYmNiYmEzYjIxOGU4YTNlOTMzNDI5N2I2MTEzNWM3ODQ5ZGI0NTY5M2Y0Y2QzYyJ9fX0="
        }]
    }
     
  12. You need to add a field to the url, this:
    ?unsigned=false
     
  13. By adding "?unsigned=false" I'm getting the signature with success. But I can't see skins.
     
  14. Maybe let the player force respawn after you apply the skin (that's what i had to do at one of my old Nick systems)
     
  15. WAS

    WAS

    Here is my 1_11 FakePlayer class. Feel free to use it. It's MIT. It works off of a in-game player, so you'd just need to change that for a skin as shown above.

    1_11_R1 Class
    Code (Java):
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.craftbukkit.v1_11_R1.CraftServer;
    import org.bukkit.craftbukkit.v1_11_R1.CraftWorld;
    import org.bukkit.craftbukkit.v1_11_R1.entity.CraftPlayer;
    import org.bukkit.craftbukkit.v1_11_R1.inventory.CraftItemStack;
    import org.bukkit.entity.Player;

    import com.mojang.authlib.GameProfile;

    import net.minecraft.server.v1_11_R1.EntityPlayer;
    import net.minecraft.server.v1_11_R1.EnumItemSlot;
    import net.minecraft.server.v1_11_R1.ItemStack;
    import net.minecraft.server.v1_11_R1.MinecraftServer;
    import net.minecraft.server.v1_11_R1.PacketPlayOutNamedEntitySpawn;
    import net.minecraft.server.v1_11_R1.PacketPlayOutPlayerInfo;
    import net.minecraft.server.v1_11_R1.PlayerConnection;
    import net.minecraft.server.v1_11_R1.PlayerInteractManager;
    import net.minecraft.server.v1_11_R1.WorldServer;
    import net.minecraft.server.v1_11_R1.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;

    /*************************
    *
    *   Copyright (c) 2017 Jordan Thompson (WASasquatch)
    *
    *   Permission is hereby granted, free of charge, to any person obtaining a copy
    *   of this software and associated documentation files (the "Software"), to deal
    *   in the Software without restriction, including without limitation the rights
    *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    *   copies of the Software, and to permit persons to whom the Software is
    *   furnished to do so, subject to the following conditions:
    *
    *   The above copyright notice and this permission notice shall be included in all
    *   copies or substantial portions of the Software.
    *
    *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    *   SOFTWARE.
    *
    *************************/


    public class FakePlayer_v1_11_R1 implements FakePlayer {
     
       public void spawnFakePlayer(Player player, Location location, String displayName) {
        MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
        WorldServer world = ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle();
        EntityPlayer npc = new EntityPlayer(server,
                           world,
                           new GameProfile(player.getUniqueId(),
                                   displayName),
                           new PlayerInteractManager(world));

        npc.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
     
        ItemStack feet = CraftItemStack.asNMSCopy(player.getInventory().getBoots());
        ItemStack legs = CraftItemStack.asNMSCopy(player.getInventory().getLeggings());
        ItemStack chest = CraftItemStack.asNMSCopy(player.getInventory().getChestplate());
        ItemStack head = CraftItemStack.asNMSCopy(player.getInventory().getHelmet());
        ItemStack mainHand = CraftItemStack.asNMSCopy(player.getInventory().getItemInMainHand());
        ItemStack offHand = CraftItemStack.asNMSCopy(player.getInventory().getItemInOffHand());
       
        npc.setEquipment(EnumItemSlot.FEET, feet);
        npc.setEquipment(EnumItemSlot.LEGS, legs);
        npc.setEquipment(EnumItemSlot.CHEST, chest);
        npc.setEquipment(EnumItemSlot.HEAD, head);
        npc.setEquipment(EnumItemSlot.MAINHAND, mainHand);
        npc.setEquipment(EnumItemSlot.OFFHAND, offHand);
       
        for (Player p : Bukkit.getOnlinePlayers()) {
          PlayerConnection connection = ((CraftPlayer)p).getHandle().playerConnection;
          connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, npc));
          connection.sendPacket(new PacketPlayOutNamedEntitySpawn(npc));
        }
       
       }

    }
    Interface
    Code (Java):
    import org.bukkit.Location;
    import org.bukkit.entity.Player;

    /*************************
    *
    *   Copyright (c) 2017 Jordan Thompson (WASasquatch)
    *
    *   Permission is hereby granted, free of charge, to any person obtaining a copy
    *   of this software and associated documentation files (the "Software"), to deal
    *   in the Software without restriction, including without limitation the rights
    *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    *   copies of the Software, and to permit persons to whom the Software is
    *   furnished to do so, subject to the following conditions:
    *
    *   The above copyright notice and this permission notice shall be included in all
    *   copies or substantial portions of the Software.
    *
    *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    *   SOFTWARE.
    *
    *************************/


    public interface FakePlayer {
     
       public void spawnFakePlayer(Player player, Location location, String displayName);

    }

    Example Main

    Code (Java):
    import org.bukkit.Bukkit;
    import org.bukkit.plugin.java.JavaPlugin;

    import wa.was.fakeplayer.Main;
    import wa.was.fakeplayer.events.OnJoin;
    import wa.was.fakeplayer.nms.FakePlayer;
    import wa.was.fakeplayer.nms.FakePlayer_v1_11_R1;
    import wa.was.fakeplayer.utils.ConsoleColor;

    /*************************
    *
    * Copyright (c) 2017 Jordan Thompson (WASasquatch)
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to deal
    * in the Software without restriction, including without limitation the rights
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in
    * all copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    * SOFTWARE.
    *
    *************************/


    public class Main extends JavaPlugin {

       private static FakePlayer fakePlayer;
       private static Main instance;

       @Override
       public void onEnable() {
         instance = this;
         determineFakePlayerInstance();
         getServer().getPluginManager().registerEvents(new OnJoin(), this);
       }

       public void determineFakePlayerInstance() {

         String version = "";
         try {
           version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
         } catch (ArrayIndexOutOfBoundsException whatVersionAreYouUsingException) {
           getLogger().severe("Could not determine server version!" + ConsoleColor.RED + ConsoleColor.BOLD
               + " Disabling!" + ConsoleColor.RESET);
           getServer().getPluginManager().disablePlugin(this);
         }
         getLogger().info("Your server is running version " + version);

         switch (version) {
           case "v1_11_R1":
             fakePlayer = new FakePlayer_v1_11_R1();
             break;
           default:
             getLogger().severe("Could not determine server version!" + ConsoleColor.RED + ConsoleColor.BOLD
                 + " Disabling!" + ConsoleColor.RESET);
             getServer().getPluginManager().disablePlugin(this);
             break;
         }

       }

       public static FakePlayer getFakePlayer() {
         return fakePlayer;
       }
     
       public static Main getInstance() {
         return instance;
       }

    }
    Example Usage (Create mock player on join. Just example)
    Code (Java):
      private FakePlayer fakePlayer;

       public OnJoin() {
         fakePlayer = Main.getFakePlayer();
       }

       @EventHandler
       public void onJoin(PlayerJoinEvent e) {
         final Player player = e.getPlayer();
         new BukkitRunnable() {
           @Override
           public void run() {
             if (player != null && player.isOnline()) {
               fakePlayer.spawnFakePlayer(player, player.getLocation().add(1.0, 0, 1.0), player.getDisplayName());
             }
           }
         }.runTaskLater(Main.getInstance(), 3);
       }
     
    Bonus that ConsoleColor.class I am using
    Code (Java):
    /*************************
     *
     *   Copyright (c) 2017 Jordan Thompson (WASasquatch)
     *  
     *   Permission is hereby granted, free of charge, to any person obtaining a copy
     *   of this software and associated documentation files (the "Software"), to deal
     *   in the Software without restriction, including without limitation the rights
     *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     *   copies of the Software, and to permit persons to whom the Software is
     *   furnished to do so, subject to the following conditions:
     *  
     *   The above copyright notice and this permission notice shall be included in all
     *   copies or substantial portions of the Software.
     *  
     *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     *   SOFTWARE.
     *  
     *************************/


    public class ConsoleColor {
       
       public static final String RESET = "\u001B[0m";
       public static final String BOLD = "\u001B[1m";
       public static final String ITALIC = "\u001B[3m";
       public static final String UNDERLINE = "\u001B[4m";
       public static final String NORMAL = "\u001B[22m";
       public static final String BLACK = "\u001B[30m";
       public static final String RED = "\u001B[31m";
       public static final String GREEN = "\u001B[32m";
       public static final String YELLOW = "\u001B[33m";
       public static final String BLUE = "\u001B[34m";
       public static final String PURPLE = "\u001B[35m";
       public static final String CYAN = "\u001B[36m";
       public static final String WHITE = "\u001B[37m";
       
       public static final String BLACK_BACKGROUND = "\u001B[40m";
       public static final String RED_BACKGROUND = "\u001B[41m";
       public static final String GREEN_BACKGROUND = "\u001B[42m";
       public static final String YELLOW_BACKGROUND = "\u001B[43m";
       public static final String BLUE_BACKGROUND = "\u001B[44m";
       public static final String PURPLE_BACKGROUND = "\u001B[45m";
       public static final String CYAN_BACKGROUND = "\u001B[46m";
       public static final String WHITE_BACKGROUND = "\u001B[47m";

    }
     
    #16 WAS, May 1, 2017
    Last edited: May 1, 2017
    • Like Like x 2
  16. With that you can detect right clicks and so on?
     
  17. WAS

    WAS

    I'm sorry, I don't quite understand. You mean right clicking the fake player to trigger an event? If so, yes, that should work. It should be an instance of a entity in the world (I believe).
     
  18. I mean the fakePlayer exists because with packets its only client sided (The server dont know if there is a FakePlayer) so dont fire evetns
     
  19. WAS

    WAS

    Oh I see. I'd imagine you just bind the entity location with a invisible entity of your choosing (with no AI, and probably representing the correct size. A armorstand probably be best).