Best way of changing mob's move speed

Discussion in 'Plugin Development' started by Darkman2412, Mar 15, 2012.

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

    Darkman2412

    Hi!

    What would be the best way to change a zombie's move speed? I already tried extending the net.minecraft.server.EntityZombie class, but when I spawn the entity (with craftworld.addEntity(...)), I get this error:
    Code:
    2012-03-14 22:25:30 [SEVERE] null
    org.bukkit.command.CommandException: Unhandled exception executing command 'lol' in plugin VideoDemortuos v0.1-ALPHA
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:42)
        ...
    Caused by: java.lang.NullPointerException
        at net.minecraft.server.EntityTypes.a(SourceFile:138)
        at net.minecraft.server.Packet24MobSpawn.<init>(SourceFile:25)
        at net.minecraft.server.EntityTrackerEntry.b(EntityTrackerEntry.java:310)
        at net.minecraft.server.EntityTrackerEntry.updatePlayer(EntityTrackerEntry.java:229)
        at net.minecraft.server.EntityTrackerEntry.scanPlayers(EntityTrackerEntry.java:270)
        at net.minecraft.server.EntityTracker.addEntity(EntityTracker.java:99)
        at net.minecraft.server.EntityTracker.track(EntityTracker.java:65)
        at net.minecraft.server.WorldManager.a(WorldManager.java:16)
        at net.minecraft.server.World.c(World.java:922)
        at net.minecraft.server.WorldServer.c(WorldServer.java:171)
        at net.minecraft.server.World.addEntity(World.java:915)
        at net.minecraft.server.World.addEntity(World.java:866)
        at me.darkman2412.vd.plugin.MainPlugin.onCommand(MainPlugin.java:26)
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:40)
        ... 14 more
    This is the code I found at line 138 of EntityTypes (which isn't on CB's github and not with the same name in MCP):
    Code:java
    1. public static int a(Entity paramEntity) {
    2. return ((Integer)e.get(paramEntity.getClass())).intValue(); // error here
    3. }


    This is the FastZombie class:
    Code:java
    1. public class FastZombie extends EntityZombie {
    2. public FastZombie(World world) {
    3. super(world);
    4. this.bb = 0.4F; // move speed, normal zombie's 0.23F
    5. this.locX = this.lastX;
    6. this.locY = this.lastY;
    7. this.locZ = this.lastZ;
    8. }
    9. }


    This is my code to spawn that custom entity:
    Code:java
    1. public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    2. Player player = (Player) sender;
    3. Location loc = player.getLocation();
    4. if(command.getName().equalsIgnoreCase("lol")) {
    5. World world = ((CraftWorld)player.getWorld()).getHandle();
    6. FastZombie zomb = new FastZombie(world);
    7. zomb.setLocation(loc.getX(), loc.getY(), loc.getZ(), loc.getPitch(), loc.getYaw());
    8. zomb.world.addEntity(zomb);
    9. return true;
    10. }
    11. return false;
    12. }



    So, my question is: what do I need to do to fix this? Should I use this method, or should I use reflection to change the move speed?

    Thanks in advance!
    darkman2412
     
  2. Offline

    dsmyth1915

    Not entirely sure, add another ) to the end of that errored line. It looks like you forgot one and the return loops

    Nevermind, I read it wrong.
     
  3. Offline

    damospiderman

    Just apply a Speed potion to them... works well
     
  4. Offline

    desht

    dadaemon likes this.
  5. Offline

    sablednah

    Did you get any further in this?
    I'm trying to alter speeds too - but not getting much luck working it out :/
     
  6. Offline

    Darkman2412

    Yes, sorry that I didn't post it :/
    Basically, you need to reinitialize the pathing. If you're making a custom zombie:
    Code:java
    1. public SuperDuperFastZombie(World world) {
    2. super(world);
    3. this.bb = 10.0F;
    4. this.goalSelector.a(0, new PathfinderGoalFloat(this));
    5. this.goalSelector.a(1, new PathfinderGoalBreakDoor(this));
    6. this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, EntityHuman.class, this.bb, false));
    7. this.goalSelector.a(3, new PathfinderGoalMeleeAttack(this, EntityVillager.class, this.bb, true));
    8. this.goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, this.bb));
    9. this.goalSelector.a(5, new PathfinderGoalMoveThroughVillage(this, this.bb, false));
    10. this.goalSelector.a(6, new PathfinderGoalRandomStroll(this, this.bb));
    11. this.goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F));
    12. this.goalSelector.a(7, new PathfinderGoalRandomLookaround(this));
    13. this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, false));
    14. this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityHuman.class, 16.0F, 0, true));
    15. this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityVillager.class, 16.0F, 0, false));
    16. }


    Just look at the source of the specific entity you want to change. (https://github.com/Bukkit/CraftBukkit/blob/master/src/main/java/net/minecraft/server/).

    The original problem was that I didn't add the custom class to the server entity list.
     
  7. Offline

    sablednah

    Thanks, that helped.
    At first they where faster - 'cept when chasing a player !!

    Playing about it looks like I just needed to clear the old pathing first with this...

    Code:
     this.goalSelector = new PathfinderGoalSelector();
            this.targetSelector = new PathfinderGoalSelector();
     
  8. Offline

    Darkman2412

    Oh yeah, forgot to add that :/
     
  9. Offline

    dxwarlock

    [edit got it working] :)
     
  10. Offline

    sablednah

    Ok for anyone following this and messing with speeds - Under bukkit/mc 1.3.1 "this.bb" should now be "this.bw" ;)

    Hope this saves someone a bit of digging ;)

    We
    Well that doesn't work any more :/

    PathfinderGoalSelector needs a MethodProfiler argument.

    works - but gives a Final field cannot be modified error...

    So I'm now investigating going direct to the goals arraylist itself with
    Bit that's not visible... sooo - any ideas from the more expert Java coders out there?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 24, 2016
    kabbage and Darkman2412 like this.
  11. Offline

    sablednah

    got it working ;)
    Build the PathfinderGoalSelector object then use reflection to directly apply it to this.goalSelector
     
  12. Offline

    kabbage

    sablednah
    Could you provide a code example of how to do that?
    I don't understand what you mean...and I have no idea what the MethodProfiler is that is now a parameter...
     
  13. Offline

    sablednah

    Yup can do.. heres what i did to work.

    BTW - java experts. I apologise in advance for this horrific code - feel free to help me streamline it! ;)


    Code:
    public class SpeedZombie extends net.minecraft.server.EntityZombie{
        public SpeedZombie(World world) {
            super(world);
            this.bw = 0.46F;  // new speed  0.46 is double normal zombie
       
            try {
                //enable PathfinderGoalSelector's "a" feild to be editable
                Field gsa = net.minecraft.server.PathfinderGoalSelector.class.getDeclaredField("a");
                gsa.setAccessible(true);
           
                // ok now take this instances goals and targets and blank them
                gsa.set(this.goalSelector, new ArrayList());
                gsa.set(this.targetSelector, new ArrayList());
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
       
            // now re-add goals and targets  with new speed
            // you could remove or edit these (or add line from other entities) to change behaviours.
       
            this.goalSelector.a(0, new PathfinderGoalFloat(this));
            this.goalSelector.a(1, new PathfinderGoalBreakDoor(this));
            this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, EntityHuman.class, this.bw, false));
            this.goalSelector.a(3, new PathfinderGoalMeleeAttack(this, EntityVillager.class, this.bw, true));
            this.goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, this.bw));
            this.goalSelector.a(5, new PathfinderGoalMoveThroughVillage(this, this.bw, false));
            this.goalSelector.a(6, new PathfinderGoalRandomStroll(this, this.bw));
            this.goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F));
            this.goalSelector.a(7, new PathfinderGoalRandomLookaround(this));
            this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, false));
            this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityHuman.class, 16.0F, 0, true));
            this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityVillager.class, 16.0F, 0, false));
        }
    }
     
    kabbage likes this.
  14. Offline

    javaguy78

    Ok, Setting the initial speed of the creature is trivial following the above directions. Is there a way to change the speed of an entity on an event. So if my zombie moves at the standard 0.23F when moving without a target, is there a way I can buff his speed up to 0.5F when he targets a player?
     
  15. Offline

    sablednah

    Actually yes.
    And its fairly simple, the goal for "Attack Player" has speed as a parameter. So change it to..
    Code:
    this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, EntityHuman.class, (this.bw * 2), false));
    
    or change (this.bw * 2) to your 0.5F ;)

    To change as an actual event reaction - you have to blank and reset the goals again, not an easy task, so best stick to what the AI goals and targets let you do. Remember there are goals and targets in other Entities NMS code you can patch in too. In my custom zombie mod - I have archery zombies that properly maintain their distance like skellies, 'cause they ARE 'thinking' like skellies;)
     
  16. Offline

    javaguy78

    Cool, I'll give that a try. Thanks
     
  17. Offline

    Pippiter69

    Can anyone make a plugin for this with zombies having the same speed as the player sprinting? I would like the player to not be able to get away from them.
     
  18. hmm not working...
     
  19. Offline

    sablednah

    I have - and many other types.... but its private for ImagiScape's Zombie Apocalypse server.
    http://www.imagicraft.net/wiki/index.php?title=Zombie_Types

    How not working?

    Also did you read the whole thread? You also need to edit Minecrafts Entity types list to get your new zombie class in... something like this in your onEnable function...
    Code:
    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.EntityTypes.class.getDeclaredMethod("a", args);
        a.setAccessible(true);
        a.invoke(a, SpeedZombie.class, "Zombie", 54);
    } catch (Exception e) {
        e.printStackTrace();
        this.setEnabled(false);
    }
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 24, 2016
  20. Yep I did that
     
  21. Offline

    Deckerz

    you need to create a navigation class / object or you can't change speed. ill post the code when I get on my comp.
     
  22. Offline

    sablednah

    Looks like net.minecraft.server.PathfinderGoalSelector.class.getDeclaredField("a") is now of type UnsafeList (as of r2.1 if not before...)
    so you'll now need
    Code:
    gsa.set(this.goalSelector, new UnsafeList());
    gsa.set(this.targetSelector, new UnsafeList());
     
    kabbage likes this.
  23. Offline

    CookCreeperz

    Could someone show me how to do this? I've tried sablednah's method and no success.......Anyone know how to do this?

    Thanks,

    CookCreeperz
     
Thread Status:
Not open for further replies.

Share This Page