1.17.x NPC following a invisible zombie can't be hit sometimes

Discussion in 'Spigot Plugin Development' started by tomekcz, Jun 20, 2021.

  1. Basically i've made it so a npc follows a invisible zombie, but the problem is that if you hit zombie it takes proper knockback but if you hit the npc it does nothing becouse its just programmed to follow the zombie
    Is there a way to fix it or make it so it always hits the zombie?
    Code (Java):
    package tomekcz.skyblock.npc;

    import com.mojang.authlib.GameProfile;
    import net.minecraft.network.protocol.game.*;
    import net.minecraft.server.MinecraftServer;
    import net.minecraft.server.level.EntityPlayer;
    import net.minecraft.server.level.WorldServer;
    import net.minecraft.world.entity.monster.EntityZombie;
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.World;
    import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
    import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
    import org.bukkit.scheduler.BukkitRunnable;
    import tomekcz.skyblock.Main;

    import java.util.UUID;

    import static tomekcz.skyblock.npc.PacketManager.broadcastPacket;
    import static tomekcz.skyblock.npc.PacketManager.broadcastPackets;

    public abstract class PathfindingNpc extends EntityZombie {
        //b is for walking at a block
        EntityPlayer npc;
        Double lastX, lastY, lastZ;
        float lastHealth;
        World world;

        public PathfindingNpc(Location location, String name) {
            super(((CraftWorld)location.getWorld()).getHandle());

            //Zombie
            this.setLocation(location.getX(),location.getY(),location.getZ(),location.getYaw(),location.getPitch());
            this.world = location.getWorld();
            //this.setInvisible(true);

            //NPC
            MinecraftServer minecraftServer = ((CraftServer) Bukkit.getServer()).getServer();
            WorldServer worldServer = ((CraftWorld) Bukkit.getWorld(location.getWorld().getName())).getHandle();
            GameProfile gameProfile = new GameProfile(UUID.randomUUID(), name);
            this.npc = new EntityPlayer(minecraftServer, worldServer, gameProfile);
            npc.setLocation(location.getX(),location.getY(),location.getZ(),location.getYaw(),location.getPitch());

            broadcastPacket(
                    new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a, npc)
            );
            broadcastPackets(
                    new PacketPlayOutNamedEntitySpawn(npc),
                    new PacketPlayOutEntityHeadRotation(npc,(byte)(aY*256/360)),
                    new PacketPlayOutEntity.PacketPlayOutEntityLook(npc.getId(),(byte)(aY*256/360),(byte)(aZ*256/360),true)
            );

            lastX = locX();
            lastY = locY();
            lastZ = locZ();
            lastHealth = getHealth();

            new BukkitRunnable() {
                @Override
                public void run() {
                    if(getHealth() == 0) {
                        broadcastPackets(
                                new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.e, npc),
                                new PacketPlayOutEntityDestroy(npc.getId())
                        );
                        cancel();
                    }
                    broadcastPackets(
                            new PacketPlayOutEntityHeadRotation(npc,(byte)(aY*256/360)),
                            new PacketPlayOutEntity.PacketPlayOutEntityLook(npc.getId(),(byte)(aY*256/360),(byte)(aZ*256/360),true)
                    );

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

                    if(x != lastX || y != lastY || z != lastZ)
                        move(x-lastX,y-lastY,z-lastZ);
                    lastX = x;
                    lastY = y;
                    lastZ = z;
                    if(lastHealth > getHealth()) {
                        lastHealth = getHealth();
                        broadcastPacket(new PacketPlayOutAnimation(npc,1));
                    }
                }
            }.runTaskTimer(Main.getPlugin(Main.class),0,0);
        }

        protected void move(double x, double y, double z) {
            broadcastPacket(new PacketPlayOutEntity.PacketPlayOutRelEntityMove(npc.getId(),(short)(x*4096),(short)(y*4096),(short)(z*4096),true));
        }

        @Override
        public void setOnFire(int i) {
            return;
        }
    }
     
     
  2. There is a better way to do that, you can 'disguise' the zombie into npc.
    By sending a destroy packet of the zombie and spawning your npc with the same zombie id.
     
    • Like Like x 1
  3. Thank you very much
    (Apparently the site dosen't let me change it to fixed)
    upload_2021-6-24_0-4-10.png
    Code (Java):
    package tomekcz.skyblock.npc;

    import com.mojang.authlib.GameProfile;
    import net.minecraft.network.protocol.game.*;
    import net.minecraft.server.MinecraftServer;
    import net.minecraft.server.level.EntityPlayer;
    import net.minecraft.server.level.WorldServer;
    import net.minecraft.world.entity.monster.EntityZombie;
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.World;
    import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
    import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
    import org.bukkit.scheduler.BukkitRunnable;
    import tomekcz.skyblock.Main;

    import java.util.UUID;

    import static tomekcz.skyblock.npc.PacketManager.broadcastPacket;
    import static tomekcz.skyblock.npc.PacketManager.broadcastPackets;

    public abstract class PathfindingNpc extends EntityZombie {
        EntityPlayer npc;
        Double lastX, lastY, lastZ;
        float lastHealth;
        World world;

        public PathfindingNpc(Location location, String name) {
            super(((CraftWorld)location.getWorld()).getHandle());

            //Zombie
            this.setLocation(location.getX(),location.getY(),location.getZ(),location.getYaw(),location.getPitch());
            this.world = location.getWorld();

            MinecraftServer minecraftServer = ((CraftServer) Bukkit.getServer()).getServer();
            WorldServer worldServer = ((CraftWorld) Bukkit.getWorld(location.getWorld().getName())).getHandle();
            GameProfile gameProfile = new GameProfile(UUID.randomUUID(), name);
            npc = new EntityPlayer(minecraftServer, worldServer, gameProfile);

            new BukkitRunnable() {
                @Override
                public void run() {
                    broadcastPacket(
                            new PacketPlayOutEntityDestroy(getId())
                    );

                    npc.setLocation(locX(),locY(),locZ(),aY,aZ);
                    npc.e(getId());


                    broadcastPackets(
                            new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a, npc),
                            new PacketPlayOutNamedEntitySpawn(npc),
                            new PacketPlayOutEntityHeadRotation(npc,(byte)(aZ*256/360)),
                            new PacketPlayOutEntity.PacketPlayOutEntityLook(npc.getId(),(byte)(aY*256/360),(byte)(aZ*256/360),true)
                    );
                }
            }.runTaskLater(Main.getPlugin(Main.class),0);

        }


        @Override
        public void setOnFire(int i) {
            return;
        }


    }