Help with Custom Entity 1.7.2

Discussion in 'Plugin Development' started by rimidalv111, Dec 11, 2013.

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

    rimidalv111

    Hi, I need some help understanding bukkit 1.7.2 custom entities. I go ahead and make the classes that need to be made.

    CustomEntityType.class
    Code:java
    1.  
    2. import java.lang.reflect.Field;
    3. import java.lang.reflect.Method;
    4. import java.util.List;
    5.  
    6. import net.minecraft.server.v1_7_R1.BiomeBase;
    7. import net.minecraft.server.v1_7_R1.BiomeMeta;
    8. import net.minecraft.server.v1_7_R1.EntityInsentient;
    9. import net.minecraft.server.v1_7_R1.EntityTypes;
    10. import net.minecraft.server.v1_7_R1.EntityZombie;
    11.  
    12. import org.bukkit.entity.EntityType;
    13.  
    14. public enum CustomEntityType
    15. {
    16.  
    17. ZOMBIE("Zombie", 54, EntityType.ZOMBIE, EntityZombie.class, CustomEntityZombie.class);
    18.  
    19. private String name;
    20. private int id;
    21. private EntityType entityType;
    22. private Class<? extends EntityInsentient> nmsClass;
    23. private Class<? extends EntityInsentient> customClass;
    24.  
    25. private CustomEntityType(String name, int id, EntityType entityType, Class<? extends EntityInsentient> nmsClass, Class<? extends EntityInsentient> customClass)
    26. {
    27. this.name = name;
    28. this.id = id;
    29. this.entityType = entityType;
    30. this.nmsClass = nmsClass;
    31. this.customClass = customClass;
    32. }
    33.  
    34. public String getName()
    35. {
    36. return this.name;
    37. }
    38.  
    39. public int getID()
    40. {
    41. return this.id;
    42. }
    43.  
    44. public EntityType getEntityType()
    45. {
    46. return this.entityType;
    47. }
    48.  
    49. public Class<? extends EntityInsentient> getNMSClass()
    50. {
    51. return this.nmsClass;
    52. }
    53.  
    54. public Class<? extends EntityInsentient> getCustomClass()
    55. {
    56. return this.customClass;
    57. }
    58.  
    59. public static void registerEntities()
    60. {
    61. for (CustomEntityType entity : values())
    62. {
    63. try
    64. {
    65. Method a = EntityTypes.class.getDeclaredMethod("a", new Class<?>[]
    66. {Class.class, String.class, int.class});
    67. a.setAccessible(true);
    68. a.invoke(null, entity.getCustomClass(), entity.getName(), entity.getID());
    69. } catch (Exception e)
    70. {
    71. e.printStackTrace();
    72. }
    73. }
    74.  
    75. BiomeBase[] biomes;
    76. try
    77. {
    78. biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
    79. } catch (Exception exc)
    80. {
    81. System.out.println("Biome loading messed up!");
    82. return;
    83. }
    84. for (BiomeBase biomeBase : biomes)
    85. {
    86. if (biomeBase == null)
    87. break;
    88.  
    89. for (String field : new String[]
    90. {"as", "at", "au", "av"})
    91. try
    92. {
    93. Field list = BiomeBase.class.getDeclaredField(field);
    94. list.setAccessible(true);
    95. @SuppressWarnings("unchecked")
    96. List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
    97.  
    98. for (BiomeMeta meta : mobList)
    99. for (CustomEntityType entity : values())
    100. if (entity.getNMSClass().equals(meta.b))
    101. meta.b = entity.getCustomClass();
    102. } catch (Exception e)
    103. {
    104. e.printStackTrace();
    105. }
    106. }
    107. }
    108.  
    109. private static Object getPrivateStatic(Class<BiomeBase> clazz, String f) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
    110. {
    111. Field field = clazz.getDeclaredField(f);
    112. field.setAccessible(true);
    113. return field.get(null);
    114. }
    115. }
    116.  

    CustomEntityZombie.class
    Code:java
    1.  
    2. import net.minecraft.server.v1_7_R1.EntityZombie;
    3. import net.minecraft.server.v1_7_R1.World;
    4.  
    5. public class CustomEntityZombie extends EntityZombie
    6. {
    7. public CustomEntityZombie(World world)
    8. {
    9. super(world);
    10. }
    11. }
    12.  

    Then I run the plugin and get error
    Code:
    [14:50:57 WARN]: java.lang.reflect.InvocationTargetException
    .........
    [14:50:57 WARN]: Caused by: java.lang.IllegalArgumentException: ID is already re
    gistered: Zombie
    [14:50:57 WARN]:        at net.minecraft.server.v1_7_R1.EntityTypes.a(SourceFile
    :30)
    
    So how can ID be already registered??

    Thanks!
     
  2. Offline

    jeremytrains

    I have the same problem. Have you figured out a solution yet? When I try to register it as a different String ID or int ID the client crashes.
     
  3. Offline

    EcMiner

    it's already registered because minecraft registers their zombie class with the same id and name, to overwrite their registration do this:
    Code:java
    1. public static void registerEntities() {
    2. for (CustomEntityType entity : values()) {
    3. try {
    4. Class<?> en = EntityTypes.class;
    5. Field c = en.getDeclaredField("c");
    6. c.setAccessible(true);
    7. Field d = en.getDeclaredField("d");
    8. d.setAccessible(true);
    9. Field e = en.getDeclaredField("e");
    10. e.setAccessible(true);
    11. Field f = en.getDeclaredField("f");
    12. f.setAccessible(true);
    13. Field g = en.getDeclaredField("g");
    14. g.setAccessible(true);
    15. ((Map) c.get(null)).put(entity.getName(), entity.getCustomClass());
    16. ((Map) d.get(null)).put(entity.getCustomClass(), entity.getName());
    17. ((Map) e.get(null)).put(entity.getID(), entity.getCustomClass());
    18. ((Map) f.get(null)).put(entity.getCustomClass(), entity.getID());
    19. } catch (Exception e) {
    20. e.printStackTrace();
    21. }
    22. }
    23. for (BiomeBase biomeBase : BiomeBase.n()) {
    24. if (biomeBase == null) {
    25. break;
    26. }
    27.  
    28. for (String field : new String[] { "as", "at", "au", "av" }) {
    29. try {
    30. Field list = BiomeBase.class.getDeclaredField(field);
    31. list.setAccessible(true);
    32. List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
    33.  
    34. for (BiomeMeta meta : mobList) {
    35. for (CustomEntityType entity : values()) {
    36. if (entity.getNMSClass().equals(meta.b)) {
    37. meta.b = entity.getCustomClass();
    38. }
    39. }
    40. }
    41. } catch (Exception e) {
    42. e.printStackTrace();
    43. }
    44. }
    45. }
    46. }
     
  4. Offline

    jeremytrains

    EcMiner
    But what if I don't want to change ALL entities to my special subclass, but I just want to create some special entities. If I use the first section of code to register the class and I use craftWorld.getHandler().addEntity(entity, SpawnReason.CUSTOM); then will it spawn the entity correctly? I don't want to change all entities to my special class, just a few specific ones.
     
  5. Offline

    EcMiner


    If you created a custom zombie, it won't naturally spawn as your custom zombie, but when you use like a zombie monster egg, your custom zombie will spawn, if you use .addEntity() you can do new EntityZombie(....) it will spawn a normal zombie but if you do new CustomZombe(....) it will spawn your custom zombie
     
  6. Offline

    TeeePeee

    See the code snippet I posted here. I believe it's the forum post you got your CustomEntityTypes class from but I revised the code for 1.7.2. Minecraft added a check to ensure an entity wasn't registered twice with the same ID, but it can be easily bypassed with reflection.

    There is also a reply on the page I linked to that provides a solution for allowing normal mobs to spawn when custom.
     
  7. Offline

    jeremytrains

    EcMiner TeeePeee
    Thank you so much!! I have been stuck on this for multiple days and I finally figured out, thanks to your help, what I was doing wrong! When I attempted to manually write the id's, names, and classes into the maps in EntityTypes, I used the fields b, c, d, e, and f instead of c, d, e, f, and g. Thank you so much! I can continue to code now!
     
  8. Offline

    Scyntrus

    I recommend skipping "e", since that might make zombie eggs spawn your custom zombie instead of regular zombies. Correct me if I'm wrong.
     
Thread Status:
Not open for further replies.

Share This Page