1.9+ Custom WASD Entity Riding (Help)

Discussion in 'Spigot Plugin Development' started by Etheus, Jun 12, 2017.

Thread Status:
Not open for further replies.
  1. Hi there, today I would like to learn about a more advanced (at least it seems that way to me) subject.

    Custom WASD Entity Riding. 3D models. Vectors. Yaw. Pitch. Armorstand modifications. I'm not sure how to do this or where to start.

    My goal is to make flyable or on-ground vehicles. A good example of this would be RideMyCraft.
    https://www.spigotmc.org/resources/ridemycraft.9016/

    I've seen a more OOP-based system and I've also seen another system where vehicles extend a WASDEntity interface with goForward goBackward types of methods and such. I'm still wondering: What is the best way to make custom armorstand/entity vehicles?

    I've stated that this is 1.9+, but if you need a specific version since NMS changes, 1.9.4 would do fine. I also stated this is a help thread rather than a tutorial, so people don't get confused.

    If anyone has good experience with this, I would appreciate it if you shared some of your ideas, links, or code with me. Just looking for some solid information for a system I would like to implement implement. I might make a tutorial as well, because I bet other people have the same question.

    More clarification:
    - Vehicles should have a WASD controller. I'm thinking using ProtocolLib and listening for steering?
    - Vehicles are most likely going to be armor stands; then, the item on their head is made a 3D model.

    TLDR; How can I make a WASD vehicle system?

    Thank you in advance,
    AthenaDev
     
  2. Hi :)

    WASD controls can be done with just NMS, no protocollib or packets required. Unfortunately the fields you need to read do change with every version. Fortunately I have a collection of all the field names since 1.9 if you want:

    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) {
                                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;
                }
    That's obviously a little ugly, but gets the job done. You could also not use reflection if you don't care about version independence, it'd be cleaner.

    I also have a lib you could use, if you'd like.

    The forward field will be 1 or -1 depending on if W or S are pressed, strafing shows A or D. I also included jump so you can detect spacebar presses while riding a vehicle.

    I'll just throw this out there that if you're using my plugin already you could just use it to set up vehicles rather than custom-coding :)

    My broomsticks (and cars, from the war/GTA configs) work just as you describe- armor stands with items mounted on their heads, apply velocity every tick, WASD can be used to control that velocity.
     
    • Like Like x 1
  3. Ohh, that makes sense! Are the 1.9 fields different?
    I would love to haha, your plugins are great but I would rather setup my own custom system for this as it's good practice and if I want to modify anything to my liking, it will go better.
    I would be happy to take a look at it, mind linking me to it?
     
    • Useful Useful x 1
  4. The last case is 1.9 - basically my code just tries the latest version, if that fails it tries the next oldest, and so on. Hacky, but works.

    Code (Text):

                                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");
    Lib is here:

    https://github.com/elBukkit/MagicPlugin/tree/master/CompatibilityLib

    Not super user friendly, but you can grab it and shade it in with Maven (make sure to shade it if you use it, please! Or if you're sure Magic will be present you could also just mark it as provided)

    Then you can just call CompatibilityUtils.getForwardMovement to get W/S direction.
     
  5. Alright - so I think I have all the NMS and OOP planned out, but how can you change the location of the armor stand easily? That confuses me quite a bit.
     
  6. Nice, what about flying?
     
  7. I use setVelocity to move it around. I've tried teleporting but it doesn't feel as smooth to me, may be subjective.

    Flying is actually easier than staying on the ground when using velocity :)

    In my plugin, both work the same way- the vehicles that have to stay on ground just do a ground check before applying velocity, if they're on the ground then velocity is restricted by removing the y-component.

    This could be improved, though, on my TODO list is making it so you can drive over 1-block-high bumps, for instance.
     
  8. Ohh yeah so you can easily set horizontal/vertical velocity that way. Thank you!
     
  9. Create a custom entity and override the g(float,float) method which handles entity movement. Check if theres a passenger on the entity, and set the velocity of the passenger to the entity
     
Thread Status:
Not open for further replies.