[Tutorial] Register your custom entities [NMS][Reflection]

Discussion in 'Resources' started by bigteddy98, Apr 18, 2014.

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

    Cirno

    I'm replying to a really old post. I'm going insane, aren't I?
    It is possible to make classes that extend other classes "version proof".
    It isn't easy, friendly, or pretty. On the bright side, the library required for this is included in CraftBukkit (at the time when I made the linked version, I didn't know about it). No idea why, but hey, it's something. On the... darker side, you have the typical dangers of NMS; same methods doing different things across two version, etc. etc. However, at least when you're defining a class, it'll fall on it's face as soon as the bytecode validator kicks in.
     
  2. Thanks but I don't understand any of it so I won't be using it xD Helpful for others that do understand this though.
     
  3. Offline

    Cirno

    It's actually pretty easy; the code looks scary, but most of it is generated :p
     
    KingFaris11 likes this.
  4. Offline

    paully104

    bigteddy98 I imagine im doing something wrong, for whatever reason all skeletons/spiders/creepers are replaced with zombies with their attributes on the server lol.. I have zombies that walk up to me and explode and zombies holding bows.
    main:
    Code:java
    1. package com.paulreitz.entitytest;
    2.  
    3.  
    4. import java.lang.reflect.Field;
    5. import java.lang.reflect.Method;
    6. import java.util.ArrayList;
    7. import java.util.List;
    8. import java.util.Map;
    9.  
    10. import net.minecraft.server.v1_7_R3.BiomeBase;
    11. import net.minecraft.server.v1_7_R3.BiomeMeta;
    12. import net.minecraft.server.v1_7_R3.EntityCreeper;
    13. import net.minecraft.server.v1_7_R3.EntityInsentient;
    14. import net.minecraft.server.v1_7_R3.EntitySkeleton;
    15. import net.minecraft.server.v1_7_R3.EntitySpider;
    16. import net.minecraft.server.v1_7_R3.EntityTypes;
    17. import net.minecraft.server.v1_7_R3.EntityZombie;
    18.  
    19. import org.bukkit.plugin.java.JavaPlugin;
    20.  
    21. public class Entitytestmain extends JavaPlugin {
    22. @Override
    23. public void onEnable() {
    24. registerEntity("Zombie", 54, EntityZombie.class, CustomEntityZombie.class);
    25. registerEntity("Skeleton", 54, EntitySkeleton.class, CustomEntitySkeleton.class);
    26. registerEntity("Spider", 54, EntitySpider.class, CustomEntitySpider.class);
    27. registerEntity("Creeper", 54, EntityCreeper.class, CustomEntityCreeper.class);
    28. }
    29.  
    30. public void registerEntity(String name, int id, Class<? extends EntityInsentient> nmsClass, Class<? extends EntityInsentient> customClass) {
    31. try {
    32.  
    33. /*
    34. * First, we make a list of all HashMap's in the EntityTypes class
    35. * by looping through all fields. I am using reflection here so we
    36. * have no problems later when minecraft changes the field's name.
    37. * By creating a list of these maps we can easily modify them later
    38. * on.
    39. */
    40. List<Map<?, ?>> dataMaps = new ArrayList<Map<?, ?>>();
    41. for (Field f : EntityTypes.class.getDeclaredFields()) {
    42. if (f.getType().getSimpleName().equals(Map.class.getSimpleName())) {
    43. f.setAccessible(true);
    44. dataMaps.add((Map<?, ?>) f.get(null));
    45. }
    46. }
    47.  
    48. /*
    49. * since minecraft checks if an id has already been registered, we
    50. * have to remove the old entity class before we can register our
    51. * custom one
    52. *
    53. * map 0 is the map with names and map 2 is the map with ids
    54. */
    55. if (dataMaps.get(2).containsKey(id)) {
    56. dataMaps.get(0).remove(name);
    57. dataMaps.get(2).remove(id);
    58. }
    59.  
    60. /*
    61. * now we call the method which adds the entity to the lists in the
    62. * EntityTypes class, now we are actually 'registering' our entity
    63. */
    64. Method method = EntityTypes.class.getDeclaredMethod("a", Class.class, String.class, int.class);
    65. method.setAccessible(true);
    66. method.invoke(null, customClass, name, id);
    67.  
    68. /*
    69. * after doing the basic registering stuff , we have to register our
    70. * mob as to be the default for every biome. This can be done by
    71. * looping through all BiomeBase fields in the BiomeBase class, so
    72. * we can loop though all available biomes afterwards. Here, again,
    73. * I am using reflection so we have no problems later when minecraft
    74. * changes the fields name
    75. */
    76. for (Field f : BiomeBase.class.getDeclaredFields()) {
    77. if (f.getType().getSimpleName().equals(BiomeBase.class.getSimpleName())) {
    78. if (f.get(null) != null) {
    79.  
    80. /*
    81. * this peace of code is being called for every biome,
    82. * we are going to loop through all fields in the
    83. * BiomeBase class so we can detect which of them are
    84. * Lists (again, to prevent problems when the field's
    85. * name changes), by doing this we can easily get the 4
    86. * required lists without using the name (which probably
    87. * changes every version)
    88. */
    89. for (Field list : BiomeBase.class.getDeclaredFields()) {
    90. if (list.getType().getSimpleName().equals(List.class.getSimpleName())) {
    91. list.setAccessible(true);
    92. @SuppressWarnings("unchecked")
    93. List<BiomeMeta> metaList = (List<BiomeMeta>) list.get(f.get(null));
    94.  
    95. /*
    96. * now we are almost done. This peace of code
    97. * we're in now is called for every biome. Loop
    98. * though the list with BiomeMeta, if the
    99. * BiomeMeta's entity is the one you want to
    100. * change (for example if EntitySkeleton matches
    101. * EntitySkeleton) we will change it to our
    102. * custom entity class
    103. */
    104. for (BiomeMeta meta : metaList) {
    105. Field clazz = BiomeMeta.class.getDeclaredFields()[0];
    106. if (clazz.get(meta).equals(nmsClass)) {
    107. clazz.set(meta, customClass);
    108. //System.out.println("set");
    109. }
    110. }
    111. }
    112. }
    113.  
    114. }
    115. }
    116. }
    117.  
    118. } catch (Exception e) {
    119. //e.printStackTrace();
    120. }
    121. }
    122. }
    123.  

    creeper class:
    Code:java
    1. package com.paulreitz.entitytest;
    2.  
    3. import java.lang.reflect.Field;
    4.  
    5. import net.minecraft.server.v1_7_R3.EntityCreeper;
    6. import net.minecraft.server.v1_7_R3.EntityZombie;
    7. import net.minecraft.server.v1_7_R3.GenericAttributes;
    8. import net.minecraft.server.v1_7_R3.World;
    9.  
    10.  
    11.  
    12. public class CustomEntityCreeper extends EntityCreeper {
    13.  
    14.  
    15.  
    16.  
    17.  
    18. public CustomEntityCreeper(World world) {
    19. super(world);
    20.  
    21. }
    22.  
    23.  
    24.  
    25.  
    26.  
    27. @Override
    28. protected void aC() {
    29.  
    30.  
    31. super.aC();
    32. //this.bc().b(GenericAttributes.b);
    33. this.getAttributeInstance(GenericAttributes.b).setValue(100.0D);//mob range
    34.  
    35.  
    36. }
    37.  
    38. }


    edit: im a special kind of stupid lol, forgot to switch the ids
    Code:java
    1. public void onEnable() {
    2. registerEntity("Zombie", 54, EntityZombie.class, CustomEntityZombie.class);
    3. registerEntity("Skeleton", 51, EntitySkeleton.class, CustomEntitySkeleton.class);
    4. registerEntity("Spider", 52, EntitySpider.class, CustomEntitySpider.class);
    5. registerEntity("Creeper", 50, EntityCreeper.class, CustomEntityCreeper.class);
    6. }
     
  5. Offline

    Dablakbandit

    KingFaris11
    I just did it.... will be releasing a API to do this soon
     
    KingFaris11 likes this.
  6. Offline

    bigteddy98

    hmm, how? Did you really make it version independent? Or did you develop an API which you have to update for us?
     
  7. Offline

    _LB

    It's not difficult to make it version independent, the problem is that you're setting yourself up for problems when obfuscation changes.
     
  8. Offline

    Dablakbandit

    bigteddy98
    Version Independent
     
  9. Offline

    Dablakbandit

    bigteddy98 KingFaris11

    Check out the progress here, will be uploading a plugin soon (sadly only with being able to edit sheep, will move onto other entities afterwards)
    http://dev.bukkit.org/bukkit-plugins/customentitiesapi/

    Also if you have any methods that would like me to add to the custom entities please pm with a pastebin link + what the code does and I will happily apply it to the CustomEntities

    #Edit: Just realised you may not be able to see the page as I haven't uploaded a file
     
  10. Offline

    bigteddy98

    "
    This project is currently under moderation. Please come back later.
    " Do you have a direct link?
     
  11. Offline

    Dablakbandit

    The best I can do is provide you with a picture
    [​IMG]

    #Edit : Sorry for any spelling mistakes, English is not my strong point
     
    KingFaris11 likes this.
  12. Yay :]
     
  13. Offline

    Dablakbandit

  14. Offline

    Dablakbandit

    KingFaris11 likes this.
  15. Holy crap - that's mad useful - especially the diamond thing. Wow... never knew you could actually make something like that. Is it possible for you to have a boolean parameter for setUnpushable() or whatever? E.g: sheep.setUnpushable(true);
     
  16. Offline

    Dablakbandit

    I could add that yeah, but I've already uploaded the file so in the next update it will be there
     
  17. Damn ;( Okay. :p
     
  18. Offline

    Dablakbandit

    KingFaris11 bigteddy98
    The plugin is on the Spigot Forums aswell <Edit by Moderator: Redacted not allowed paid resource url>
     
    Last edited by a moderator: Dec 7, 2016
  19. I think your message is going to get edited/deleted as you're "advertising" as the poor Bukkit staff members say.
    But anyway, nice. :p
     
  20. Offline

    lenis0012

    So may yours, for going off-topic
     
    KingFaris11 likes this.
  21. Offline

    Force_Update1

    Hello,
    I have make a CustomBat Class, but why is not performed unleash event

    Code:java
    1. Bat entity = (Bat) bat.getBukkitEntity();
    2. entity.setLeashHolder(player);
     
Thread Status:
Not open for further replies.

Share This Page