Solved NMS mob stop walking towards target so that it can target an entity?

Discussion in 'Plugin Development' started by Gamesareme, Sep 26, 2014.

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

    Gamesareme

    I am making a plugin that spawns mobs, and they move towards a target. I am able to do this well. The problem I am having is making that mob stop walking to the target, so that is it can kill another entity. Then the mob resumes its walk towards the set target. I am having a problem where the mob just walks past the entities I want it to attack. Can someone help?
     
  2. Offline

    AlphaRLee

    Gamesareme can you post your code? It makes it a lot easier...

    I'm a newbie to NMS coding, but I have a basic gist of it...I can make my entites walk to a specific spot too, using pathFinders, but my entities always prioritize attacking over walking to their spot. If you are using pathfinders, maybe try reorganizing them?
     
  3. Offline

    Gamesareme

    AlphaRLee ok this is what I have. I do no believe that I am using a path finder so that may be why. I am using a built in function which I have modified.
    Here is my code.
    This is what sets the target.
    Code:java
    1. import net.minecraft.server.v1_7_R3.EntityCreature;
    2. import net.minecraft.server.v1_7_R3.PathfinderGoal;
    3.  
    4. public class PathfinderGoalWalktoTile extends PathfinderGoal{
    5.  
    6. float speed;
    7. private EntityCreature entitycreature;
    8. public PathfinderGoalWalktoTile(EntityCreature entitycreature, float speed){
    9. this.speed = speed;
    10. this.entitycreature = entitycreature;
    11. }
    12.  
    13.  
    14. @Override
    15. public boolean a() {
    16. return true;
    17. }
    18.  
    19. @Override
    20. public void e(){
    21. this.entitycreature.getNavigation().a(60, 60, 100, speed);
    22. }
    23.  
    24. }

    This is what calls the code above.
    Code:java
    1. import java.lang.reflect.Field;
    2.  
    3. import net.minecraft.server.v1_7_R3.EntityPig;
    4. import net.minecraft.server.v1_7_R3.EntitySkeleton;
    5. import net.minecraft.server.v1_7_R3.EntityZombie;
    6. import net.minecraft.server.v1_7_R3.PathfinderGoalFloat;
    7. import net.minecraft.server.v1_7_R3.PathfinderGoalHurtByTarget;
    8. import net.minecraft.server.v1_7_R3.PathfinderGoalMeleeAttack;
    9. import net.minecraft.server.v1_7_R3.PathfinderGoalNearestAttackableTarget;
    10. import net.minecraft.server.v1_7_R3.PathfinderGoalSelector;
    11. import net.minecraft.server.v1_7_R3.World;
    12.  
    13. import org.bukkit.craftbukkit.v1_7_R3.util.UnsafeList;
    14.  
    15. public class CustomEntityZombie extends EntityZombie {
    16.  
    17. public CustomEntityZombie(World world) {
    18. super(world);
    19. try {
    20. Field bField = PathfinderGoalSelector.class.getDeclaredField("b");
    21. bField.setAccessible(true);
    22. Field cField = PathfinderGoalSelector.class.getDeclaredField("c");
    23. cField.setAccessible(true);
    24. bField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
    25. bField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
    26. cField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
    27. cField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
    28. } catch (Exception exc) {
    29. exc.printStackTrace();
    30. }
    31. this.goalSelector.a(0, new PathfinderGoalFloat(this));
    32. this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this,EntityPig.class, 1.0D, false));
    33. this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this,EntitySkeleton.class, 1.0D, true));
    34. this.goalSelector.a(4, new PathfinderGoalWalktoTile(this, (float) 1.0));
    35. this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, true));
    36. this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityPig.class, 0, true));
    37. this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget(this, EntitySkeleton.class, 0, false));
    38. }
    39. }

    This probably does not make sense to you. If that is the case, I would apriciate if you could explain what you did. :)
    Cheers
     
  4. Offline

    fireblast709

    Gamesareme Why not use the Bukkit API? The classes EntityTargetEvent and EntityTargetLivingEntityEvent exist for a reason.
     
  5. Offline

    Gamesareme

    fireblast709 Correct me if I am wrong, but don't they have a target radius. I need so the mobs can be anywhere in the world.
     
  6. Offline

    fireblast709

    Gamesareme
    • What good would that do? (Aside that it could lag/crash your server due to massive path algorithms)
    • You can use reflection to alter this attribute (or in the case of publicly accessible fields - which includes this one iirc). Aside that this is still accessing NMS (due to obfuscation, code cannot be written 100% failsafe), you don't have to create a custom entity
     
  7. Offline

    Gamesareme

    fireblast709 I will see if what AlphaRLee has is going to work. If not I will try looking into that. (I am slightly confused by what you are saying though)
     
  8. Offline

    Gamesareme

  9. Offline

    xTrollxDudex

    This is not difficult: Prevent EntityTargetEvent, target should be added to HashMap with UUID of targeting and the targeted entities. Check Map each time fired.
     
  10. Offline

    Gamesareme

    xTrollxDudex I will try that. The Current problem I am having is stoping the mob moving to wards a location I have set. (See code above) The mob seams to target the entity, because it looks at it as it walks by, but it does not stop its walk and target the entity. Can you help me at all?
     
  11. Offline

    xTrollxDudex

    Again, I have no idea why you would want to use NMS for this. Using the API methods like Entity#setTarget(...) (hint hint) and EntityTargetEvent to prevent distractions should work fine.
     
  12. Offline

    Gamesareme

    xTrollxDudex Ok, I will try what you said. Just a quick question. I will have to set the target as an entity right? Or does it work for locations as well?
     
  13. Offline

    xTrollxDudex

    You probably will have to.
     
  14. Offline

    AlphaRLee

    Gamesareme I know there has been issues with the Bukkit API EntityTargetEvent and EntityTargetLivingEntityEvent. The events fire beautifully, but in my case, when I tried to set the target to be null (cancel 2 entities from trying to kill each other), the entities continue with their former target.

    For your pathfinder, I noticed that you always have it set to true. This will make the entity always want to move to the coordinates specified. Try adding these few things into your code (hopefully this will work, this is untested code):

    1. (You have already completed this step) Get an object of the entity that calls this pathfinder.

    2. Add this variable to your zombie class, near the beginning. You will use this to check if the entity should walk to the tile or not:
    Code:java
    1. public boolean willWalkToTile = true;


    3. Edit your method "a" in your pathfinder to check if the entity should walk to the tile or not:
    Code:java
    1. @Override
    2. public boolean a(){
    3. //Check if this a custom zombie using this pathfinder
    4. if (this.entitycreature instanceof CustomEntityZombie) {
    5. //Return whether or not it should walk to the tile
    6. try {
    7. return ((CustomEntityZombie) entitycreature).willWalkToTile;
    8. }
    9. catch (NullPointerException exception) {
    10. //This is some unexpected error I hope you don't get.
    11. //Send a message to you with some info so you can debug if this error pops up
    12. }
    13. return false; //This should never occur unless if there was an error
    14. }
    15. }
    16. }


    4. Set the value of willWalkToTile to false every time the zombie spots a target. Put this method in your eventListener class
    Code:java
    1. @Eventhandler
    2. public void onTargetEntity(EntityTargetLivingEntity event) {
    3.  
    4. Entity selectingEntity = event.getEntity();
    5. Entity targetedEntity = event.getTarget();
    6.  
    7. //Check to see if selecting entity is a zombie
    8. if (selectingEntity.getType().equals(EntityType.ZOMBIE)) {
    9.  
    10. //Check to see if target is still alive. I can't remember the actual method name, look for the documentation if I'm wrong
    11. if (targetedEntity.isLiving()) {
    12. //This is the part you need to do on your own. I don't know how to make a bukkit entity into its NMS form
    13. ((CustomEntityZombie) selectingEntity).willWalkToTile = false;
    14. }
    15. else {
    16. //This is the part you need to do on your own. I don't know how to make a bukkit entity into its NMS form
    17. ((CustomEntityZombie) selectingEntity).willWalkToTile = true;
    18. }
    19. }

    I'm not sure if this will work perfectly, but I hope this helps!
     
  15. Offline

    Gamesareme

    AlphaRLee I am trying your sugestion now, but I am stuck on a bit of your code. What is "selectingTarget"?
     
  16. Offline

    AlphaRLee

    Gamesareme selectingTarget is my own definition. It's the entity that selects a target. Look at line 4
     
  17. Offline

    Gamesareme

    AlphaRLee Thanks but I worked it out. You named the Entity on line 4 "selectingEntity" I was confused because you later called it "selectingTarget." That is all worked out now, but I am having trouble casting. I have done it in the past, but I have completely forgotten how to do it. Oh well, I guess I have some researching to do. :p

    Ok I can now cast and axis the function. There is a problem though. The listener will only be called when the zombie targets an entity. That means that the target will never be dead, because there is always a new target every time the listener is is called. That means walk to target will never be set to true. How would you fix this?

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

    AlphaRLee

    Hmm...I thought that the eventlistener listened for when both the target was selected and deselected. Apparently not. Probably the second best thing (but this might be more computer intensive the more intense it gets) is to get a listener for a mob death event. If a mob dies, and if the killer is a custom zombie (just zombie in your case), then set the value to true for your zombie...hopefully that works.
     
  19. Offline

    Gamesareme

    AlphaRLee Well I really am stupid. This is the solution that I came up with.
    Just put this in the a() function.
    Code:java
    1. @Override
    2. public boolean a() {
    3. if(this.entitycreature instanceof CustomEntityZombie){
    4. if(this.entitycreature.target == null){
    5. return true;
    6. }
    7. if(this.entitycreature.target !=null && this.entitycreature.target.isAlive() == false){
    8. return true;
    9. }else{
    10. return false;
    11. }
    12. }
    13. return false;
    14. }
     
  20. Offline

    AlphaRLee

    Gamesareme Haha, lol. Yeah, I rarely think about methods like that in the NMS sense. I use Bukkit as much as possible and ignore simple NMS solutions, oops.

    Now I got a challenge for you, seeing I need help in it (probs should go in a new forum). You made a zombie attack a skeleton, how do you get a zombie to attack a zombie, or a skeleton attack a skeleton? Hopefully, there's a simple solution...
     
  21. Offline

    Gamesareme

    AlphaRLee Well I worked it out. You need to add this to your CustomEntityZombie code. (Or what you named the class with your custom entity)
    Code:
    this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, EntityZombie.class, 1.0D, false));
    this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityZombie.class, 0, true));
    I spawned a lot of zombies to see if it worked. I did, and I had a little laugh.
    Any way, hope that helps you.
     
  22. Offline

    AlphaRLee

    Gamesareme What the. No way, they actually can attack their own type without them trying to commit suicide or crash.

    I'm creating a custom pathfinder, it looks very similar to the PathfinderGoalNearestAttackableTarget, but it adds a test to see if a custom variable called "team" matches or not. I guess I just have a typo on my side...
     
  23. Offline

    Gamesareme

    AlphaRLee Great well if you need any more help, ask me, and I will see if I can do anything. :) Thanks again for your help as well.
     
  24. Offline

    AlphaRLee

    Gamesareme do you know what the numbering system is for attack priority? Right after the selector.a( appears a number, and it seems that it dictates priority. But do you know what the order is?
     
  25. Offline

    Gamesareme

    AlphaRLee I have looked into that, but I have not been able to work it out. the best I came up with is that the lower the number the more likely it is have priority over other things. If you find out, could you tell me?
     
  26. Offline

    AlphaRLee

    Yeah, I guess that would make the most sense. I used to think it went the opposite way around, but your idea makes the most sense. I need to make dynamic orderings for my plugin...so somehow, I need to be able to remove the pathfinder list and reload it in a new order. I'll see what I can do...

    Gamesareme More fun...I need my zombies to not reassign thier targets and start hunting whoever just hurt a neighbouring zombie (because I have teams of zombies, and if one hurts an enemy, the attacker's ally would suddenly turn on him)...oddly enough, there is nothing in the damageEntity class that assign currently existing zombie's target, unlike zombie pigmen...

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

    Gamesareme

    AlphaRLee I do not have this problem. I also have two teams of zombies, but the teamed zombies do not attack each other. If you are not doing the same thing, try making two customentityZombies. It is a little more work, but it allows a lot more control over what the zombies do.
     
  28. Offline

    AlphaRLee

    Gamesareme Heh, that's odd, I already have customEntityZombies...I use strings to determine the teams. I also use a custom pathfinder that basically scans if the team string matches between entities and cancels the nearestAttackableEnemy (just a modified version of nearestAttackableTarget). What happens is I pit 3 zombies in an area, 2 of them are on a team, the last one tries to kill the nearest zombie. If one of the teammates attack the odd one out, then his teammate will turn on him.

    Can you either tell me what you did or test your zombie teams to see if you can get one to attack a zombie?
     
  29. Offline

    Gamesareme

    AlphaRLee I have made so they do not target zombies, but rather they target my custom entities. The best way I came up with to fix the problem is to have a customEntityZombieRed, and a customEntityZombieBlue. Then just make so they target the other team, rather than the EntityZombie.class. Hope that helps. :)
     
  30. Offline

    AlphaRLee

    Hmm...interesting solution. It sounds good, but I want to be able to have arbitrary teams, like ones based on usernames...Idk, maybe I can make more zombie classes inherit my custom zombie class? I'll have to look around. But that's a great answer...
     
Thread Status:
Not open for further replies.

Share This Page