1.8.8 Armor stand smooth animation

Discussion in 'Spigot Plugin Development' started by mopmop, Jun 30, 2021.

  1. Hey guys, im trying to do a armor stand animation and the animation is so sad.

    Current animation :


    Code (Text):
                Location loc = animHologram.getLocation();
                EntityArmorStand nmsArmor = ((CraftArmorStand) animHologram).getHandle();

                if (up) {
                    if (rotate >= 40) {
                        this.up = false;
                    }

                    loc.add(0.0, 0.01, 0.0);

                    if (rotate > 35) {
                        loc.setYaw((loc.getYaw() + 3));
                    } else if (this.rotate > 30) {
                        loc.setYaw((loc.getYaw() + 6));
                    } else {
                        loc.setYaw((loc.getYaw() + 12));
                    }
                    ((CraftArmorStand) animHologram).getHandle().setLocation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
                    Bukkit.getOnlinePlayers().forEach(player -> PacketUtils.sendPacket(player, new PacketPlayOutEntityTeleport(nmsArmor)));
                    this.rotate++;
                } else {
                    if (rotate <= 0) {
                        up = true;
                    }

                    loc.subtract(0.0, 0.01, 0.0);

                    if (rotate > 10) {
                        loc.setYaw((loc.getYaw() + -12));
                    } else if (rotate > 5) {
                        loc.setYaw((loc.getYaw() + -6));
                    } else {
                        loc.setYaw((loc.getYaw() + -3));
                    }
                    ((CraftArmorStand) animHologram).getHandle().setLocation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
                    Bukkit.getOnlinePlayers().forEach(player -> PacketUtils.sendPacket(player, new PacketPlayOutEntityTeleport(nmsArmor)));
                    this.rotate--;
                }
            }
     
     
  2. I don't know if it's the problem but don't forget to set loc after you add/subtract (i.e.: loc = loc.add(0,0.01,0);/loc = loc.subtract(0,0.01,0); )
    If not, then try to increase the interval of changing and see if it works (maybe the game doesn't have enough time to display the change and gets confused).
     

  3. It works with a bigger gap but I absolutely need 0.01
     
  4. Not a bigger gap, a bigger interval between changing the locations (let's say if you change it every 1 tick make it change after 2-5 ticks and see if it still does that)
     
  5. I already tried and is sad
     
  6. You'll have to work with velocity, rather then exact teleportation. The client will end up interpolating teleportation creating that look you see.
     
  7. Does it still do the weird jump if you add 0.02-0.05 instead of 0.01?
     
  8. Ok but just with setVelocity() ?
     
  9. In 0.05 the animation is smooth
     
  10. So yeah, the server can't keep up with the teleports and does the awkward jump instead...
    I suggest you do as @Blutkrone and use velocity instead of teleporting it.
    Either that or you'll have to use a value bigger than 0.01.
     
  11. How often is your runnable?
     
  12. 1 ticks
     
  13. result on video - https://disk.yandex.ru/i/UJMZMhSnD4XY0w

    Okay. Once upon a time I tried to make a rotation like on a hypixel, but for some reason I gave it up.
    Then I managed to make the rotation to the right (it was not smooth enough), I used teleportation and rotation of the head in packets.
    Today I wondered how to make it even smoother, and I found an answer on the forum - PacketPlayOutEntity.*
    At the moment I am using PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook to combine rotation and shear in Y in one package
    As you can see, my previous formulas are not suitable for this package.
    As soon as I find the time I will try to leave the code ready.

    Sorry for the bad English I use a translator
     
    • Like Like x 2
  14. thank you for your answer I will test this solution now
     
  15. I have test and its not smooth. You use the 1.8 or higher ?
     
  16. Yes its 1.8.8. I finished it.

    Comparison video: https://disk.yandex.ru/i/wbqdalVzrDwfxw
    On the left is the code using PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook, on the right
    PacketPlayOutEntityTeleport)
    The quality of the video is not good enough to understand the difference, but it is colossal

    While I was doing this, I realized that this is not quite what you needed initially
    But you would be hit by the fact that the rotation at PacketPlayOutEntityTeleport jerks and this is not what you want

    My runnuble
    Code (Java):

            new BukkitRunnable() {
               
                PacketStand ps = rb.getPacketStand(); //My custom stand
                int currentTick = 0; //counter
                int maxTick = 60; //cycle time (fall and rise)
                double length = 0.5; // 1/2 of Y cycle
                double a = 2 * length / Math.pow(maxTick/2, 2); //Calculation of uniform acceleration
                boolean isFall = true;
               
                @Override
                public void run() {
                    currentTick++;
                    int tickValue = currentTick < maxTick/2 ? currentTick : maxTick - currentTick; //value for animation
                    double currentA = a * tickValue; //speed at a specific time for Y
                    double currentA2 = (a + 0.5) * tickValue; ////speed at a specific time for Yaw
                    ps.setMove(ps.locX, (isFall ? ps.locY - currentA : ps.locY + currentA), ps.locZ, (isFall ? ps.yaw - currentA2 : ps.yaw + currentA2), 0); //Move setter
                    if (currentTick == maxTick) { //cycle change
                        currentTick = 0;
                        isFall = !isFall;
                    }
                }
            }.runTaskTimer(Main.main, 0, 1);
     

    Here is the move method and methods for converting values to byte as it is done in NMS for protocol
    Code (Java):
        public void setMove(double x, double y, double z, double yaw, double pitch) {
            PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook p = new PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook(this.getId(), xLoc(x), yLoc(y), zLoc(z), yaw(yaw), pitch(pitch), false);
            Util.sendPacket(p);
            this.locY = y;
            this.yaw = (float) yaw;
        }
       
        private byte xLoc(double xTo) {
            return (byte)(MathHelper.floor(xTo * 32.0D) - MathHelper.floor(this.locX * 32.0D));
        }
       
        private byte yLoc(double yTo) {
            return (byte)(MathHelper.floor(yTo * 32.0D) - MathHelper.floor(this.locY * 32.0D));
        }
       
        private byte zLoc(double zTo) {
            return (byte)(MathHelper.floor(zTo * 32.0D) - MathHelper.floor(this.locZ * 32.0D));
        }
       
        private byte yaw(double yawTo) {
            return (byte)MathHelper.d(yawTo * 256.0F / 360.0F);
        }

        private byte pitch(double pitchTo) {
            return (byte)MathHelper.d(pitchTo * 256.0F / 360.0F);
        }
    I change Y and Yaw since it counts in my Runnuble


    Maybe I forgot to say something else. But hope this helps you
     
    • Like Like x 1
    • Useful Useful x 1
  17. Ok i go test this
     
  18. @NoooobKa you using tha packet for spawn the armorstand entity ?
     
  19. Sure
    Code (Text):


    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
    import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.PlayerJoinEvent;
    import org.bukkit.inventory.ItemStack;

    import main.Main;
    import net.minecraft.server.v1_8_R3.EntityArmorStand;
    import net.minecraft.server.v1_8_R3.MathHelper;
    import net.minecraft.server.v1_8_R3.PacketPlayOutEntity;
    import net.minecraft.server.v1_8_R3.PacketPlayOutEntityEquipment;
    import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata;
    import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport;
    import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving;
    import net.minecraft.server.v1_8_R3.Vector3f;
    import utils.Util;

    public class PacketStand extends EntityArmorStand implements Listener{
     
        public PacketStand(net.minecraft.server.v1_8_R3.World world, Location standLocation) {
            super(world);
            this.setGravity(false);
            setInvisible(true);
            setLocation(standLocation.getX(), standLocation.getY(), standLocation.getZ(), 0, 0);
            spawnForAll();
            Bukkit.getPluginManager().registerEvents(this, Main.main);
        }
     
        private void spawn(Player p) {
            PacketPlayOutSpawnEntityLiving spawn = new PacketPlayOutSpawnEntityLiving(this);
            ((CraftPlayer)p).getHandle().playerConnection.sendPacket(spawn);
        }
     
        private void spawnForAll() {
            PacketPlayOutSpawnEntityLiving spawn = new PacketPlayOutSpawnEntityLiving(this);
            Util.sendPacket(spawn);
        }
     
        @Override
        public void setLocation(double d0, double d1, double d2, float f, float f1) {
            super.setLocation(d0, d1, d2, f, f1);
            PacketPlayOutEntityTeleport teltportPacket = new PacketPlayOutEntityTeleport(this);
            Util.sendPacket(teltportPacket);
        }
     
        @Override
        public void setHeadPose(final Vector3f vector3f) {
            super.setHeadPose(vector3f);
            PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(this.getId(), this.getDataWatcher(),true);
            Util.sendPacket(meta);
        }
     
        public void setMove(double x, double y, double z, double yaw, double pitch) {
            PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook p = new PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook(this.getId(), xLoc(x), yLoc(y), zLoc(z), yaw(yaw), pitch(pitch), false);
            Util.sendPacket(p);
            this.locY = y;
            this.yaw = (float) yaw;
        }
     
        public void setEquipment(EnumEquipmentSlot es, ItemStack is) {
            setEquipment(es.getSlotId(), CraftItemStack.asNMSCopy(is));
            PacketPlayOutEntityEquipment equi = new PacketPlayOutEntityEquipment(this.getId(), es.getSlotId(), CraftItemStack.asNMSCopy(is));
            Util.sendPacket(equi);
        }
     
        @Override
        public void setEquipment(int i, net.minecraft.server.v1_8_R3.ItemStack is) {
            super.setEquipment(i, is);
            PacketPlayOutEntityEquipment equi = new PacketPlayOutEntityEquipment(this.getId(), i, is);
            Util.sendPacket(equi);
        }
     
        @Override
        public void setInvisible(boolean flag) {
            super.setInvisible(flag);
            PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(this.getId(), this.getDataWatcher(),true);
            Util.sendPacket(meta);
        }
     
        public void updateEquipment(Player p) {
            for (int i = 0; i < getEquipment().length; i++) {
                net.minecraft.server.v1_8_R3.ItemStack is = getEquipment(i);
                if (is == null)continue;
                PacketPlayOutEntityEquipment equi = new PacketPlayOutEntityEquipment(this.getId(), i, is);
                Util.sendPacket(equi);
            }
        }
     
        private byte xLoc(double xTo) {
            return (byte)(MathHelper.floor(xTo * 32.0D) - MathHelper.floor(this.locX * 32.0D));
        }
     
        private byte yLoc(double yTo) {
            return (byte)(MathHelper.floor(yTo * 32.0D) - MathHelper.floor(this.locY * 32.0D));
        }
     
        private byte zLoc(double zTo) {
            return (byte)(MathHelper.floor(zTo * 32.0D) - MathHelper.floor(this.locZ * 32.0D));
        }
     
        private byte yaw(double yawTo) {
            return (byte)MathHelper.d(yawTo * 256.0F / 360.0F);
        }

        private byte pitch(double pitchTo) {
            return (byte)MathHelper.d(pitchTo * 256.0F / 360.0F);
        }
     
        public Location getLocation() {
            return new Location(this.getWorld().getWorld(), locX, locY, locZ);
        }
     
        @EventHandler(priority = EventPriority.HIGHEST)
        public void pje(PlayerJoinEvent e) {
            spawn(e.getPlayer());
            updateEquipment(e.getPlayer());
        }
     
     
    }
     
     
  20. You have no problem with me if I do that when I walk away he despawn