1.6.1 added a new system of attributes to most entities, this allows us to set modifiers for various properties of their behaviour, the most interesting one being movement speed. I'll assume a small amount of knowledge of the net.minecraft.server part of CraftBukkit for this tutorial, you may want to look at my other tutorial on the topic. Each entity has a set of default attributes, what each of these do can be worked out from the top of GenericAttributes.java, each of these can have a modifier applied. As an example lets create a listener that speeds up all zombies Code: @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntitySpawn(CreatureSpawnEvent event){ LivingEntity entity = event.getEntity(); if (entity.getType() == EntityType.ZOMBIE){ } } simple so far, were just selecting all the zombies that managed to spawn. Now we need to get hold of the Minecraft entity instead of the Bukkit one Code: @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntitySpawn(CreatureSpawnEvent event){ LivingEntity entity = event.getEntity(); if (entity.getType() == EntityType.ZOMBIE){ EntityInsentient nmsEntity = (EntityInsentient) ((CraftLivingEntity) entity).getHandle(); AttributeInstance attributes = nmsEntity.a(GenericAttributes.d); } } We're also getting an entity attribute here. nmsEntity.a(GenericAttributes.d) returns an object which contains all of the modifiers that are applied for the attribute that is defined by the d field, looking at the source we see that this is movement speed. Next we need to create a modifier for this attribute that we can then apply, we need a UUID to identify it so that it can be removed later it we want. I would define this as a static field in the class. Code: private static final UUID movementSpeedUID = UUID.fromString("206a89dc-ae78-4c4d-b42c-3b31db3f5a7c"); The string here is a random one, you should generate a unique ID for this specific modifier. For example there is one UUID for speed potions and one for baby mobs. The modifier can then be created Code: AttributeModifier modifier = new AttributeModifier(movementSpeedUID, "<plugin_name> movement speed multiplier", 1.1d, 1); The string parameter is not used anywhere that I can see but we may as well use a sensible name. The third parameter is the modifier value and the 3rd is the type of modifier, this can be 0 for additive or 1 for multiplicative. The next step is simply to add the modifier to the attribute Code: attributes.a(modifier); AttributeInstance has two important methods, a() adds a modifier and b() removes it. Adding a modifier that already exists (has the same UUID) causes an error so it makes sense to remove it before hand. The final thing becomes Code: private static final UUID movementSpeedUID = UUID.fromString("206a89dc-ae78-4c4d-b42c-3b31db3f5a7c"); @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntitySpawn(CreatureSpawnEvent event){ LivingEntity entity = event.getEntity(); if (entity.getType() == EntityType.ZOMBIE){ EntityInsentient nmsEntity = (EntityInsentient) ((CraftLivingEntity) entity).getHandle(); AttributeInstance attributes = nmsEntity.getAttributeInstance(GenericAttributes.d); AttributeModifier modifier = new AttributeModifier(movementSpeedUID, "<plugin_name> movement speed multiplier", 1.1d, 1); attributes.b(modifier); attributes.a(modifier); } } As a final point, it might be a good idea to wrap this up into a method or class depending on what you are doing. I created my own LivingEntity class. https://github.com/betterphp/BloodM...t/bloodmoon/entity/BloodMoonEntityLiving.java
Thanks! This will come probably come in handy some time soon assuming Bukkit doesn't add an API for it.
This makes my zombies go bananaz running like crazy :S, doing 0d as multipliers and they are still running very fast... any idea?
Is there anything lower then 0? Code:java AttributeModifier modifier = new AttributeModifier(movementSpeedUID, "TestPlugin movement speed multiplier", 0d, 1);
well... if it's a multiplier 1.0 should be the same speed... but they are going bananaz :S I'm probably doing something wrong... Has anyone made a class for it, like Mobs.setSpeed(LivingeEntity, Multiplier); would be great!
You might be setting an additive attribute instead of a multiplier, check the ID in the constructor. 0 is addition 1 is multiplication.
thanks, for the code at the top i was able to read and set horses speed with these 2 methods Code: public Double getHorseSpeed(Horse h){ AttributeInstance attributes = ((EntityInsentient)((CraftLivingEntity)h).getHandle()).getAttributeInstance(GenericAttributes.d); return attributes.getValue(); } public void setHorseSpeed(Horse h,double speed){ // use about 2.25 for normalish speed AttributeInstance attributes = ((EntityInsentient)((CraftLivingEntity)h).getHandle()).getAttributeInstance(GenericAttributes.d); attributes.setValue(speed); }
Quick question, is the max health and attack damage a multiplier or a modifier? If you don't know, that's fine I'll do some testing
Jacek This tutorial, along with your previous one on the same subject, are great resources and have helped a lot. I can not thank you enough for taking the time to clearly explain how something works. Only caveat is that best practices say you should use UUID.randomUUID() or something similar rather than making one up that could (I know the odds are astronomical) be duplicated. Again, thanks for a thought-out and concisely written tutorial. And to those waiting for the bukkit api, I hope you have a lifetime supply of patience.
Jake0oo0 Only entities that have AI as far as I know. Anything that extends EntityInsentient wafwot Thanks Nice to know the time I put in was worth it. On the UUID thing, it needs to stay the same across restarts so that you don't end up with attributes that cannot be removed, I see your point though, hopefully people don't just copy the one from my post
I'm having a few issues setting a mobs attackDamage. Would you mind taking a peak? When I use the speed UUID and GenericAttributes.d it makes the mobs move faster. But a-c don't work for anything. Any Advice? Code Sample: privatestaticfinal UUID attackDamageUID = UUID.fromString("7bbe3bb1-079d-4150-ac6f-669e71550776"); EntityInsentient nmsEntity = (EntityInsentient) ((CraftLivingEntity) entity).getHandle(); AttributeInstance attributes = nmsEntity.getAttributeInstance(GenericAttributes.a); AttributeModifier modifier = new AttributeModifier(attackDamageUID, "MPM attack strength", 5.0d, 1); attributes.b(modifier); attributes.a(modifier);
Hey there, Is this still relevant? I am looking to accomplish something of this sort, but am very new with NMS source. Thought I'd ask (while still attempting to dive in) and see if I could fish up any new info if there have been developments. Thanks! edit: Looks like this is still very relevant, though with a small tweak in some syntax changes since September. Thanks for the guide!
Just as a note to you guys, as of Minecraft 1.7.2 this change is required for the above code to work Replace: Code:java AttributeInstance attributes = nmsEntity.a(GenericAttributes.d); With: Code:java AttributeInstance attributes = nmsEntity.getAttributeInstance(GenericAttributes.d); Apart from that everything else appears to be the same, also to help some others out, here are the field names of each generic attribute Max Health = GenericAttributes.a Follow Range = GenericAttributes.b Knockback Resistance = GenericAttributes.c Movement Speed = GenericAttributes.d Attack Damage = GenericAttributes.e Depending on which attribute you want to apply, this line will have to be changed Code:java AttributeInstance attributes = nmsEntity.getAttributeInstance(GenericAttributes.d); There are also mob specific attributes but I haven't looked into them.
Jacek Is there any way to make this work with an ender dragon? The dragon is different from all other mobs based on that it doesn't use path finders (All of the movement code is inside of one method called e()), and also it is composed of several parts which are all their own entities.
So did we find a way to stop mobs moving using this? Just did some messing around: Code: AttributeModifier modifier = new AttributeModifier(movementSpeedUID, "<plugin_name> movement speed multiplier", -100D, 1); This seems to work EDIT by Moderator: merged posts, please use the edit button instead of double posting.