Resource [TUTORIAL] 1.9 Custom NMS Entities, Part 1: Important Entity Methods, and Intro to PathfinderGoals

Discussion in 'Spigot Plugin Development' started by bigans01, May 1, 2016.

  1. I'm sorry if I sounded rude, it wasn't my intention. I was just trying to say that maybe sometimes it's better to test things yourself instead of copy and paste some code found online. For instance, try to look at the decompiled nms classes and understand how things works. At the beginning it can be a bit tricky but after you figure it out I can assure you that you will be pleased. At least, that's my experience concering nms.
    BTW, I'm not accusing you, just giving you some piece of advice <3

    PS: I'm going to test the pathfinders on the slime. I'll let you know if it works for me.
    • Like Like x 1
  2. Here's my solution for the slime (tested with spigot v1_9_R1):
    Code (Text):
    public class PathfinderGoalSlimeFollowOwner extends PathfinderGoal {

        private EntityInsentient entity;
        private double speed;
        private float distanceSquared;

        private static Method controllerRotate;
        // init reflection method for the controller (ref to the "e" method)
        static {
            try {
                controllerRotate = EntitySlime.class.getDeclaredClasses()[0].getDeclaredMethod("a", float.class, boolean.class);
            } catch (Exception e) {

        public PathfinderGoalSlimeFollowOwner(EntityInsentient entity, double speed, float distance) {
            this.entity = entity;
            this.speed = speed;
            this.distanceSquared = distance * distance;

        public boolean a() {
            Entity owner = ((EntityOwnable)this.entity).getOwner();

            // don't move if the owner is dead or the slime is close to him
            return (owner != null && owner.isAlive() && this.entity.h(owner) > (double)distanceSquared);

        public void d() {
            // clear the PathEntity

        public void e() {
            Entity owner = ((EntityOwnable)this.entity).getOwner();

            // rotate the slime towards the owner
            this.entity.a(owner, 10.0F, 10.0F);

            // have to use reflection to get the ControllerMoveSlime class cuz it's static :(
            try {
                // method to make the slime rotated towards the player while jumping
                // if the boolean is true the cooldown between every jump is 1/3 of the default one
                controllerRotate.invoke(this.entity.getControllerMove(), this.entity.yaw, true);
            } catch (Exception e) {

            // make the slime move towards the owner
            this.entity.getNavigation().a(owner, this.speed);
    TBH I would have used encapsulation making this class extend the default pathfinder class for the other pets and overriding just the "e" method... but I won't spoonfeed you and do all the work for you :p
  3. I appreciate the work you just put forth for helping my out, however i do not expect to be spoon fed. Thanks for help!
    • Like Like x 1
  4. Yeah, i didn't think you were trying to be rude xD And I have decompiled spigot before to look. But I just wanted to see how this whole thing works and make a understanding of what is working before trying to accomplish something I have no knowledge about and trying to fix it when i have no idea whats going on. (If that makes sense)
  5. Does anyone have a solid list of sounds used in the SoundEffects.* enum? Or how to obtain the actual sound names?
  6. MiniDigger


    • Useful Useful x 1
  7. Hey guys,

    Thanks for keeping this thread civil and on topic so far. I just wanted to drop a note and say im still working with NMS code in my spare time, (although i took a slight break for a few months) and will soon begin doing some additional testing.

    In about 2 weeks, i plan to open up a Spigot server that serves as a testbed for a mod im working on (which uses all the features i have mentioned in this tutorial). I already have the server spawn, most of the plugins i need, and permissions set up. It is a 24/7 server where others can play/test at any time, and its where ive been doing my dev work (including this NMS tutorial) for the past year.

    Out of respect for the forums rules, i wont advertise the server here when the time comes, but will simply ask that you PM me or give this post a rating. I will also try to send out a mass message to others who have rated this thread.

    Explaining NMS code can be an in-depth conversation, and sometimes its better to demonstrate whats happening. This can be done more easily by showing you what happens on the server. Plus, i dont mind having company!

    Anyway, back to the discussion.

    • Like Like x 1
  8. How would I make a creeper move towards the player then hit the player with pathfindergoals?

  9. Target Goal: PathfinderGoalNearestAttackableTarget
    Attack Goal: PathfinderGoalMeleeAttack
    (don't use PathfinderGoalSwell)

    To damage the target you have to override the "public boolean B(Entity entity)" method invoking the default one from the EntityMonster class with "super.B(entity)", and set the GenericAttributes.ATTACK_DAMAGE attribute.
  10. In EntityCreeper it's only this:
    public boolean B(Entity entity) {
    return true;
  11. Yes, and you have to override it like I said.
  12. super.B(entity) just refers to EntityCreeper's 'public boolean B(entity)' method? and won't Nearestattackabletarget make the creeper blow up and die? I want it to hit the player like a zombie.
  13. I forgot you are extending the EntityCreeper class...
    To call the "public boolean B(Entity entity)" from the EntityMonster class you need to use reflection.
    What makes him blow up is the PathfinderGoalSwell.
  14. NearestAttackableTarget that sets the entities current target to the entity type that is passed through its constructor. It doesnt actually carry out the attack itself, but rather it sets the target that the action will be performed on.

    What you will likely have to do is create your own custom melee attack goal, and remove the exploding creeper one (that @Grimerlin mentioned), and assign the new one to your creeper. Zombies have a relatively simple melee attack goal, thats what i would use in your case.

    I would look into it myself, but i am very busy this week with finishing up the Fortress mod for testing and setting up the test/dev server...also working on a part 2 of this tutorial.
  15. @bigans01
    I followed your method to creating custom entities and overrode a() and b() nbt methods in the custom entity class, so I can save entity specific data, however when the server restarts sometimes the custom entity is replaced with a default version of the entity(it's a polar bear btw), so all of the data I was saving in the entity got wiped as did it's custom behavior. I tested this more on my local server and found out that if the custom polar bear was in a chunk that was loaded when the server reloaded, it's data and behavior would get wiped and it'd be a default polar bear. However on the actual server, we never reload it and only have restarts every few hours. So to fix this I was thinking when the server disables, kick all players immediately but then have a delay of some sort to make sure all chunks are unloaded properly and the nbt save method is called on every custom entity. My question is, is there a way to force call the nbt save method on my custom entities so I could possibly do that in onDisable instead of putting in a delay? Also do you know any other ways I can get around this, I don't like having to refund these entities everytime one of them glitches
  16. Do you have the key "load: startup" in the plugin.yml file? If not, then you are overriding the EntityTypes maps after the world is loaded and any custom entity saved in the nbt file will be converted to a default entity or even deleted.
  17. hmm I do not, where do I put that in my plugin.yml? Also players have been having these exact problems, sometimes they get deleted or replaced to the default entity
  18. You put it like a simple "key: value" in a new line. However, if players get deleted too then it's not a problem about custom entities but something else, maybe corrupt chunks.