Solved Riding an Entity

Discussion in 'Plugin Help/Development/Requests' started by Zombie_Striker, Apr 25, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    Zombie_Striker

    I currently have this for riding my Endermite
    Code:
    package com.Zombie_Striker.me.L;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.List;
    import java.util.Map;
    
    import net.minecraft.server.v1_8_R1.BiomeBase;
    import net.minecraft.server.v1_8_R1.BiomeMeta;
    import net.minecraft.server.v1_8_R1.EntityEndermite;
    import net.minecraft.server.v1_8_R1.EntityInsentient;
    import net.minecraft.server.v1_8_R1.EntityTypes;
    
    import org.bukkit.entity.EntityType;
    
    public enum CustomEntityType {
    
        SKELETON("Skelegfsdsdon", 50, EntityType.CREEPER, EntityEndermite.class,
                Car.class);
    
        private String name;
        private int id;
        private EntityType entityType;
        private Class<? extends EntityInsentient> nmsClass;
        private Class<? extends EntityInsentient> customClass;
    
        private CustomEntityType(String name, int id, EntityType entityType,
                Class<? extends EntityInsentient> nmsClass,
                Class<? extends EntityInsentient> customClass) {
            this.name = name;
            this.id = id;
            this.entityType = entityType;
            this.nmsClass = nmsClass;
            this.customClass = customClass;
        }
    
        public String getName() {
            return name;
        }
    
        public int getID() {
            return id;
        }
    
        public EntityType getEntityType() {
            return entityType;
        }
    
        public Class<? extends EntityInsentient> getNMSClass() {
            return nmsClass;
        }
    
        public Class<? extends EntityInsentient> getCustomClass() {
            return customClass;
        }
    
        /**
         * Register our entities.
         */
        public static void registerEntities() {
            for (CustomEntityType entity : values())
                a(entity.getCustomClass(), entity.getName(), entity.getID());
    
            // BiomeBase#biomes became private.
            BiomeBase[] biomes;
            try {
                biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
            } catch (Exception exc) {
                // Unable to fetch.
                return;
            }
            for (BiomeBase biomeBase : biomes) {
                if (biomeBase == null)
                    break;
    
                // This changed names from J, K, L and M.
                for (String field : new String[] { "at", "au", "av", "aw" })
                    try {
                        Field list = BiomeBase.class.getDeclaredField(field);
                        list.setAccessible(true);
                        // System.out.println(list.getName());
                        @SuppressWarnings("unchecked")
                        List<BiomeMeta> mobList = (List<BiomeMeta>) list
                                .get(biomeBase);
    
                        // Write in our custom class.
                        for (BiomeMeta meta : mobList)
                            for (CustomEntityType entity : values())
                                if (entity.getNMSClass().equals(meta.b))
                                    meta.b = entity.getCustomClass();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
            }
        }
    
        /**
         * Unregister our entities to prevent memory leaks. Call on disable.
         */
        @SuppressWarnings("rawtypes")
        public static void unregisterEntities() {
            for (CustomEntityType entity : values()) {
                // Remove our class references.
                try {
                    ((Map) getPrivateStatic(EntityTypes.class, "d")).remove(entity
                            .getCustomClass());
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                try {
                    ((Map) getPrivateStatic(EntityTypes.class, "f")).remove(entity
                            .getCustomClass());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            for (CustomEntityType entity : values())
                try {
                    // Unregister each entity by writing the NMS back in place of
                    // the custom class.
                    a(entity.getNMSClass(), entity.getName(), entity.getID());
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            // Biomes#biomes was made private so use reflection to get it.
            BiomeBase[] biomes;
            try {
                biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
            } catch (Exception exc) {
                // Unable to fetch.
                return;
            }
            for (BiomeBase biomeBase : biomes) {
                if (biomeBase == null)
                    break;
    
                // The list fields changed names but update the meta regardless.
                for (String field : new String[] { "at", "au", "av", "aw" })
                    try {
                        Field list = BiomeBase.class.getDeclaredField(field);
                        list.setAccessible(true);
                        @SuppressWarnings("unchecked")
                        List<BiomeMeta> mobList = (List<BiomeMeta>) list
                                .get(biomeBase);
    
                        // Make sure the NMS class is written back over our custom
                        // class.
                        for (BiomeMeta meta : mobList)
                            for (CustomEntityType entity : values())
                                if (entity.getCustomClass().equals(meta.b))
                                    meta.b = entity.getNMSClass();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
            }
        }
    
        /**
         * A convenience method.
         *
         * @param clazz
         *            The class.
         * @param f
         *            The string representation of the private static field.
         * @return The object found
         * @throws Exception
         *             if unable to get the object.
         */
        @SuppressWarnings("rawtypes")
        private static Object getPrivateStatic(Class clazz, String f)
                throws Exception {
            Field field = clazz.getDeclaredField(f);
            field.setAccessible(true);
            return field.get(null);
        }
    
        /*
         * Since 1.7.2 added a check in their entity registration, simply bypass it
         * and write to the maps ourself.
         */
        @SuppressWarnings({ "unchecked", "rawtypes" })
        private static void a(Class paramClass, String paramString, int paramInt) {
            try {
                ((Map) getPrivateStatic(EntityTypes.class, "c")).put(paramString,
                        paramClass);
                ((Map) getPrivateStatic(EntityTypes.class, "d")).put(paramClass,
                        paramString);
                ((Map) getPrivateStatic(EntityTypes.class, "e")).put(
                        Integer.valueOf(paramInt), paramClass);
                ((Map) getPrivateStatic(EntityTypes.class, "f")).put(paramClass,
                        Integer.valueOf(paramInt));
                ((Map) getPrivateStatic(EntityTypes.class, "g")).put(paramString,
                        Integer.valueOf(paramInt));
            } catch (Exception exc) {
                // Unable to register the new class.
            }
        }
    }
    Code:
    package com.Zombie_Striker.me.L;
    
    import java.lang.reflect.Field;
    
    import org.bukkit.entity.Player;
    
    import net.minecraft.server.v1_8_R1.EntityEndermite;
    import net.minecraft.server.v1_8_R1.EntityHorse;
    import net.minecraft.server.v1_8_R1.EntityHuman;
    import net.minecraft.server.v1_8_R1.EntityLiving;
    import net.minecraft.server.v1_8_R1.EntityVillager;
    import net.minecraft.server.v1_8_R1.MathHelper;
    import net.minecraft.server.v1_8_R1.World;
    
    public class Car extends EntityEndermite{
    //I was experimenting if changing it to a horse/pig/villager would change anything
        public Car(World world) {
            super(world);
          
        }
    
        @Override
        public void e(float sideMot, float forMot) {
            if (this.passenger == null || !(this.passenger instanceof EntityHuman)) {
                super.e(sideMot, forMot);
             //   this.width = 0.5F;    // Make sure the entity can walk over half slabs, instead of jumping
                return;
            }
          
            this.lastYaw = this.yaw = 45;//this.passenger.yaw;
            this.pitch = this.passenger.pitch * 0.5F;
       
            // Set the entity's pitch, yaw, head rotation etc.
            this.b((int) this.passenger.yaw,true); //[url]https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/Entity.java#L163-L166[/url]
    
        }
        @Override
        public void g(float sideMot, float forMot) {
            if(this.passenger != null && (this.passenger instanceof EntityHuman||this.passenger instanceof Player)) {
                this.lastYaw = this.yaw = this.passenger.yaw;
                this.pitch = this.passenger.pitch * 0.5F;
                this.setYawPitch(this.yaw, this.pitch);//Update the pitch and yaw
                this.aI = this.aG = this.yaw;
                sideMot = ((EntityLiving)this.passenger).aX * 0.5F;
                forMot = ((EntityLiving)this.passenger).aY;
                if(forMot <= 0.0F) {
                    forMot *= 0.25F;// Make backwards slower
                }
                Field jump = null; //Jumping
                try {
                    jump = EntityLiving.class.getDeclaredField("aW");
                } catch (NoSuchFieldException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } catch (SecurityException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                jump.setAccessible(true);
                if (jump != null && this.onGround) {    // Wouldn't want it jumping while on the ground would we?
                    try {
                        if (jump.getBoolean(this.passenger)) {
                            double jumpHeight = 0.5D;//Here you can set the jumpHeight
                            this.motY = jumpHeight;    // Used all the time in NMS for entity jumping
                        }
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
                this.S = 1.0F;// The custom entity will now automatically climb up 1 high blocks
                this.aK = this.bH() * 0.1F;
                if(!this.world.isStatic) {
                    this.j(0.35F);//Here is the speed the entity will walk.
                    super.g(sideMot, forMot);
                }
                this.ay = this.az;//Some extra things
                double d0 = this.locX - this.lastX;
                double d1 = this.locZ - this.lastZ;
                float f4 = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F;
                if(f4 > 1.0F) {
                    f4 = 1.0F;
                }
                this.az += (f4 - this.az) * 0.4F;
                this.aA += this.az;
            } else {
                this.S = 0.5F;
                this.aK = 0.02F;
                super.g(sideMot, forMot);
            }
        }
      
      
    
    }
    
    And for some reason I can't control it. What did I miss?
     
    Last edited: Apr 25, 2015
  2. @Zombie_Striker
    I could be wrong but do endermites have an method so they can be controlled?
     
  3. Offline

    Zombie_Striker

    @DoppelRR I think all mobs can be controlled. Any that have either the g or e method in them I think.
     
  4. Offline

    Funergy

    @Zombie_Striker First try to make your mob like this
    just extend the EntityEndermite
    then just add the required method

    public Yourclass(World w){
    super(w);}

    and then just add the g() method from my thread. The only thing you will need to do is register the entity.
    The easiest thing is the NMSUtil
    Code:
    import net.minecraft.server.v1_8_R1.BiomeBase;
    import net.minecraft.server.v1_8_R1.BiomeMeta;
    import net.minecraft.server.v1_8_R1.EntityInsentient;
    import net.minecraft.server.v1_8_R1.EntityTypes;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    public class NMSUtils {
        public void registerEntity(String name, int id, Class<? extends EntityInsentient> nmsClass, Class<? extends EntityInsentient> customClass) {
            try {
    
                /*
                * First, we make a list of all HashMap's in the EntityTypes class
                * by looping through all fields. I am using reflection here so we
                * have no problems later when minecraft changes the field's name.
                * By creating a list of these maps we can easily modify them later
                * on.
                */
                List<Map<?, ?>> dataMaps = new ArrayList<Map<?, ?>>();
                for (Field f : EntityTypes.class.getDeclaredFields()) {
                    if (f.getType().getSimpleName().equals(Map.class.getSimpleName())) {
                        f.setAccessible(true);
                        dataMaps.add((Map<?, ?>) f.get(null));
                    }
                }
    
                /*
                * since minecraft checks if an id has already been registered, we
                * have to remove the old entity class before we can register our
                * custom one
                *
                * map 0 is the map with names and map 2 is the map with ids
                */
                if (dataMaps.get(2).containsKey(id)) {
                    dataMaps.get(0).remove(name);
                    dataMaps.get(2).remove(id);
                }
    
                /*
                * now we call the method which adds the entity to the lists in the
                * EntityTypes class, now we are actually 'registering' our entity
                */
                Method method = EntityTypes.class.getDeclaredMethod("a", Class.class, String.class, int.class);
                method.setAccessible(true);
                method.invoke(null, customClass, name, id);
    
                /*
                * after doing the basic registering stuff , we have to register our
                * mob as to be the default for every biome. This can be done by
                * looping through all BiomeBase fields in the BiomeBase class, so
                * we can loop though all available biomes afterwards. Here, again,
                * I am using reflection so we have no problems later when minecraft
                * changes the fields name
                */
                for (Field f : BiomeBase.class.getDeclaredFields()) {
                    if (f.getType().getSimpleName().equals(BiomeBase.class.getSimpleName())) {
                        if (f.get(null) != null) {
    
                            /*
                            * this peace of code is being called for every biome,
                            * we are going to loop through all fields in the
                            * BiomeBase class so we can detect which of them are
                            * Lists (again, to prevent problems when the field's
                            * name changes), by doing this we can easily get the 4
                            * required lists without using the name (which probably
                            * changes every version)
                            */
                            for (Field list : BiomeBase.class.getDeclaredFields()) {
                                if (list.getType().getSimpleName().equals(List.class.getSimpleName())) {
                                    list.setAccessible(true);
                                    @SuppressWarnings("unchecked")
                                    List<BiomeMeta> metaList = (List<BiomeMeta>) list.get(f.get(null));
    
                                    /*
                                    * now we are almost done. This peace of code
                                    * we're in now is called for every biome. Loop
                                    * though the list with BiomeMeta, if the
                                    * BiomeMeta's entity is the one you want to
                                    * change (for example if EntitySkeleton matches
                                    * EntitySkeleton) we will change it to our
                                    * custom entity class
                                    */
                                    for (BiomeMeta meta : metaList) {
                                        Field clazz = BiomeMeta.class.getDeclaredFields()[0];
                                        if (clazz.get(meta).equals(nmsClass)) {
                                            clazz.set(meta, customClass);
                                        }
                                    }
                                }
                            }
    
                        }
                    }
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    And then spawn it in.
    But I guess you know how to spawn it. (hopefully)
     
  5. Offline

    Zombie_Striker

    @Funergy Thanks, turns out I was imputing the wrong ID.(65 instead of 67) Thanks for the help though.
     
Thread Status:
Not open for further replies.

Share This Page