1.16.5 Walk NPC

Discussion in 'Spigot Plugin Development' started by gamerpig, Apr 10, 2021.

  1. Hello spigot community!

    So lately i've asked multiple nms / entityplayer questions on the forums and now i only have one more problem how do you make an npc walk. Now i've already tried it and it works but not how i want it too.

    Code (Java):
    PacketPlayOutEntity movepacket = new PacketPlayOutEntity.PacketPlayOutRelEntityMove(martinnpc.getId(), (short) (-10.500 * 4096), (short) (67.93750 * 1), (short) (43.500 * 4096), true);
                    ((CraftPlayer) p).getHandle().playerConnection.sendPacket(movepacket);
    now this is my code for making an npc walk but it has 2 problems. first off i have no idea how to tell it to move a specific amount of blocks and second of all it walks SUPER FAST to the point where you dont see the walk animation. just for future replies i've already looked at this forum : https://www.spigotmc.org/threads/how-to-create-and-modify-npcs.400753/

    hope someone can help!
    gamerpig
     
  2. I'd suggest you teleport the npc a fraction of a block every tick with a repeating runnable. This should display the walk animation if I'm not mistaking.
     
  3. so your saying to use PacketPlayOutRelEntityTeleport? I understand everything else but i dont really know what you mean by teleporting the npc.
     
  4. I just meant Enity#teleport() but I think it should work how you want to do it.
     
  5. Try with PathFinder
     
  6. ok ill try
     
  7. whats pathfinder?
     
  8. It will not work beacuse NPC's doesn't have pathfinder. You have to make a custom entity that has the pathfinding and teleport the NPC to it every tick.
    Edit: the most important function is update.
    Code (Text):


    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    import com.mojang.authlib.GameProfile;
    import com.mojang.authlib.properties.Property;
    import net.minecraft.server.v1_16_R3.*;
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
    import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
    import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.Plugin;
    import org.bukkit.scheduler.BukkitRunnable;

    import javax.net.ssl.HttpsURLConnection;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.UUID;

    public class NPC {

        private EntityPlayer npc=null;
        private String name;
        private String skin;
        private double prevx;
        private double prevy;
        private double prevz;
        private Location loc;
        private CustomMob mob = null;
        public static Plugin plugin;

        public NPC(Location loc, String name, String skinUsername) {
            this.name = name;
            this.loc = loc;

            skin = skinUsername;
            createNPC();

            prevx = mob.locX();
            prevy = mob.locY();
            prevz = mob.locZ();

            for (Player p : Bukkit.getOnlinePlayers()) {
                addNPCPacket(p);
            }
            update();
            new BukkitRunnable(){
                @Override
                public void run(){
                    update();

                    double x = mob.locX();
                    double y = mob.locY();
                    double z = mob.locZ();

                    if ( x!=prevx || y!=prevy || z!=prevz) {
                        double getx = x - prevx;
                        double gety = y - prevy;
                        double getz = z - prevz;
                        moveNPC(getx, gety, getz);
                        prevx=x;
                        prevy=y;
                        prevz=z;
                    }

                }
            }.runTaskTimer(plugin, 0L, 1L);
        }

        public void createNPC() {
            mob = new CustomMob(loc);
            WorldServer world = ((CraftWorld) loc.getWorld()).getHandle(); // Creates and NMS world
            world.addEntity(mob);
            MinecraftServer nmsServer = ((CraftServer) Bukkit.getServer()).getServer();
            WorldServer nmsWorld = ((CraftWorld)Bukkit.getWorld("world")).getHandle(); // Change "world" to the world the NPC should be spawned in.
            GameProfile gameProfile = new GameProfile(UUID.randomUUID(), name); // Change "playername" to the name the NPC should have, max 16 characters.
            String[] name = getSkin(skin);
            gameProfile.getProperties().put("textures", new Property("textures", name[0], name[1]));
            npc = new EntityPlayer(nmsServer, nmsWorld, gameProfile, new PlayerInteractManager(nmsWorld)); // This will be the EntityPlayer (NPC) we send with the sendNPCPacket method.
            npc.setLocation(mob.locX(), mob.locY(), mob.locZ(), 0, 0);


        }

        public void addNPCPacket(Player player) {
            if (npc == null) return;
            PlayerConnection connection = ((CraftPlayer)player).getHandle().playerConnection;
            connection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, npc)); // "Adds the player data for the client to use when spawning a player" - https://wiki.vg/Protocol#Spawn_Player
            connection.sendPacket(new PacketPlayOutNamedEntitySpawn(npc)); // Spawns the NPC for the player client.
            connection.sendPacket(new PacketPlayOutEntityHeadRotation(npc, (byte) (npc.yaw * 256 / 360))); // Correct head rotation when spawned in player look direction.
        }

        public void removeNPC() {
            for (Player p : Bukkit.getOnlinePlayers()) {
                removeNPCPacket(p);
            }
        }

        public void removeNPCPacket(Player player) {
            PlayerConnection connection = ((CraftPlayer)player).getHandle().playerConnection;
            connection.sendPacket(new PacketPlayOutEntityDestroy(npc.getId()));
        }

        private static String[] getSkin(String name ) {
            try {
                URL url = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
                InputStreamReader reader = new InputStreamReader(url.openStream());
                String uuid = new JsonParser().parse(reader).getAsJsonObject().get("id").getAsString();
                URL url2 = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid
                        + "?unsigned=false");
                InputStreamReader reader2 = new InputStreamReader(url2.openStream());
                JsonObject property = new JsonParser().parse(reader2).getAsJsonObject().get("properties").getAsJsonArray().get(0).getAsJsonObject();
                String texture = property.get("value").getAsString();
                String signature = property.get("signature").getAsString();
                return new String[] {texture, signature};
            }
            catch (Exception e) {
                e.printStackTrace();
                return new String[] {"ERROR", "ERROR"};
            }
        }

        public void update() {
            if (mob == null) return;
            for (Player p : Bukkit.getOnlinePlayers()) {
                PlayerConnection connection = ((CraftPlayer) p).getHandle().playerConnection;
                connection.sendPacket(new PacketPlayOutEntityHeadRotation(npc, (byte) (mob.lastYaw*256/360)));
                connection.sendPacket(new PacketPlayOutEntity.PacketPlayOutEntityLook(npc.getId(), (byte) (mob.lastYaw*256/360), (byte) (mob.lastPitch*256/360), true));
            }
        }

        public void moveNPC (double x, double y, double z) {
            for (Player p : Bukkit.getOnlinePlayers()) {
                PlayerConnection connection = ((CraftPlayer) p).getHandle().playerConnection;

                connection.sendPacket(new PacketPlayOutEntity.PacketPlayOutRelEntityMove(npc.getId(), (short)(x * 4096), (short)(y * 4096), (short)(z * 4096), true));
            }
        }

        public void takeDamage(float damage) {
            for (Player p : Bukkit.getOnlinePlayers()) {
                PlayerConnection connection = ((CraftPlayer) p).getHandle().playerConnection;

                connection.sendPacket(new PacketPlayOutAnimation(npc, 1));
            }
        }

        public EntityPlayer getEntityPlayer() {
            return npc;
        }
    }
     
     
  9. You can make your NPC a CraftPlayer object then CraftEntity
     
  10. how would you do this? would you use brackets and change it to (CraftPlayer) or would you
    Code (Text):
    CraftPlayer npcplayer = (CraftEntity) stuff
     
  11. I don't remember how but i know that you can :oops:
     
  12. Not sure if it still works, but I heard that setting the NPC's velocity by an extremely small amount such as 0.5 works.
     
  13. I tried this but unfortunately it didnt work but thanks for the reply!
     
  14. I didnt want to use pathfinder in the first place i want an npc to walk somewhere at a certain speed and specific location