Solved Velocity WASD controls

Discussion in 'Spigot Plugin Development' started by Qruet, Jun 15, 2018.

  1. Currently I'm slowing down a player's fall by altering their y velocity, however this prevents them from being able to navigate during their fall with W,A,S,D keys. I would like them to be able to navigate during their fall as if they were normally falling. So using vector direction (the direction they're looking at) shouldn't be used as a possible option for ways to allow the player to control their x and z position while falling. The player is slowly moving though if they hold down one of the controls, however velocity still returns 0 for both x or z. Here's what I've got so far that controls the player's fall velocity.

    Code (Text):
    public class ParachuteRemover extends BukkitRunnable {

        private ParachuteHolder holder;
        private Player player;

        public ParachuteRemover(ParachuteHolder holder) {
            this.holder = holder;
            this.player = holder.getParachuter();
        }

        @Override
        public void run() {
            if (player.getWorld().getHighestBlockAt(player.getLocation()).getY() + 10 >= player.getLocation().getY()) {
                holder.destroy(); //drops player
                cancel();
                return;
            }
            if (player.getVelocity().getY() < -0.3) {
                //Smoothly slows player down, preventing any jagged, unnatural falling movements
                for (double v = player.getVelocity().getY(); v < -0.25f; v+=0.01f) {
                    new D(v).runTaskLater(ParachuteFall.i, 1L);
                }

            }
        }

        private class D extends BukkitRunnable {

            private double v;

            public D(double v) {
                this.v = v;
            }

            @Override
            public void run() {
                //Attempt at increase player's x and z velocity.
                double x = player.getVelocity().getX();
                double z = player.getVelocity().getZ();

                Bukkit.broadcastMessage("X: " + x); //returns 0.0
                Bukkit.broadcastMessage("Z: " + z); //returns 0.0

                x += x < 0 ? -0.4 : (x > 0 ? 0.4 : 0);
                z += z < 0 ? -0.4 : (z > 0 ? 0.4 : 0);
                //----------------------------------------------
                player.setVelocity(player.getVelocity().setX(x * 10));
                player.setVelocity(player.getVelocity().setY(v)); //sets player's y velocity
                player.setVelocity(player.getVelocity().setZ(z * 10));
            }
        }
    }
     
     
  2. Maybe a better solution: Give them the levitation effect with an amplifier (strength) between 129 and 255. Opposite to what their name entails, the effect will cause players to slowly descend if the strength is between 129 and 255. Players will not lose control and will be able to navigate using their W/A/S/D keys. Using vectors to accomplish this will be rather tricky.

    The levitation effect with strength 129 will cause players to descend SUPER quick.
    Strength 255 will cause them to descend SUPER slowly.

    Try an effect amplifier between 250 and 254 and see if that is the effect you desire.

    One side note though:
    The levitation effect was only added in 1.9. If you're still one of those stupid people who stick to spigot 1.8, you gotta find a different solution.
     
    • Like Like x 1
    • Agree Agree x 1
    • Winner Winner x 1
    • Informative Informative x 1
  3. Slowing down a players' fall due to gravity is actually quite difficult mainly because movement due to gravity is purely handled by the client.
    There are ways to still control the gravity players are under using different methods, but none of them are perfectly seamless and well integrated for the client.
    Here are 2 workarounds that can work.

    1. Some time ago, SethBling (a Minecraft map building genius youtuber) built a bukkit plugin that changes the effects of gravity on entities. He made a video which you can watch here. He also made another video which was a bukkit plugin that slowed the pull of gravity when you had a lead attached to multiple chickens. You can watch that video here. I would recommend downloading these plugins here (titled 'blinggravity.jar' and 'blingparachute.jar') and then decompiling using this (web application) or this (desktop application).

    2. Have player ride and armorstand and descend that armorstand slowly. This is a pretty straightforward approach.

    3. Do what @JustDJplease recommended as it looks like that is the best method :p
     
    • Friendly Friendly x 1
  4. I'll definitely look into what SethBling did. I've tried the armorstand approach and that didn't seem to work. In fact the player couldn't move at all... perhaps with some NMS tweaks I could create a player controlled armorstand? Elevation may be worth something to try out, however although the server runs off of the latest spigot build (1.12.2), I do support 1.8 clients, therefore I'm not sure if there may be small conflicts there. Also, although it may still be the best option, I'm not a fan with using just potion effects since it kinda prevents the realism of the "air drag" effect.
     
    #4 Qruet, Jun 15, 2018
    Last edited: Jun 15, 2018
  5. When a player is riding an entity, packets for WASD input are sent. The values are stored in obfuscated fields in the nms entity object. You can use them for movement.
    This does however use NMS so it may not be the best solution for you.
     
    • Agree Agree x 1
  6. Do you know by chance what the names of these values are? I would like to know without having to test every value in the class :p
     
  7. In my 1.11 project I've used EntityLiving.bf for forward motion and EntityLiving.be for side motion. Lets just hope that 1.12 didn't change it.

    Edit: There's also a method called for entity steering (float, float) as parameters. You can override it if you figure out what it's called in the obfuscated code.
     
  8. They did change... here are the fields for 1.9 - 1.12

    Code (Text):
     try {
                    // 1.12
                    try {
                        if (!current) {
                            throw new Exception("Not 1.12");
                        }
                        class_Entity_jumpingField = class_EntityLiving.getDeclaredField("bd");
                        class_Entity_jumpingField.setAccessible(true);
                        class_Entity_moveStrafingField = class_EntityLiving.getDeclaredField("be");
                        class_Entity_moveForwardField = class_EntityLiving.getDeclaredField("bg");
                    } catch (Throwable not12) {
                        // 1.11
                        current = false;
                        try {
                            class_Entity_jumpingField = class_EntityLiving.getDeclaredField("bd");
                            class_Entity_jumpingField.setAccessible(true);
                            class_Entity_moveStrafingField = class_EntityLiving.getDeclaredField("be");
                            class_Entity_moveForwardField = class_EntityLiving.getDeclaredField("bf");
                        } catch (Throwable not11) {
                            // 1.10
                            try {
                                class_Entity_jumpingField = class_EntityLiving.getDeclaredField("be");
                                class_Entity_jumpingField.setAccessible(true);
                                class_Entity_moveStrafingField = class_EntityLiving.getDeclaredField("bf");
                                class_Entity_moveForwardField = class_EntityLiving.getDeclaredField("bg");
                            } catch (Throwable not10) {
                                // 1.9
                                class_Entity_jumpingField = class_EntityLiving.getDeclaredField("bc");
                                class_Entity_jumpingField.setAccessible(true);
                                class_Entity_moveStrafingField = class_EntityLiving.getDeclaredField("bd");
                                class_Entity_moveForwardField = class_EntityLiving.getDeclaredField("be");
                            }
                        }
                    }
                } catch (Throwable ex) {
                    Bukkit.getLogger().log(Level.WARNING, "An error occurred while registering entity movement accessors, vehicle control will not work", ex);
                    class_Entity_jumpingField = null;
                    class_Entity_moveStrafingField = null;
                    class_Entity_moveForwardField = null;
                }
     
    • Useful Useful x 1
  9. Was reading up on that exact thread. Strangely it's throwing NoSuchFieldException when using bd, be and bg in 1.12. I'll keep testing, perhaps I'm doing something stupid.
     
  10. Not quite sure what I'm doing wrong here? Here's my custom armor stand class.
    Code (Text):
    public class CustomArmorStand extends EntityArmorStand {

        public CustomArmorStand(World world, double d0, double d1, double d2) {
            super(world, d0, d1, d2);
        }

        public CustomArmorStand(World world) {

            super(world);
            super.setSmall(true);
            super.setInvulnerable(true);

        }

        public Field getStrafing() {
            try {
                return super.getClass().getDeclaredField("be");
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
                return null;
            }
        }

        public Field getForward() {
            try {
                return super.getClass().getDeclaredField("bg");
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
                return null;
            }
        }

     
    I'm spawning it in and riding it, but at the same time debugging by retrieving the class and calling the getStrafing() method and getForward() method, which returns a "NoSuchFieldException". Perhaps the armorstand doesn't have these fields for some reason, or named differently then perhaps a living entity?
     
  11. Have you looked at the source code? In 1.11 the fields were public and I didn't need reflection.
     
  12. The methods are defined in in Entity, not LivingEntity. Rather than super.getClass() maybe just do Entity.getDeclaredField.
     
  13. Both float values just return 0 while I tried to strafe or sprint forward while riding the armorstand.

    EDIT:
    Ah I was looking in EntityLiving (which never realized ArmorStands were considered living), but I'll try the entity class.
     
  14. Tried that. Both throw the same NoSuchFieldException.
    EDIT:
    Getting the declared field from EntityLiving doesn't throw an exception, however it just returns zero just as before.
     
    #14 Qruet, Jun 15, 2018
    Last edited: Jun 15, 2018
  15. Derp, I was wrong, it is EntityLiving ...

    Keep in mind that you need to call this on the player, not on the armorstand mount. From your code it looks like you're probably doing the latter.
     
  16. I get those values from the player's class...? That probably would make more sense, lel.
    EDIT:
    Haha my bad, yeah I wasn't checking for it in the player class. I am successfully retrieving values now. What's the best way to use these values now? I'm not sure if I should just play around with just changing the x and z velocity of the armor stand based of the returned values or try replicating how with the pig handles such values? I'll try with values for now, but I'm not sure if for some reason the other approach would be better.
     
    #16 Qruet, Jun 15, 2018
    Last edited: Jun 15, 2018
  17. I think that's up to you, personally I use them for vehicles (flying and on-ground), by modifying a velocity vector that I apply to the vehicle each tick.
     
  18. How did you go about determining the appropriate direction with keeping in mind both when the player is going forward/backward or strafing left/right and the direction they're looking at? It doesn't seem something that complicated but I'm having trouble getting the formula right without going in the wrong direction when I go forward.
     
  19. I basically just start with the player's look direction vector. The A and D keys will translate that vector to the left/right (I think I just add in a vector that's rotated 90 degrees left or right), W and S increase or decrease the speed along the direction. I also have an option to linearly interpolate between the current direction and target direction so changes aren't immediately (including when rotating the look direction), which gives it more of a "steering" sort of feel, and opens up possibilities for differentiating vehicles by "handling" quality as well as speed/acceleration.

    This is all pretty specific to vehicles though, not sure how much it applies to your problem- especially since my reply is so late :)