Tutorial - How to Customize the Behaviour of a Mob or Entity

Discussion in 'Resources' started by Jacek, Jan 13, 2012.

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

    elraro

    /bump my question
     
  2. Offline

    MrOAriO

    With this :
    Code:java
    1. @Override
    2. public void ay() {
    3. super.ay();
    4. this.getAttributeInstance(GenericAttributes.a).setValue(1000.0D); // Leben
    5. }
     
  3. Offline

    waicool20

    Hey uhh how can i make a bat go to a location?
     
  4. Offline

    elraro

    The method ay() of type CustomEntityIronGolem must override or implement a supertype
    method

    The method ay() is undefined for the type EntityIronGolem
     
  5. Offline

    elraro

    Solved my question :p
     
  6. Offline

    Quaro

    And how to create, for example, frozen, invincible mob?
     
    GrandmaJam likes this.
  7. Offline

    RingOfStorms

    Remove pathfinders and override damage methods, or just cancel it's damage with bukkit's events.
     
  8. Offline

    Quaro

  9. Offline

    RingOfStorms

    Google, there are even examples in this thread iirc
     
  10. Offline

    Quaro

    I don't understand this, need better example. Could someone make example: IronGolem that attacks players instead of monsters? And how to spawn it at my specific location?
     
  11. Offline

    RingOfStorms

    This thread is not about copy pasting, if you don't understand this code then you shouldn't be using it. The point of all the examples here are to be examples that you read and learn how they work. We're not going to make another one that fits your exact situation just so you can copy paste it and not understand what it really does. Several people who had that happen just come back every update and ask over and over again because they don't know how the code works.

    Try searching and reading more about it, there are so many resources in this thread and a few others that you can use to learn how to make it yourself.
     
    GrandmaJam likes this.
  12. Offline

    Quaro

    -deleted-
     
  13. Offline

    Quaro

    I made a custom entity iron golem, that attacks players, but it attacks monsters too. How to make that it would attack only players?
     
  14. Offline

    TeeePeee

    This works great, but, what about spawning the custom entities only in a specific world and not in others?
     
    GrandmaJam likes this.
  15. Offline

    CrystalxNeth

    Would it be possible to have custom villagers and other mobs that you choose where they spawn, and if that mob spawns naturally than it wont be custom, just a regular mob. Also with the custom mobs you choose to spawn would they be able to have different names as well as not be able to move?
     
  16. Offline

    BeastlyJman

    I know this is a very broad question... but could someone please tell me what is wrong with this code? I have been working on it for a solid 3 days and im still unable to spawn custom iron golems.

    This is the custom mob code:
    Code:java
    1. package Mob;
    2.  
    3. import java.lang.reflect.AccessibleObject;
    4. import java.lang.reflect.Field;
    5. import java.util.List;
    6. import org.bukkit.entity.Entity;
    7. import org.bukkit.entity.IronGolem;
    8. import net.minecraft.server.v1_6_R3.EntityHuman;
    9. import net.minecraft.server.v1_6_R3.EntityMonster;
    10. import net.minecraft.server.v1_6_R3.PathfinderGoal;
    11. import net.minecraft.server.v1_6_R3.PathfinderGoalHurtByTarget;
    12. import net.minecraft.server.v1_6_R3.PathfinderGoalLookAtPlayer;
    13. import net.minecraft.server.v1_6_R3.PathfinderGoalNearestAttackableTarget;
    14. import net.minecraft.server.v1_6_R3.World;
    15.  
    16. public class CustomEntityGolem extends net.minecraft.server.v1_6_R3.EntityGolem {
    17.  
    18. @SuppressWarnings("unchecked")
    19. public CustomEntityGolem(World world) {
    20. super(world);
    21. System.out.println("Created Iron Golem... Custom fo sho");
    22. try {
    23. Field goala = this.goalSelector.getClass().getDeclaredField("a");
    24. goala.setAccessible(true);
    25. ((List<PathfinderGoal>) goala.get(this.goalSelector)).clear();
    26. Field targeta = this.targetSelector.getClass().getDeclaredField("a");
    27. targeta.setAccessible(true);
    28. ((List<PathfinderGoal>) targeta.get(this.targetSelector)).clear();
    29. this.goalSelector.a(0, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F));
    30.  
    31. this.targetSelector.a(2, new PathfinderGoalHurtByTarget(this, false));
    32. this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget(this, EntityMonster.class, 0, false, true));
    33. } catch (Exception e) {
    34. }
    35. }
    36.  
    37. public void anger() {
    38. this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget(this, EntityHuman.class, 0, false, true));
    39. }
    40.  
    41. public Entity getEntity() {
    42. IronGolem currentIronGolem = (IronGolem) this.getBukkitEntity();
    43. return currentIronGolem;
    44. }
    45. }


    This is the line i have in the enum:
    Code:text
    1.  
    2. CUSTOMGOLEM("VillagerGolem", 99, EntityType.IRON_GOLEM, EntityIronGolem.class, CustomEntityGolem.class);
    3.  

    And also what is the most effective way to spawn them? I have tried:
    Code:text
    1.  
    2. p.getWorld().spawnEntity(p.getLocation(), CustomEntityType.CUSTOMGOLEM.getEntityType());
    3.  

    Thanks for the help... Idk how everyone was getting this so easily... i must be overthinking it or something. And yes i have
    Code:text
    1. CustomEntityType.registerEntities()
    in the onEnable();
     
  17. Offline

    Ugleh

    How do I spawn the custom entity into the world without having it take over the normal one. I.E I want 2 types of bats, the regular kind and the kind I want to spawn via code.
     
  18. Offline

    TeeePeee

    For those of you wondering, the new class would look something like this with the Minecraft 1.7.2 update.

    Code:java
    1. package p;
    2.  
    3. import java.lang.reflect.Field;
    4. import java.util.List;
    5. import java.util.Map;
    6.  
    7. import net.minecraft.server.v1_7_R1.BiomeBase;
    8. import net.minecraft.server.v1_7_R1.BiomeMeta;
    9. import net.minecraft.server.v1_7_R1.EntityInsentient;
    10. import net.minecraft.server.v1_7_R1.EntityTypes;
    11. import net.minecraft.server.v1_7_R1.EntityZombie;
    12.  
    13. import org.bukkit.entity.EntityType;
    14.  
    15. public enum CustomEntityType {
    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,
    26. Class<? extends EntityInsentient> customClass) {
    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. return name;
    36. }
    37.  
    38. public int getID() {
    39. return id;
    40. }
    41.  
    42. public EntityType getEntityType() {
    43. return entityType;
    44. }
    45.  
    46. public Class<? extends EntityInsentient> getNMSClass() {
    47. return nmsClass;
    48. }
    49.  
    50. public Class<? extends EntityInsentient> getCustomClass() {
    51. return customClass;
    52. }
    53.  
    54. /**
    55.   * Register our entities.
    56.   */
    57. public static void registerEntities() {
    58. for (CustomEntityType entity : values())
    59. a(entity.getCustomClass(), entity.getName(), entity.getID());
    60.  
    61. // BiomeBase#biomes became private.
    62. BiomeBase[] biomes;
    63. try {
    64. biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
    65. } catch (Exception exc) {
    66. // Unable to fetch.
    67. return;
    68. }
    69. for (BiomeBase biomeBase : biomes) {
    70. if (biomeBase == null)
    71. break;
    72.  
    73. // This changed names from J, K, L and M.
    74. for (String field : new String[] { "as", "at", "au", "av" })
    75. try {
    76. Field list = BiomeBase.class.getDeclaredField(field);
    77. list.setAccessible(true);
    78. @SuppressWarnings("unchecked")
    79. List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
    80.  
    81. // Write in our custom class.
    82. for (BiomeMeta meta : mobList)
    83. for (CustomEntityType entity : values())
    84. if (entity.getNMSClass().equals(meta.b))
    85. meta.b = entity.getCustomClass();
    86. } catch (Exception e) {
    87. e.printStackTrace();
    88. }
    89. }
    90. }
    91.  
    92. /**
    93.   * Unregister our entities to prevent memory leaks. Call on disable.
    94.   */
    95. public static void unregisterEntities() {
    96. for (CustomEntityType entity : values()) {
    97. // Remove our class references.
    98. try {
    99. ((Map) getPrivateStatic(EntityTypes.class, "d")).remove(entity.getCustomClass());
    100. } catch (Exception e) {
    101. e.printStackTrace();
    102. }
    103.  
    104. try {
    105. ((Map) getPrivateStatic(EntityTypes.class, "f")).remove(entity.getCustomClass());
    106. } catch (Exception e) {
    107. e.printStackTrace();
    108. }
    109. }
    110.  
    111. for (CustomEntityType entity : values())
    112. try {
    113. // Unregister each entity by writing the NMS back in place of the custom class.
    114. a(entity.getNMSClass(), entity.getName(), entity.getID());
    115. } catch (Exception e) {
    116. e.printStackTrace();
    117. }
    118.  
    119. // Biomes#biomes was made private so use reflection to get it.
    120. BiomeBase[] biomes;
    121. try {
    122. biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
    123. } catch (Exception exc) {
    124. // Unable to fetch.
    125. return;
    126. }
    127. for (BiomeBase biomeBase : biomes) {
    128. if (biomeBase == null)
    129. break;
    130.  
    131. // The list fields changed names but update the meta regardless.
    132. for (String field : new String[] { "as", "at", "au", "av" })
    133. try {
    134. Field list = BiomeBase.class.getDeclaredField(field);
    135. list.setAccessible(true);
    136. @SuppressWarnings("unchecked")
    137. List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
    138.  
    139. // Make sure the NMS class is written back over our custom class.
    140. for (BiomeMeta meta : mobList)
    141. for (CustomEntityType entity : values())
    142. if (entity.getCustomClass().equals(meta.b))
    143. meta.b = entity.getNMSClass();
    144. } catch (Exception e) {
    145. e.printStackTrace();
    146. }
    147. }
    148. }
    149.  
    150. /**
    151.   * A convenience method.
    152.   * @param clazz The class.
    153.   * @param f The string representation of the private static field.
    154.   * @return The object found
    155.   * @throws Exception if unable to get the object.
    156.   */
    157. private static Object getPrivateStatic(Class clazz, String f) throws Exception {
    158. Field field = clazz.getDeclaredField(f);
    159. field.setAccessible(true);
    160. return field.get(null);
    161. }
    162.  
    163. /*
    164.   * Since 1.7.2 added a check in their entity registration, simply bypass it and write to the maps ourself.
    165.   */
    166. private static void a(Class paramClass, String paramString, int paramInt) {
    167. try {
    168. ((Map) getPrivateStatic(EntityTypes.class, "c")).put(paramString, paramClass);
    169. ((Map) getPrivateStatic(EntityTypes.class, "d")).put(paramClass, paramString);
    170. ((Map) getPrivateStatic(EntityTypes.class, "e")).put(Integer.valueOf(paramInt), paramClass);
    171. ((Map) getPrivateStatic(EntityTypes.class, "f")).put(paramClass, Integer.valueOf(paramInt));
    172. ((Map) getPrivateStatic(EntityTypes.class, "g")).put(paramString, Integer.valueOf(paramInt));
    173. } catch (Exception exc) {
    174. // Unable to register the new class.
    175. }
    176. }
    177. }


    I threw that together in a hurry so I haven't actually tested it yet but I'd imagine it works. Also added an unregister method so that there are no memory leaks on reloads, etc.
     
    GrandmaJam and Zughy like this.
  19. Offline

    Scyntrus

    TeeePeee
    I prefer to leave out
    Code:java
    1. ((Map) getPrivateStatic(EntityTypes.class, "e")).put(Integer.valueOf(paramInt), paramClass);

    I believe this line of code will make spawn eggs spawn your custom entity instead of the regular one.
     
  20. Offline

    TeeePeee

    Scyntrus
    Clever spot. I didn't delve all too far into the NMS, but the revised code serves its general purpose, albeit unsafely. Then again, is there a safe way to do NMS?
     
  21. Offline

    Zughy

    I updated to 1.7.2 and changed the code with TeeePeee one; now, on the main onEnable generate this
    Code:
    [12:52:57 INFO]: [LoM] Enabling LoM v0.2
    [12:52:57 WARN]: java.lang.reflect.InvocationTargetException
    [12:52:57 WARN]:        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native M
    ethod)
    [12:52:57 WARN]:        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMet
    hodAccessorImpl.java:57)
    [12:52:57 WARN]:        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Deleg
    atingMethodAccessorImpl.java:43)
    [12:52:57 WARN]:        at java.lang.reflect.Method.invoke(Method.java:606)
    [12:52:57 WARN]:        at me.dungeoncraft.lom.LoM.onEnable(LoM.java:49)
    [12:52:57 WARN]:        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlug
    in.java:217)
    [12:52:57 WARN]:        at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(
    JavaPluginLoader.java:457)
    [12:52:57 WARN]:        at org.bukkit.plugin.SimplePluginManager.enablePlugin(Si
    mplePluginManager.java:381)
    [12:52:57 WARN]:        at org.bukkit.craftbukkit.v1_7_R1.CraftServer.loadPlugin
    (CraftServer.java:298)
    [12:52:57 WARN]:        at org.bukkit.craftbukkit.v1_7_R1.CraftServer.enablePlug
    ins(CraftServer.java:280)
    [12:52:57 WARN]:        at org.bukkit.craftbukkit.v1_7_R1.CraftServer.reload(Cra
    ftServer.java:630)
    [12:52:57 WARN]:        at org.bukkit.Bukkit.reload(Bukkit.java:279)
    [12:52:57 WARN]:        at org.bukkit.command.defaults.ReloadCommand.execute(Rel
    oadCommand.java:23)
    [12:52:57 WARN]:        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCo
    mmandMap.java:192)
    [12:52:57 WARN]:        at org.bukkit.craftbukkit.v1_7_R1.CraftServer.dispatchCo
    mmand(CraftServer.java:542)
    [12:52:57 WARN]:        at org.bukkit.craftbukkit.v1_7_R1.CraftServer.dispatchSe
    rverCommand(CraftServer.java:529)
    [12:52:57 WARN]:        at net.minecraft.server.v1_7_R1.DedicatedServer.aw(Dedic
    atedServer.java:286)
    [12:52:57 WARN]:        at net.minecraft.server.v1_7_R1.DedicatedServer.u(Dedica
    tedServer.java:251)
    [12:52:57 WARN]:        at net.minecraft.server.v1_7_R1.MinecraftServer.t(Minecr
    aftServer.java:541)
    [12:52:57 WARN]:        at net.minecraft.server.v1_7_R1.MinecraftServer.run(Mine
    craftServer.java:453)
    [12:52:57 WARN]:        at net.minecraft.server.v1_7_R1.ThreadServerApplication.
    run(SourceFile:617)
    [12:52:57 WARN]: Caused by: java.lang.IllegalArgumentException: ID is already re
    gistered: Zombie
    [12:52:57 WARN]:        at net.minecraft.server.v1_7_R1.EntityTypes.a(SourceFile
    :30)
    [12:52:57 WARN]:        ... 21 more
    telling to me that ID is already registered; is mob ID changed or what?

    the onEnable part is this, the LoM.49 is the 15th one
    Code:java
    1. public void onEnable(){
    2. plugin = this;
    3. settings.setup(this);
    4.  
    5. try{
    6. @SuppressWarnings("rawtypes")
    7. Class[] args = new Class[3];
    8. args[0] = Class.class;
    9. args[1] = String.class;
    10. args[2] = int.class;
    11.  
    12. Method a = net.minecraft.server.v1_7_R1.EntityTypes.class.getDeclaredMethod("a", args);
    13. a.setAccessible(true);
    14.  
    15. a.invoke(a, CustomEntityZombie.class, "Zombie", 54);
    16. }catch (Exception e){
    17. e.printStackTrace();
    18. this.setEnabled(false);
    19. }
    20.  
    21. getCommand("lom").setExecutor(new ReloadCommand(this));
    22. getServer().getPluginManager().registerEvents(new Signs(), this);
    23. if (Bukkit.getServerName().contains("Abisso")){
    24. getServer().getPluginManager().registerEvents(new ChampionSelect(), this);
    25. getServer().getPluginManager().registerEvents(new EventsAbisso(), this);
    26. getServer().getPluginManager().registerEvents(new EntityListener(), this);
    27. au.GenerateArena();
    28. }
    29. getServer().getPluginManager().registerEvents(new Respawn(), this);
    30. }
     
  22. Offline

    RingOfStorms


    Look it up in the mc-dev source. You'll have to go to the spigot repository for the updated version because Bukkit delays their release to ruin "unofficial" builds and "unsupported" practices. But look at the EntityTypes class and at the bottom there should be a list of all the Entities and their ID's.
     
  23. Offline

    Zughy

  24. Offline

    Scyntrus


    Actually, you didn't implement TeeePeee 's code properly. The entire point to his code was to replace the invocation of the EntityTypes.a method with your own method, since the EntityTypes.a method now raises an error. In essence, you are remaking the EntityTypes.a method with the error raising removed. Your code still uses the old EntityTypes.a invocation. Scroll down to the bottom of TeeePeee's code. That last function is the only thing that's important.
     
    Zughy likes this.
  25. Offline

    BungeeTheCookie

    Could this work in 1.7.2?
     
  26. Offline

    MrInspector

    If the code is compatible with the 1.7 build, sure why not, make sure to test it though, it may not cause any errors in the code but may not work when you test it, I haven't tested this yet, I'll use it if I need something. :p
     
  27. Offline

    TeeePeee

  28. Offline

    travelingdp

    Could someone who understands this tutorial please look at This Thread and help me out? I would greatly appreciate it! :)
     
  29. Offline

    EcMiner

    How do i spawn in my custom entity?
     
  30. Offline

    Block34

    Is it normal at the start to get a red line/error on SKELETON even though i imported everything that i can import and i have bukkit and craftbukkit as external jar.
     
Thread Status:
Not open for further replies.

Share This Page