Force zombies to be able to break doors

Discussion in 'Plugin Development' started by kittyPL, Apr 8, 2014.

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

    kittyPL

    Hello!

    As far as I know, since 1.7 not all zombies are able to break doors, only those tagged with "CanBreakDoor".

    I extended EntityZombie to have custom pathfinding along with few other things and now I'm trying to make each ExtendedZombie break doors.

    Here is my code:

    Code:java
    1. public class ExtendedZombie extends EntityZombie {
    2.  
    3. private void setTargets() //Set pathfinding targets
    4. {
    5. try {
    6. Field bField = PathfinderGoalSelector.class.getDeclaredField("b");
    7. bField.setAccessible(true);
    8. Field cField = PathfinderGoalSelector.class.getDeclaredField("c");
    9. cField.setAccessible(true);
    10. bField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
    11. bField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
    12. cField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
    13. cField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
    14.  
    15.  
    16. //These two lines actually should do the job. "bu" is the CanBreakDoor boolean.
    17. setField(EntityZombie.class,"bu",true);
    18. this.goalSelector.a(1, (PathfinderGoalBreakDoor)(getField(EntityZombie.class,"bs")));
    19.  
    20. this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, EntityHuman.class, 1.0D, false));
    21. this.goalSelector.a(5, new PathfinderGoalMoveTowardsRestriction(this, 1.0D));
    22.  
    23. this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, true));
    24. this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityHuman.class, 0, true));
    25.  
    26. } catch (Exception exc) {
    27. exc.printStackTrace();
    28. }
    29. }
    30.  
    31. private void setField(Class<?> clazz, String field, Object obj) //Helper method
    32. {
    33. try
    34. {
    35. Field f = clazz.getDeclaredField(field);
    36. f.setAccessible(true);
    37. f.set(this,obj);
    38. } catch (Exception ex)
    39. {
    40. ex.printStackTrace();
    41. }
    42. }
    43.  
    44. private Object getField(Class<?> clazz, String field) //Helper method
    45. {
    46. try
    47. {
    48. Field f = clazz.getDeclaredField(field);
    49. f.setAccessible(true);
    50. return f.get(this);
    51. } catch (Exception ex)
    52. {
    53. ex.printStackTrace();
    54. }
    55. return null;
    56. }
    57.  
    58. @Override //Called by LoadFromNbt
    59. public void a(boolean flag)
    60. {
    61. System.out.println("FLAG: "+flag); //Debug
    62. if ((boolean)(getField(EntityZombie.class,"bu")) != flag)
    63. {
    64. setField(EntityZombie.class,"bu",flag);
    65. if (flag) {
    66. this.goalSelector.a(1, (PathfinderGoalBreakDoor)(getField(EntityZombie.class,"bs")));
    67. } else {
    68. this.goalSelector.a((PathfinderGoalBreakDoor)(getField(EntityZombie.class,"bs")));
    69. }
    70. }
    71. }
    72.  
    73. public ExtendedZombie(World world)
    74. {
    75. super(world);
    76.  
    77. setField(EntityInsentient.class,"navigation",new NavigationEx(this,world)); //Custom pathfinding, no overrides yet
    78.  
    79. setTargets();
    80. a(true); //Try to make him break blocks
    81. }
    82.  
    83. @Override
    84. public void aC() {
    85. super.aC();
    86. this.getAttributeInstance(GenericAttributes.e).setValue(3D); //Set damage
    87. this.getAttributeInstance(GenericAttributes.a).setValue(40D); //Set HP
    88. this.getAttributeInstance(GenericAttributes.b).setValue(32); //Set view rage
    89. }
    90.  
    91. @SuppressWarnings({ "unchecked", "rawtypes" })
    92. public static void registerMob()
    93. {
    94. //Standard registration of mob
    95. }
    96. }


    Actually, the funny thing is that this code works well when I restart the server. I mean, if I spawn a zombie then he doesn't break doors (although he is using my AI methods and performing good) but when I don't kill him and restart the server (let him get loaded by ChunkLoader, spawned and NbtLoaded, calling a(boolean flag)), he can break the door perfectly as I wish.

    I know this may seem hard, but I'm hope there is anyone who can help me in solving this problem...
     
  2. Offline

    epicfacecreeper

    The BreakDoor goal is probably checking if the zombie has the tag CanBreakDoors. I'm not very familiar with NMS, and I didn't look any of this up, but it seems like the BreakDoor goal caches the CanBreakDoors, and since booleans are not objects, it does not change with the zombie. Try calling a(true) before the setTargets() call. I'll see if I can find anything to back this theory up.

    Actually, if you check the BreakDoor goal source, it checks if the difficulty is on hard. It doesn't make much sense, but it may be your problem.
    Source

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 7, 2016
  3. Offline

    kittyPL

    epicfacecreeper
    Checked it a lot of times, and if it wasn't hard then they wouldn't break doors after restart :)
    Gonna check with a before targets...

    epicfacecreeper
    Nothing has changed. :/

    Furthermore, String ".getBoolean("CanBreakDoors")" is only referenced in EntityZombie, so it cannot check the NBT tags in PathfinderGoal...

    epicfacecreeper
    Okay, after 4 hours I found what was causing the wrong behaveiour.

    I was setting the new Navigation after the super constructor. In EntityZombie.java we have:
    Code:java
    1. public EntityZombie(World world)
    2. {
    3. super(world);
    4. getNavigation().b(true); //NOTICE!!!
    5. this.goalSelector.a(0, new PathfinderGoalFloat(this));
    6. this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, EntityHuman.class, 1.0D, false));
    7. //More goals, blah blah
    8. }


    getNavigation().b(true) allows pathfinding to cross the doors >.<

    Calling it before setTargets() did the job.
    Finally, my code looks like before, except for the constructor:
    Code:java
    1. public ExtendedZombie(World world)
    2. {
    3. super(world);
    4.  
    5. setField(EntityInsentient.class,"navigation",new NavigationEx(this,world));
    6. this.getNavigation().b(true);
    7.  
    8. setTargets();
    9.  
    10. a(true);
    11. }


    Thanks for your interest!!!

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 7, 2016
Thread Status:
Not open for further replies.

Share This Page