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

    RingOfStorms

    I would go about it by making custom pathfindergoals. Possibly a custom one that moves the mobs toward a certain goal/block. And then another one that breaks it. You may want to look at the PathfinderGoalEatTile which is what sheep use to eat grass, and then possibly look at other goals for the movement since there are lots. But i'm guessing the eat tile is the closest to breaking a block, as it does change a block.
     
  2. Offline

    hawkfalcon

    Oh okay. So I would use this.
     
  3. Offline

    RingOfStorms

    Start with that, I am not gonna read through all of it, but not sure if that checks for "door durability" as it normally takes them a few hits. So if you copy/paste that class im guessing you'll need to change a few things for it to work with a block instead of a door. But yea something along those lines.
     
    hawkfalcon likes this.
  4. Offline

    Kazzababe

    Is there a way to figure out which method is which? Every time I get the method I want, the next update changes it and I end up trying every method until I get what I need.
     
  5. Offline

    Jacek

    Look at the code of each one and see which has the logic you expect, that's how I do it anyway.
     
    Kazzababe likes this.
  6. Offline

    xGamingDudex

    When I reload or start/stop the server it says in the console:
    Code:
    21:17:53 [SEVERE] java.lang.NoSuchMethodException: me.xADudex.McCoC.Mobs.CustomBat.<init>(net.minecraft.server.v1_5_R3.World)
    21:17:53 [SEVERE]    at java.lang.Class.getConstructor0(Class.java:2706)
    21:17:53 [SEVERE]    at java.lang.Class.getConstructor(Class.java:1657)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.EntityTypes.a(SourceFile:140)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.ChunkRegionLoader.loadEntities(ChunkRegionLoader.java:352)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.ChunkRegionLoader.a(ChunkRegionLoader.java:49)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.ChunkProviderServer.loadChunk(ChunkProviderServer.java:176)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.ChunkProviderServer.getChunkAt(ChunkProviderServer.java:105)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.ChunkProviderServer.getChunkAt(ChunkProviderServer.java:84)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.MinecraftServer.e(MinecraftServer.java:278)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.MinecraftServer.a(MinecraftServer.java:243)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.DedicatedServer.init(DedicatedServer.java:151)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.MinecraftServer.run(MinecraftServer.java:382)
    21:17:53 [SEVERE]    at net.minecraft.server.v1_5_R3.ThreadServerApplication.run(SourceFile:573)
    21:17:53 [WARNING] Skipping Entity with id CustomBat
    I have tried quite a bit like set the "Load: Startup" in the plugin.yml, also added this on load:
    Code:
    public void setupMobs(){
            try{
                    @SuppressWarnings("rawtypes")
                    Class[] args = new Class[3];
                    args[0] = Class.class;
                    args[1] = String.class;
                    args[2] = int.class;
                   
                    Method a = net.minecraft.server.v1_5_R3.EntityTypes.class.getDeclaredMethod("a", args);
                    a.setAccessible(true);
                    a.invoke(net.minecraft.server.v1_5_R3.EntityTypes.class, CustomBat.class, "CustomBat", 65);
     
                   
                }catch (Exception e){
                    e.printStackTrace();
                    this.setEnabled(false);
                }
        }
    Also tried adding this in the CustomBat class:
    Code:
    /*
        * Save NBT data
        */
       
        @SuppressWarnings("deprecation")
        @Override
        public void b(NBTTagCompound nbttagcompound) {
            super.b(nbttagcompound);
            nbttagcompound.setString("buildingType", type.name());
            nbttagcompound.setInt("level", level);
            nbttagcompound.setBoolean("upgrading", upgrading);
            for(int i = 0; i < blocks.size(); i++){
                nbttagcompound.setInt("Block" + i + "X", blocks.get(i).getBlockX());
                nbttagcompound.setInt("Block" + i + "Y", blocks.get(i).getBlockY());
                nbttagcompound.setInt("Block" + i + "Z", blocks.get(i).getBlockZ());
            }
        }
     
        /*
        * Load NBT data
        */
       
        @SuppressWarnings("deprecation")
        @Override
        public void a(NBTTagCompound nbttagcompound) {
            super.a(nbttagcompound);
            type = BuildingType.valueOf(nbttagcompound.getString("buildingType"));
            level = nbttagcompound.getInt("level");
            upgrading = nbttagcompound.getBoolean("upgrading");
                blocks = new ArrayList<Location>();
                for(int i = 0; i > -1; i++){
                    if(nbttagcompound.hasKey("Block" + i + "X")){
                        int x = nbttagcompound.getInt("Block" + i + "X");
                        int y = nbttagcompound.getInt("Block" + i + "Y");
                        int z = nbttagcompound.getInt("Block" + i + "Z");
                        blocks.add(world.getWorld().getBlockAt(x, y, z).getLocation());
                    } else break;
            }
           
        }
    Which loads and saves all the variables in the custom bat. Also the custom mobs stays functional after reload but is I can't recognize them in any way, like world.getEntities() and then check if it is a bat and then try
    Code:
    if(bat instanceof CustomBat){
    //    Do Stuff
    }
    But it works before reload


    Any help please
     
  7. Offline

    Jacek

    xGamingDudex Looks like you've changed the constructor of the entity class, you can't do that :p
     
  8. Offline

    xGamingDudex

    Thanks so much, now after tweaking the constructor and the NBT load and save it seams to work perfectly :D
     
    Jacek likes this.
  9. Offline

    Jamesthatguy

    Any chance of this being updated?
     
  10. Offline

    Regenwurm97

    Hey,




    I don't understand what the "super" Thing is (never heard about it before and can't understand other users comments on this question in other Forums)...

    So first of all: What does this thing here do?


    Code:
    public BloodMoonEntityZombie(World world) {
     
     
          super(world);
     
    }
     
    
    It seems like you'd set the world from the constructor to a pre-variable (like "this."...dont know how this is called :D)
    But you never defined it :l so what does "super(world)" actually do?

    The next Thing I wanted to know is what this does:
    Code:
    super.s_();
    is "super" a class now and if yes, which is it? and from where do you know what ".s_()" means? is there a list?

    Hope you can help me :D
    BTW: Good tutorial unless could be updated a bit :)
     
  11. Offline

    Jacek

    No, you should be able to work out the new method names from the source or from BloodMoon.

    Regenwurm97 super(world); is calling the constructor from the parent class, in this case it's EntityZombie. A bit of set-up stuff is done there so we need to call it for our entity too.

    super.s_(); is a bit like doing this.s_();, the only difference is that super refers to the parent class instead of the current one. So super.s_() will call EntityZombie.s_() and this.s_() will call BloodMoonEntityZombie.s_()

    There is no documentation for the methods that I know of, you can try MCP but honestly it's easier to work it out from the source.
     
  12. Offline

    Regenwurm97

    Hey again!
    Thx I understand it now :D

    Yeah I already thought I had to search on my own for the method names :l I just have 1 more question: I'm trying to make a Entity out of an Item. So, my goal is to make ghast tears throwable and so I wanted to set the velocity and / or physics from a snowball to it... Is there any Chance to do this with bukkit?

    There is a Server called "MC Headshot" which made potatos throwable so they can be used as grenades (they also bounce when hitting the floor ;D). I tried to figgure out how this works but cant find a way
     
  13. Offline

    Jacek

    Regenwurm97 I'm pretty sure you can .setVelocity() on an ItemStack
     
  14. Offline

    RingOfStorms

    I think it is an Item not ItemStack
     
    bobacadodl likes this.
  15. Offline

    SgtPunishment

    Okay, I have two questions...

    1. How am I able to place multiple new blocks into a config file for zombies to break
    2. How can I say extend a skeleton class but make it look / sound like a Zombie Pigman with a bow?
     
  16. Offline

    SgtPunishment

  17. Offline

    RingOfStorms

    1. Make a custom zombie and add a custom pathfinder goal to break the blocks you want (Look at how the breakdoor one works).
    2. Extend a pigman, give it the same properties as a skeleton, and just equip a bow to it.
     
  18. Offline

    SgtPunishment

    I've done as you've said RingOfStorms

    EDIT: I got it working... only problem is now that all the Archer Pig Zombies are zipping around like crazy fast, and I don't know how to fix it

    Code:java
    1. import java.lang.reflect.Field;
    2.  
    3. import org.bukkit.craftbukkit.v1_6_R2.util.UnsafeList;
    4. import org.bukkit.enchantments.Enchantment;
    5.  
    6. import net.minecraft.server.v1_6_R2.AchievementList;
    7. import net.minecraft.server.v1_6_R2.DamageSource;
    8. import net.minecraft.server.v1_6_R2.EnchantmentManager;
    9. import net.minecraft.server.v1_6_R2.EntityArrow;
    10. import net.minecraft.server.v1_6_R2.EntityCreature;
    11. import net.minecraft.server.v1_6_R2.EntityHuman;
    12. import net.minecraft.server.v1_6_R2.EntityLiving;
    13. import net.minecraft.server.v1_6_R2.EntityPigZombie;
    14. import net.minecraft.server.v1_6_R2.EnumMonsterType;
    15. import net.minecraft.server.v1_6_R2.GenericAttributes;
    16. import net.minecraft.server.v1_6_R2.IRangedEntity;
    17. import net.minecraft.server.v1_6_R2.Item;
    18. import net.minecraft.server.v1_6_R2.ItemStack;
    19. import net.minecraft.server.v1_6_R2.MathHelper;
    20. import net.minecraft.server.v1_6_R2.PathfinderGoal;
    21. import net.minecraft.server.v1_6_R2.PathfinderGoalArrowAttack;
    22. import net.minecraft.server.v1_6_R2.PathfinderGoalFleeSun;
    23. import net.minecraft.server.v1_6_R2.PathfinderGoalFloat;
    24. import net.minecraft.server.v1_6_R2.PathfinderGoalHurtByTarget;
    25. import net.minecraft.server.v1_6_R2.PathfinderGoalLookAtPlayer;
    26. import net.minecraft.server.v1_6_R2.PathfinderGoalMeleeAttack;
    27. import net.minecraft.server.v1_6_R2.PathfinderGoalNearestAttackableTarget;
    28. import net.minecraft.server.v1_6_R2.PathfinderGoalRandomLookaround;
    29. import net.minecraft.server.v1_6_R2.PathfinderGoalRandomStroll;
    30. import net.minecraft.server.v1_6_R2.PathfinderGoalRestrictSun;
    31. import net.minecraft.server.v1_6_R2.PathfinderGoalSelector;
    32. import net.minecraft.server.v1_6_R2.Statistic;
    33. import net.minecraft.server.v1_6_R2.World;
    34.  
    35. public class UberPigZombieArcher extends EntityPigZombie implements
    36. IRangedEntity {
    37.  
    38. private PathfinderGoalArrowAttack bp = new PathfinderGoalArrowAttack(this,
    39. 1.0D, 20, 60, 15.0F);
    40. private PathfinderGoalMeleeAttack bq = new PathfinderGoalMeleeAttack(this,
    41. EntityHuman.class, 1.2D, false);
    42.  
    43. public UberPigZombieArcher(World world) {
    44. super(world);
    45. this.fireProof = true;
    46. try {
    47. Field gsa = PathfinderGoalSelector.class.getDeclaredField("a");
    48. gsa.setAccessible(true);
    49.  
    50. gsa.set(this.goalSelector, new UnsafeList<PathfinderGoalSelector>());
    51. } catch (SecurityException e) {
    52. e.printStackTrace();
    53. } catch (NoSuchFieldException e) {
    54. e.printStackTrace();
    55. e.printStackTrace();
    56. } catch (IllegalAccessException e) {
    57. e.printStackTrace();
    58. }
    59. this.goalSelector.a(1, new PathfinderGoalFloat(this));
    60. this.goalSelector.a(2, new PathfinderGoalRestrictSun(this));
    61. this.goalSelector.a(3, new PathfinderGoalFleeSun(this, 1.0D));
    62. this.goalSelector.a(5, new PathfinderGoalRandomStroll(this, 1.0D));
    63. this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this,EntityHuman.class, 8.0F));
    64. this.goalSelector.a(6, new PathfinderGoalRandomLookaround(this));
    65. this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, false));
    66. this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityHuman.class, 0, true));
    67. if (world != null && !world.isStatic) {
    68. this.bT();
    69. }
    70. }
    71.  
    72. @Override
    73. protected void ay() {
    74. super.ay();
    75. this.getAttributeInstance(GenericAttributes.a).setValue(25.0D);
    76. this.getAttributeInstance(GenericAttributes.b).setValue(64.0D);
    77. this.getAttributeInstance(GenericAttributes.e).setValue(7.0D);
    78. }
    79.  
    80. @Override
    81. public boolean be() {
    82. return true;
    83. }
    84.  
    85. @Override
    86. protected String r() {
    87. return "mob.zombiepig.zpig";
    88. }
    89.  
    90. @Override
    91. protected String aN() {
    92. return "mob.zombiepig.zpighurt";
    93. }
    94.  
    95. @Override
    96. protected String aO() {
    97. return "mob.zombiepig.zpigdeath";
    98. }
    99.  
    100. @Override
    101. protected void a(int i, int j, int k, int l) {
    102. this.makeSound("mob.zombie.step", 0.15F, 1.0F);
    103. }
    104.  
    105. @Override
    106. public EnumMonsterType getMonsterType() {
    107. return EnumMonsterType.UNDEAD;
    108. }
    109.  
    110. @Override
    111. public void c() {
    112. if (this.world.v() && !this.world.isStatic) {
    113. float f = this.d(1.0F);
    114.  
    115. if (f > 0.5F
    116. && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F
    117. && this.world.l(MathHelper.floor(this.locX),
    118. MathHelper.floor(this.locY),
    119. MathHelper.floor(this.locZ))) {
    120. boolean flag = true;
    121. ItemStack itemstack = this.getEquipment(4);
    122.  
    123. if (itemstack != null) {
    124. if (itemstack.g()) {
    125. itemstack.setData(itemstack.j()
    126. + this.random.nextInt(2));
    127. if (itemstack.j() >= itemstack.l()) {
    128. this.a(itemstack);
    129. this.setEquipment(4, (ItemStack) null);
    130. }
    131. }
    132.  
    133. flag = false;
    134. }
    135.  
    136. if (flag) {
    137. this.setOnFire(8);
    138. }
    139. }
    140. }
    141.  
    142.  
    143. super.c();
    144. }
    145.  
    146. @Override
    147. public void U() {
    148. super.U();
    149. if (this.vehicle instanceof EntityCreature) {
    150. EntityCreature entitycreature = (EntityCreature) this.vehicle;
    151.  
    152. this.aN = entitycreature.aN;
    153. }
    154. }
    155.  
    156. @Override
    157. public void die(DamageSource damagesource) {
    158. super.die(damagesource);
    159. if (damagesource.h() instanceof EntityArrow
    160. && damagesource.getEntity() instanceof EntityHuman) {
    161. EntityHuman entityhuman = (EntityHuman) damagesource.getEntity();
    162. double d0 = entityhuman.locX - this.locX;
    163. double d1 = entityhuman.locZ - this.locZ;
    164.  
    165. if (d0 * d0 + d1 * d1 >= 2500.0D) {
    166. entityhuman.a((Statistic) AchievementList.v);
    167. }
    168. }
    169. }
    170.  
    171. @Override
    172. protected void dropDeathLoot(boolean flag, int i) {
    173. int j = this.random.nextInt(2 + i);
    174.  
    175. int k;
    176.  
    177. for (k = 0; k < j; ++k) {
    178. this.b(Item.ROTTEN_FLESH.id, 1);
    179. }
    180.  
    181. j = this.random.nextInt(2 + i);
    182.  
    183. for (k = 0; k < j; ++k) {
    184. this.b(Item.GOLD_NUGGET.id, 1);
    185. }
    186. }
    187.  
    188. @Override
    189. public boolean a(EntityHuman entityhuman) {
    190. return false;
    191. }
    192.  
    193. @Override
    194. protected int getLootId() {
    195. return Item.ROTTEN_FLESH.id;
    196. }
    197.  
    198. @Override
    199. protected void bw() {
    200. super.bw();
    201. this.setEquipment(0, new ItemStack(Item.BOW));
    202. }
    203.  
    204. public void bT() {
    205. this.goalSelector.a((PathfinderGoal) this.bq);
    206. this.goalSelector.a((PathfinderGoal) this.bp);
    207. ItemStack itemstack = this.aY();
    208.  
    209. if (itemstack != null && itemstack.id == Item.BOW.id) {
    210. this.goalSelector.a(4, this.bp);
    211. } else {
    212. this.goalSelector.a(4, this.bq);
    213. }
    214. }
    215.  
    216. @Override
    217. public void a(EntityLiving entityliving, float f) {
    218. EntityArrow entityarrow = new EntityArrow(this.world, this,
    219. entityliving, 1.6F, (float) (14 - this.world.difficulty * 4));
    220. int i = EnchantmentManager.getEnchantmentLevel(
    221. Enchantment.ARROW_DAMAGE.getId(), this.aY());
    222. int j = EnchantmentManager.getEnchantmentLevel(
    223. Enchantment.ARROW_KNOCKBACK.getId(), this.aY());
    224.  
    225. entityarrow.b((double) (f * 2.0F) + this.random.nextGaussian() * 0.25D
    226. + (double) ((float) this.world.difficulty * 0.11F));
    227. if (i > 0) {
    228. entityarrow.b(entityarrow.c() + (double) i * 0.5D + 0.5D);
    229. }
    230.  
    231. if (j > 0) {
    232. entityarrow.a(j);
    233. }
    234.  
    235. if (EnchantmentManager.getEnchantmentLevel(
    236. Enchantment.ARROW_FIRE.getId(), this.aY()) > 0) {
    237. entityarrow.setOnFire(100);
    238. }
    239.  
    240. this.makeSound("random.bow", 1.0F,
    241. 1.0F / (this.aC().nextFloat() * 0.4F + 0.8F));
    242. this.world.addEntity(entityarrow);
    243. }
    244.  
    245.  
    246. @Override
    247. public void setEquipment(int i, ItemStack itemstack) {
    248. super.setEquipment(i, itemstack);
    249. if (!this.world.isStatic && i == 0) {
    250. this.bT();
    251. }
    252. }
    253.  
    254. @Override
    255. public double W() {
    256. return super.W() - 0.5D;
    257. }
    258.  
    259. }
     
  19. Offline

    TomTheDeveloper

    SgtPunishment

    Hey, I tried to make custom zombies, a few months ago, I got it to work, but now I can't figure out what I am doing wrong. So I copied your class, and spawned an Zombie myself

    Code:java
    1. @EventHandler
    2. public void spawningZomb(PlayerInteractEvent e){
    3. if (e.getAction() == Action.PHYSICAL){
    4. CraftWorld world = (CraftWorld) e.getPlayer().getWorld();
    5. net.minecraft.server.v1_6_R2.World McWorld = world.getHandle();
    6. UberPigZombieArcher zombie = new UberPigZombieArcher(McWorld);
    7. Location location = e.getPlayer().getLocation();
    8. zombie.setPosition(location.getX(), location.getY(), location.getZ());
    9. McWorld.addEntity(zombie, SpawnReason.CUSTOM);
    10. }
    11. }


    Sadly it crashed my minecraft, everytime when I try to spawn someone. Why does it work when you do it, and when I try it, it fails :(

    To slow the zombie, I think you just need to do this
    Code:java
    1. private PathfinderGoalMeleeAttack bq = new PathfinderGoalMeleeAttack(this,
    2. EntityHuman.class, 1.2D, false);


    Change that 1.2D to 1.0D

    Nevermind, I found out what was wrong with it, I forgot to put someting in the onenable method :), It works now :)

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 23, 2016
  20. Offline

    StrangeOne101

    Why don't I have the packages? Anything under net.minecraft.server isn't there?
     
  21. Offline

    SgtPunishment

    StrangeOne101 you need to reference craftbukkit in your build path, but make sure it's above bukkit
     
  22. Offline

    RingOfStorms

    You need to reference CraftBukkit, and you should not put it above bukkit. Bukkit should be the highest priority. As long as you have the CraftBukkit reference your IDE will pick it up.
     
  23. Offline

    TomTheDeveloper

    In 1.5 you could increase the pathfinding range of a zombie with
    Code:
    this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityHuman.class, 100.0F, 0, true));
    (100.0F is the pathfinding range)
    But now they removed the 100.0F, does someone know how I can increase the pathfinding range in 1.6.2?
     
  24. Offline

    RingOfStorms

    You can change things like that in the new attribute system.
     
  25. Offline

    Elimnator

    Jacek
    I have a class like this:
    Code:
    public class BloodMoonEntityZombie extends net.minecraft.server.EntityZombie {
     
    public BloodMoonEntityZombie(World world) {
    super(world);
    }
    }
    
    And it says "net cannot be resolved to a type".
     
  26. Offline

    Jacek

    Elimnator Use the right package name for the current version and make sure you have CratBukkit on your build path.
     
  27. Offline

    Elimnator

    Jacek
    I have bukkit on my build path, do I need craft-bukkit?
     
  28. Offline

    Jacek

    "make sure you have CratBukkit on your build path."
     
  29. Offline

    Elimnator

    Jacek
    OK, I am trying to change a creeper not a zombie, and it says:
    "The method s_() of type trampling_creeper must override or implement a supertype method"
    What dose that mean?
     
  30. Offline

    Jacek

    Elimnator You need to use the right method name as mentioned in the post.
     
Thread Status:
Not open for further replies.

Share This Page