[NMS] [1.8] Customized Mob Behaviour

Discussion in 'Plugin Help/Development/Requests' started by megamichiel, Dec 5, 2014.

Thread Status:
Not open for further replies.
  1. Hello there, a short while ago Spigot/Bukkit was released for Minecraft 1.8. So I wanted to modify the behavious of 1.8 mobs(like rabbits). This post was continued from this post which was for 1.7 and originally continued from this post. Since in each MC update the Fields/Methods change and the other 2 posts's creators haven't been active for a while, I wanted to show to others how it's possible in Minecraft 1.8.
    Let's say we want a custom skeleton. At first, we need to set up out entitytypes, I recommend using an enum for this, cause it's easy to use to add your own mobs.
    Code:java
    1. public enum CustomEntityType {
    2. //Temporary, cause else it will throw some errors, you will see for yourself if u remove it :p
    3. CUSTOMSKELETON(null,0,null,null,null);
    4. private String name;
    5. private int id;
    6. private EntityType entityType;
    7. private Class<? extends EntityInsentient> nmsClass;
    8. private Class<? extends EntityInsentient> customClass;
    9.  
    10. private CustomEntityType(/*The name of the NMS entity*/String name, /*The entity id*/int id, /*The entity type*/EntityType entityType, /*The origional NMS class*/ Class<? extends EntityInsentient> nmsClass, /*The custom class*/ Class<? extends EntityInsentient> customClass) {
    11. this.name = name;
    12. this.id = id;
    13. this.entityType = entityType;
    14. this.nmsClass = nmsClass;
    15. this.customClass = customClass;
    16. }
    17.  
    18. public String getName() {
    19. return name;
    20. }
    21.  
    22. public int getID() {
    23. return id;
    24. }
    25.  
    26. public EntityType getEntityType() {
    27. return entityType;
    28. }
    29.  
    30. public Class<? extends EntityInsentient> getNMSClass() {
    31. return nmsClass;
    32. }
    33.  
    34. public Class<? extends EntityInsentient> getCustomClass() {
    35. return customClass;
    36. }

    Then what we want to do, is set up some code to (un)register our entities:
    Code:java
    1. /*Register our entities to the server, add to onEnable()*/
    2. public static void registerEntities() {
    3. for (CustomEntityType entity : values()) /*Get our entities*/
    4. a(entity.getCustomClass(), entity.getName(), entity.getID());
    5. /*Get all biomes on the server*/
    6. BiomeBase[] biomes;
    7. try {
    8. biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
    9. } catch (Exception exc) {
    10. return;
    11. }
    12. for (BiomeBase biomeBase : biomes) {
    13. if (biomeBase == null)
    14. break;
    15. for (String field : new String[] { "at", "au", "av", "aw" }) //Lists that hold all entity types
    16. try {
    17. Field list = BiomeBase.class.getDeclaredField(field);
    18. list.setAccessible(true);
    19. @SuppressWarnings("unchecked")
    20. List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
    21.  
    22. for (BiomeMeta meta : mobList)
    23. for (CustomEntityType entity : values())
    24. if (entity.getNMSClass().equals(meta.b)) /*Test if the entity has the custom entity type*/
    25. meta.b = entity.getCustomClass(); //Set it's meta to our custom class's meta
    26. } catch (Exception e) {
    27. e.printStackTrace();
    28. }
    29. }
    30. }
    31. /*Method(add to onDisable()) to prevent server leaks when the plugin gets disabled*/
    32. @SuppressWarnings("rawtypes")
    33. public static void unregisterEntities() {
    34. for (CustomEntityType entity : values()) {
    35. // Remove our class references.
    36. try {
    37. ((Map) getPrivateStatic(EntityTypes.class, "d")).remove(entity.getCustomClass());
    38. } catch (Exception e) {
    39. e.printStackTrace();
    40. }
    41.  
    42. try {
    43. ((Map) getPrivateStatic(EntityTypes.class, "f")).remove(entity.getCustomClass());
    44. } catch (Exception e) {
    45. e.printStackTrace();
    46. }
    47. }
    48.  
    49. for (CustomEntityType entity : values())
    50. try {
    51. a(entity.getNMSClass(), entity.getName(), entity.getID());
    52. } catch (Exception e) {
    53. e.printStackTrace();
    54. }
    55.  
    56. BiomeBase[] biomes;
    57. try {
    58. biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes"); /*Get all biomes again*/
    59. } catch (Exception exc) {
    60. return;
    61. }
    62. for (BiomeBase biomeBase : biomes) {
    63. if (biomeBase == null)
    64. break;
    65.  
    66. for (String field : new String[] { "at", "au", "av", "aw" }) /*The entity list*/
    67. try {
    68. Field list = BiomeBase.class.getDeclaredField(field);
    69. list.setAccessible(true);
    70. @SuppressWarnings("unchecked")
    71. List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
    72.  
    73. for (BiomeMeta meta : mobList)
    74. for (CustomEntityType entity : values())
    75. if (entity.getCustomClass().equals(meta.b))
    76. meta.b = entity.getNMSClass(); /*Set the entities meta back to the NMS one*/
    77. } catch (Exception e) {
    78. e.printStackTrace();
    79. }
    80. }
    81. }
    82. /*A little Util for getting a private field*/
    83. @SuppressWarnings("rawtypes")
    84. private static Object getPrivateStatic(Class clazz, String f) throws Exception {
    85. Field field = clazz.getDeclaredField(f);
    86. field.setAccessible(true);
    87. return field.get(null);
    88. }
    89. /*Set data into the entitytypes class from NMS*/
    90. @SuppressWarnings({ "unchecked", "rawtypes" })
    91. private static void a(Class paramClass, String paramString, int paramInt) {
    92. try {
    93. ((Map) getPrivateStatic(EntityTypes.class, "c")).put(paramString, paramClass);
    94. ((Map) getPrivateStatic(EntityTypes.class, "d")).put(paramClass, paramString);
    95. ((Map) getPrivateStatic(EntityTypes.class, "e")).put(Integer.valueOf(paramInt), paramClass);
    96. ((Map) getPrivateStatic(EntityTypes.class, "f")).put(paramClass, Integer.valueOf(paramInt));
    97. ((Map) getPrivateStatic(EntityTypes.class, "g")).put(paramString, Integer.valueOf(paramInt));
    98. } catch (Exception exc) {
    99. }
    100. }

    Now, that was all for the CustomEntityType class, We will get back here later to register our custom entity to it, but now, create a new class for our custom skeleton:
    Code:java
    1. public class CustomEntitySkeleton extends EntitySkeleton/*NMS Skeleton class*/ {
    2. /*Something from the EntitySkeleton class, isn't very important*/
    3. public CustomEntitySkeleton(World world) {
    4. super(world);
    5. }
    6. }

    Now, for example, if we want to let the skeleton shoot 2 arrows, we could add this method to the custom skeleton class:
    Code:java
    1. @Override
    2. public void a(EntityLiving entity, float f) { //Called when the skeleton wants to shoot an arrow
    3. for(int i=0;i<2;i++) { //Create a loop
    4. super.a(entity, f); //Shoot an arrow from the normal skeleton class
    5. }
    6. }

    Now, at last, we need to add the skeleton to our CustomEntityType enum, this is very easy, but u need to make sure it's added just below the enum opening:
    Code:java
    1. public enum CustomEntityType {
    2. CUSTOMSKELETON(/*NMS entity name*/"Skeleton",/*NMS entity id*/51,/*The entity type*/EntityType.SKELETON,/*The NMS class*/EntitySkeleton.class,/*Our custom class*/CustomEntitySkeleton.class);
    3. I hope you fully understand an can enjoy it! :)
    4.  
    5. //Recent code stuff...
     
  2. Offline

    callum2904

    Code:
    package me.callum2904.roleplay.entities;
    
    import java.lang.reflect.Field;
    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.EntityInsentient;
    import net.minecraft.server.v1_8_R1.EntityTypes;
    import net.minecraft.server.v1_8_R1.EntityZombie;
    
    import org.bukkit.entity.EntityType;
    
    public enum CustomEntityType {
    
        ZOMBIE("Zombie", 54, EntityType.ZOMBIE, EntityZombie.class, CustomEntityZombie.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;
        }
     
        public static void registerEntities() {
            for (CustomEntityType entity : values())
                a(entity.getCustomClass(), entity.getName(), entity.getID());
    
            for (BiomeBase biomeBase : BiomeBase.getBiomes()) {
                if (biomeBase == null)
                    break;
                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);
    
                        for (BiomeMeta meta : mobList)
                            for (CustomEntityType entity : values())
                                if (entity.getNMSClass().equals(meta.b))
                                    meta.b = entity.getCustomClass();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
            }
        }
     
        @SuppressWarnings("rawtypes")
        public static void unregisterEntities() {
            for (CustomEntityType entity : values()) {
                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 {
                    a(entity.getNMSClass(), entity.getName(), entity.getID());
                } catch (Exception e) {
                    e.printStackTrace();
                }
         
            for (BiomeBase biomeBase : BiomeBase.getBiomes()) {
                if (biomeBase == null)
                    break;
    
                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);
    
                        for (BiomeMeta meta : mobList)
                            for (CustomEntityType entity : values())
                                if (entity.getCustomClass().equals(meta.b))
                                    meta.b = entity.getNMSClass();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
            }
        }
    
        @SuppressWarnings("rawtypes")
        private static Object getPrivateStatic(Class clazz, String f) throws Exception {
            Field field = clazz.getDeclaredField(f);
            field.setAccessible(true);
            return field.get(null);
        }
    
        @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) {
            }
        }
    }
    
    
    Code:
    [19:56:09 WARN]:        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlug
    in.java:318)
    [19:56:09 WARN]:        at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin
    (JavaPluginLoader.java:357)
    [19:56:09 WARN]:        at org.bukkit.plugin.SimplePluginManager.disablePlugin(S
    implePluginManager.java:431)
    [19:56:09 WARN]:        at org.bukkit.plugin.SimplePluginManager.disablePlugins(
    SimplePluginManager.java:424)
    [19:56:09 WARN]:        at org.bukkit.plugin.SimplePluginManager.clearPlugins(Si
    mplePluginManager.java:465)
    [19:56:09 WARN]:        at org.bukkit.craftbukkit.v1_8_R1.CraftServer.reload(Cra
    ftServer.java:709)
    [19:56:09 WARN]:        at org.bukkit.Bukkit.reload(Bukkit.java:301)
    [19:56:09 WARN]:        at org.bukkit.command.defaults.ReloadCommand.execute(Rel
    oadCommand.java:23)
    [19:56:09 WARN]:        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCo
    mmandMap.java:181)
    [19:56:09 WARN]:        at org.bukkit.craftbukkit.v1_8_R1.CraftServer.dispatchCo
    mmand(CraftServer.java:643)
    [19:56:09 WARN]:        at org.bukkit.craftbukkit.v1_8_R1.CraftServer.dispatchSe
    rverCommand(CraftServer.java:629)
    [19:56:09 WARN]:        at net.minecraft.server.v1_8_R1.DedicatedServer.aM(Dedic
    atedServer.java:353)
    [19:56:09 WARN]:        at net.minecraft.server.v1_8_R1.DedicatedServer.z(Dedica
    tedServer.java:317)
    [19:56:09 WARN]:        at net.minecraft.server.v1_8_R1.MinecraftServer.y(Minecr
    aftServer.java:625)
    [19:56:09 WARN]:        at net.minecraft.server.v1_8_R1.MinecraftServer.run(Mine
    craftServer.java:528)
    [19:56:09 WARN]:        at java.lang.Thread.run(Unknown Source)
    [19:56:09 WARN]: java.lang.ClassCastException: net.minecraft.server.v1_8_R1.Biom
    eDecorator cannot be cast to java.util.List
    [19:56:09 WARN]:        at me.callum2904.roleplay.entities.CustomEntityType.unre
    gisterEntities(CustomEntityType.java:119)
    [19:56:09 WARN]:        at me.callum2904.roleplay.Main.onDisable(Main.java:45)
    [19:56:09 WARN]:        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlug
    in.java:318)
    [19:56:09 WARN]:        at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin
    (JavaPluginLoader.java:357)
    [19:56:09 WARN]:        at org.bukkit.plugin.SimplePluginManager.disablePlugin(S
    implePluginManager.java:431)
    [19:56:09 WARN]:        at org.bukkit.plugin.SimplePluginManager.disablePlugins(
    SimplePluginManager.java:424)
    [19:56:09 WARN]:        at org.bukkit.plugin.SimplePluginManager.clearPlugins(Si
    mplePluginManager.java:465)
    [19:56:09 WARN]:        at org.bukkit.craftbukkit.v1_8_R1.CraftServer.reload(Cra
    ftServer.java:709)
    [19:56:09 WARN]:        at org.bukkit.Bukkit.reload(Bukkit.java:301)
    [19:56:09 WARN]:        at org.bukkit.command.defaults.ReloadCommand.execute(Rel
    oadCommand.java:23)
    [19:56:09 WARN]:        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCo
    mmandMap.java:181)
    [19:56:09 WARN]:        at java.lang.Thread.run(Unknown Source)
    
    Code:
    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);
    
                        for (BiomeMeta meta : mobList)
                            for (CustomEntityType entity : values())
                                if (entity.getCustomClass().equals(meta.b))
                                    meta.b = entity.getNMSClass();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
    
    This bit seems to be causing me the trouble.
     
  3. Offline

    ql_Nik_lp

    have you find a solution?
     
  4. Offline

    stonebloodtv

Thread Status:
Not open for further replies.

Share This Page