Skip to main content
Version: 1.21.4

Attributes

Attributes are special fields of living entities that determine basic properties such as max health, speed or armor. All attributes are stored as double values and synced automatically. Vanilla offers a wide range of default attributes, and you can also add your own.

Due to legacy implementations, not all attributes work with all entities. For example, flying speed is ignored by ghasts, and jump strength only affects horses, not players.

Built-In Attributes

Minecraft

The following attributes are in the minecraft namespace, and their in-code values can be found in the Attributes class.

NameIn CodeRangeDefault ValueUsage
armorARMOR[0,30]0The armor value of the entity. A value of 1 means half a chestplate icon above the hotbar.
armor_toughnessARMOR_TOUGHNESS[0,20]0The armor toughness value of the entity. See Armor Toughness on the Minecraft Wiki for more information.
attack_damageATTACK_DAMAGE[0,2048]2The base attack damage done by the entity, without any weapon or similar item.
attack_knockbackATTACK_KNOCKBACK[0,5]0The extra knockback dealt by the entity. Knockback additionally has a base strength not represented by this attribute.
attack_speedATTACK_SPEED[0,1024]4The attack cooldown of the entity. Higher numbers mean more cooldown, setting this to 0 effectively re-enables pre-1.9 combat.
block_break_speedBLOCK_BREAK_SPEED[0,1024]1How fast the entity can mine blocks, as a multiplicative modifier. See Mining Speed for more information.
block_interaction_rangeBLOCK_INTERACTION_RANGE[0,64]4.5The interaction range in which the entity can interact with blocks, in blocks.
burning_timeBURNING_TIME[0,1024]1A multiplier for how long the entity will burn when ignited.
explosion_knockback_resistanceEXPLOSION_KNOCKBACK_RESISTANCE[0,1]0The explosion knockback resistance of the entity. This is a value in percent, i.e. 0 is no resistance, 0.5 is half resistance, and 1 is full resistance.
entity_interaction_rangeENTITY_INTERACTION_RANGE[0,64]3The interaction range in which the entity can interact with other entities, in blocks.
fall_damage_multiplierFALL_DAMAGE_MULTIPLIER[0,100]1A multiplier for fall damage taken by the entity.
flying_speedFLYING_SPEED[0,1024]0.4A multiplier for flying speed. This is not actually used by all flying entities, and ignored by e.g. ghasts.
follow_rangeFOLLOW_RANGE[0,2048]32The distance in blocks that the entity will target/follow the player.
gravityGRAVITY[1,1]0.08The gravity the entity is influenced by, in blocks per tick squared.
jump_strengthJUMP_STRENGTH[0,32]0.42The jump strength of the entity. Higher value means higher jumping.
knockback_resistanceKNOCKBACK_RESISTANCE[0,1]0The knockback resistance of the entity. This is a value in percent, i.e. 0 is no resistance, 0.5 is half resistance, and 1 is full resistance.
luckLUCK[-1024,1024]0The luck value of the entity. This is used when rolling loot tables to give bonus rolls or otherwise modify the resulting items' quality.
max_absorptionMAX_ABSORPTION[0,2048]0The max absorption (yellow hearts) of the entity. A value of 1 means half a heart.
max_healthMAX_HEALTH[1,1024]20The max health of the entity. A value of 1 means half a heart.
mining_efficiencyMINING_EFFICIENCY[0,1024]0How fast the entity can mine blocks, as an additive modifier, only if the used tool is correct. See Mining Speed for more information.
movement_efficiencyMOVEMENT_EFFICIENCY[0,1]0A linearly-interpolated movement speed bonus applied to the entity when it is walking on blocks that have a slowdown, such as soul sand.
movement_speedMOVEMENT_SPEED[0,1024]0.7The movement speed of the entity. Higher value means faster.
oxygen_bonusOXYGEN_BONUS[0,1024]0An oxygen bonus for the entity. The higher this is, the longer it takes for the entity to start drowning.
safe_fall_distanceSAFE_FALL_DISTANCE[-1024,1024]3The fall distance for the entity that is safe, i.e. the distance in which no fall damage is taken.
scaleSCALE[0.0625,16]1The scale at which the entity is rendered.
sneaking_speedSNEAKING_SPEED[0,1]0.3A movement speed multiplier applied to the entity when it is sneaking.
spawn_reinforcementsSPAWN_REINFORCEMENTS_CHANCE[0,1]0The chance for zombies to spawn other zombies. This is only relevant on hard difficulty, as zombie reinforcements do not occur on normal difficulty or lower.
step_heightSTEP_HEIGHT[0,10]0.6The step height of the entity, in blocks. If this is 1, the player can walk up 1-block ledges like they were slabs.
submerged_mining_speedSUBMERGED_MINING_SPEED[0,20]0.2How fast the entity can mine blocks, as a multiplicative modifier, only if the entity is underwater. See Mining Speed for more information.
sweeping_damage_ratioSWEEPING_DAMAGE_RATIO[0,1]0The amount of damage done by sweep attacks, in percent of the main attack. This is a value in percent, i.e. 0 is no damage, 0.5 is half damage, and 1 is full damage.
tempt_rangeTEMPT_RANGE[0,2048]10The range at which the entity can be tempted using items. Mainly for passive animals, e.g. cows or pigs.
water_movement_efficiencyWATER_MOVEMENT_EFFICIENCY[0,1]0A movement speed multiplier that is applied when the entity is underwater.
warning

Some attribute caps are set relatively arbitrarily by Mojang. This is especially notable for armor, which is capped at 30. NeoForge doesn't touch those caps, however there are mods to change them.

NeoForge

The following attributes are in the neoforge namespace, and their in-code values can be found in the NeoForgeMod class.

NameIn CodeRangeDefault ValueUsage
creative_flightCREATIVE_FLIGHT[0,1]0Determines whether creative flight for the entity is enabled (> 0) or disabled (<= 0).
nametag_distanceNAMETAG_DISTANCE[0,32]32How far the nametag of the entity will be visible, in blocks.
swim_speedSWIM_SPEED[0,1024]1A movement speed multiplier that is applied when the entity is underwater. This is applied independently from minecraft:water_movement_efficiency.

Default Attributes

When creating a LivingEntity, it is required to register a set of default attributes for them. When an entity is spawned in, its default attributes are set on it. Default attributes are registered in the EntityAttributeCreationEvent like so:

@SubscribeEvent
public static void createDefaultAttributes(EntityAttributeCreationEvent event) {
event.put(
// Your entity type.
MY_ENTITY.get(),
// An AttributeSupplier. This is typically created by calling LivingEntity#createLivingAttributes,
// setting your values on it, and calling #build. You can also create the AttributeSupplier from scratch
// if you want, see the source of LivingEntity#createLivingAttributes for an example.
LivingEntity.createLivingAttributes()
// Add an attribute with its default value.
.add(Attributes.MAX_HEALTH)
// Add an attribute with a non-default value.
.add(Attributes.MAX_HEALTH, 50)
// Build the AttributeSupplier.
.build()
);
}
tip

Some classes have specialized versions of LivingEntity#createLivingAttributes. For example, the Monster class has a method named Monster#createMonsterAttributes that can be used instead.

In some situations, for example when making your own attributes, it is needed to add attributes to an existing entity's AttributeSupplier. This is done through the EntityAttributeModificationEvent like so:

@SubscribeEvent
public static void modifyDefaultAttributes(EntityAttributeModificationEvent event) {
event.add(
// The EntityType to add the attribute for.
EntityType.VILLAGER,
// The Holder<Attribute> to add to the EntityType. Can also be a custom attribute.
Attributes.ARMOR,
// The attribute value to add.
// Can be omitted, if so, the attribute's default value will be used instead.
10.0
);
// We can also check if a given EntityType already has a given attribute.
// In this example, if villagers don't have the armor attribute already, we add it.
if (!event.has(EntityType.VILLAGER, Attributes.ARMOR)) {
event.add(...);
}
}

Be aware that unlike some other registries, custom attributes existing do not block vanilla clients from connecting to a NeoForge server. If a vanilla client connects, it will only receive the attributes in the minecraft namespace.

Querying Attributes

Attribute values are stored on entities in an AttributeMap, which is basically a Map<Attribute, AttributeInstance>. Attribute instances are basically what item stacks are to items, i.e. whereas an attribute is a registered singleton, attribute instances are concrete attribute objects bound to a concrete entity.

The AttributeMap of an entity can be retrieved by calling LivingEntity#getAttributes. You can then query the map like so:

// Get the attribute map.
AttributeMap attributes = livingEntity.getAttributes();
// Get an attribute instance. This may be null if the entity does not have the attribute.
AttributeInstance instance = attributes.getInstance(Attributes.ARMOR);
// Get the value for an attribute. Will fallback to the default for the entity if needed.
double value = attributes.getValue(Attributes.ARMOR);
// Of course, we can also check if an attribute is present to begin with.
if (attributes.hasAttribute(Attributes.ARMOR)) { ... }

// Alternatively, LivingEntity also offers shortcuts:
AttributeInstance instance = livingEntity.getAttribute(Attributes.ARMOR);
double value = livingEntity.getAttributeValue(Attributes.ARMOR);
info

When handling attributes, you will almost exclusively use Holder<Attribute>s instead of Attributes. This is also why with custom attributes (see below), we explicitly store the Holder<Attribute>.

Attribute Modifiers

In contrast to querying, changing the attribute values is not as easy. This is mainly because there may be multiple changes required to an attribute at the same time.

Consider this: You are a player, who has an attack damage attribute of 1. You wield a diamond sword, which does 6 extra attack damage, so you have 7 total attack damage. Then you drink a strength potion, adding a damage multiplier. You then also have some sort of trinket equipped that adds yet another multiplier.

To avoid miscalculations and to better communicate how the attribute values are modified, Minecraft introduces the attribute modifier system. In this system, every attribute has a base value, which is typically sourced from the default attributes we discussed earlier. We can then add any amount of attribute modifiers that can be individually removed again, without us having to worry about correctly applying operations.

To get started, let's create an attribute modifier:

// The name of the modifier. This is later used to query the modifier from the attribute map
// and as such must be (semantically) unique.
ResourceLocation id = ResourceLocation.fromNamespaceAndPath("yourmodid", "my_modifier");
// The modifier itself.
AttributeModifier modifier = new AttributeModifier(
// The name we defined earlier.
id,
// The amount by which we modify the attribute value.
2.0,
// The operation used to apply the modifier. Possible values are:
// - AttributeModifier.Operation.ADD_VALUE: Adds the value to the total attribute value.
// - AttributeModifier.Operation.ADD_MULTIPLIED_BASE: Multiplies the value with the attribute base value
// and adds it to the total attribute value.
// - AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL: Multiplies the value with the total attribute value,
// i.e. the attribute base value with all previous modifications already performed,
// and adds it to the total attribute value.
AttributeModifier.Operation.ADD_VALUE
);

Now, to apply the modifier, we have two options: add it as a transient modifier, or as a permanent modifier. Permanent modifiers are saved to disk, while transient modifiers are not. The use case for permanent modifiers is things like permanent stat bonuses (e.g. some sort of armor or health skill), while transient modifiers are mainly for equipment, mob effects and other modifiers that depend on the player's current state.

AttributeMap attributes = livingEntity.getAttributes();
// Add a transient modifier. If a modifier with the same id is already present, this will throw an exception.
attributes.getInstance(Attributes.ARMOR).addTransientModifier(modifier);
// Add a transient modifier. If a modifier with the same id is already present, it is removed first.
attributes.getInstance(Attributes.ARMOR).addOrUpdateTransientModifier(modifier);
// Add a permanent modifier. If a modifier with the same id is already present, this will throw an exception.
attributes.getInstance(Attributes.ARMOR).addPermanentModifier(modifier);
// Add a permanent modifier. If a modifier with the same id is already present, it is removed first.
attributes.getInstance(Attributes.ARMOR).addOrReplacePermanentModifier(modifier);

These modifiers can also be removed again:

// Remove by modifier object.
attributes.getInstance(Attributes.ARMOR).removeModifier(modifier);
// Remove by modifier id.
attributes.getInstance(Attributes.ARMOR).removeModifier(id);
// Remove all modifiers for an attribute.
attributes.getInstance(Attributes.ARMOR).removeModifiers();

Finally, we can also query the attribute map for whether it has a modifier with a certain ID, as well as query base values and modifier values separately, like so:

// Check for the modifier being present.
if (attributes.getInstance(Attributes.ARMOR).hasModifier(id)) { ... }
// Get the base armor attribute value.
double baseValue = attributes.getBaseValue(Attributes.ARMOR);
// Get the value of a certain modifier.
double modifierValue = attributes.getModifierValue(Attributes.ARMOR, id);

Custom Attributes

If needed, you can also add your own attributes. Like many other systems, attributes are a registry, and you can register your own objects to it. To get started, create a DeferredRegister<Attribute> like so:

public static final DeferredRegister<Attribute> ATTRIBUTES = DeferredRegister.create(
BuiltInRegistries.ATTRIBUTE, "yourmodid");

For the attributes themselves, there are three classes you can choose from:

  • RangedAttribute: Used by most attributes, this class defines lower and upper bounds for the attribute, along with a default value.
  • PercentageAttribute: Like RangedAttribute, but is displayed in percent instead of float values. NeoForge-added.
  • BooleanAttribute: An attribute that only has semantic true (> 0) and false (<= 0). This still uses doubles internally. NeoForge-added.

Using RangedAttribute as an example (the other two work similarly), registering an attribute would look like this:

public static final Holder<Attribute> MY_ATTRIBUTE = ATTRIBUTES.register("my_attribute", () -> new RangedAttribute(
// The translation key to use.
"attributes.yourmodid.my_attribute",
// The default value.
0,
// Min and max values.
-10000,
10000
));

And that's it! Just don't forget to register your DeferredRegister to the mod bus, and off you go.

info

We use Holder<Attribute> here instead of Supplier<RangedAttribute> like with many other registered objects, as it makes working with entities a lot easier (most entity methods expect Holder<Attribute>s).

If, for some reason, you need a Supplier<RangedAttribute> (or a supplier of any other subclass of Attribute), you should use DeferredHolder<Attribute, RangedAttribute> as the type.

The same rules also apply for any other Attribute subclass, i.e., we generally use Holder<Attribute> instead of Supplier<PercentageAttribute> or Supplier<BooleanAttribute>.