package net.minecraft.world.item; import com.google.common.base.Suppliers; import com.mojang.serialization.Codec; import java.util.List; import java.util.function.Supplier; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.dispenser.BlockSource; import net.minecraft.core.dispenser.DefaultDispenseItemBehavior; import net.minecraft.core.dispenser.DispenseItemBehavior; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; import net.minecraft.util.StringRepresentable; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.EntitySelector; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.EquipmentSlotGroup; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.component.ItemAttributeModifiers; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.DispenserBlock; import net.minecraft.world.phys.AABB; public class ArmorItem extends Item implements Equipable { public static final DispenseItemBehavior DISPENSE_ITEM_BEHAVIOR = new DefaultDispenseItemBehavior() { @Override protected ItemStack execute(BlockSource blockSource, ItemStack item) { return ArmorItem.dispenseArmor(blockSource, item) ? item : super.execute(blockSource, item); } }; protected final ArmorItem.Type type; protected final Holder material; private final Supplier defaultModifiers; public static boolean dispenseArmor(BlockSource blockSource, ItemStack armorItem) { BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING)); List list = blockSource.level() .getEntitiesOfClass(LivingEntity.class, new AABB(blockPos), EntitySelector.NO_SPECTATORS.and(new EntitySelector.MobCanWearArmorEntitySelector(armorItem))); if (list.isEmpty()) { return false; } else { LivingEntity livingEntity = (LivingEntity)list.get(0); EquipmentSlot equipmentSlot = livingEntity.getEquipmentSlotForItem(armorItem); ItemStack itemStack = armorItem.split(1); livingEntity.setItemSlot(equipmentSlot, itemStack); if (livingEntity instanceof Mob) { ((Mob)livingEntity).setDropChance(equipmentSlot, 2.0F); ((Mob)livingEntity).setPersistenceRequired(); } return true; } } public ArmorItem(Holder material, ArmorItem.Type type, Item.Properties properties) { super(properties); this.material = material; this.type = type; DispenserBlock.registerBehavior(this, DISPENSE_ITEM_BEHAVIOR); this.defaultModifiers = Suppliers.memoize(() -> { int i = material.value().getDefense(type); float f = material.value().toughness(); ItemAttributeModifiers.Builder builder = ItemAttributeModifiers.builder(); EquipmentSlotGroup equipmentSlotGroup = EquipmentSlotGroup.bySlot(type.getSlot()); ResourceLocation resourceLocation = ResourceLocation.withDefaultNamespace("armor." + type.getName()); builder.add(Attributes.ARMOR, new AttributeModifier(resourceLocation, i, AttributeModifier.Operation.ADD_VALUE), equipmentSlotGroup); builder.add(Attributes.ARMOR_TOUGHNESS, new AttributeModifier(resourceLocation, f, AttributeModifier.Operation.ADD_VALUE), equipmentSlotGroup); float g = material.value().knockbackResistance(); if (g > 0.0F) { builder.add(Attributes.KNOCKBACK_RESISTANCE, new AttributeModifier(resourceLocation, g, AttributeModifier.Operation.ADD_VALUE), equipmentSlotGroup); } return builder.build(); }); } public ArmorItem.Type getType() { return this.type; } @Override public int getEnchantmentValue() { return this.material.value().enchantmentValue(); } public Holder getMaterial() { return this.material; } @Override public boolean isValidRepairItem(ItemStack stack, ItemStack repairCandidate) { return ((Ingredient)this.material.value().repairIngredient().get()).test(repairCandidate) || super.isValidRepairItem(stack, repairCandidate); } @Override public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { return this.swapWithEquipmentSlot(this, level, player, usedHand); } @Override public ItemAttributeModifiers getDefaultAttributeModifiers() { return (ItemAttributeModifiers)this.defaultModifiers.get(); } public int getDefense() { return this.material.value().getDefense(this.type); } public float getToughness() { return this.material.value().toughness(); } @Override public EquipmentSlot getEquipmentSlot() { return this.type.getSlot(); } @Override public Holder getEquipSound() { return this.getMaterial().value().equipSound(); } public static enum Type implements StringRepresentable { HELMET(EquipmentSlot.HEAD, 11, "helmet"), CHESTPLATE(EquipmentSlot.CHEST, 16, "chestplate"), LEGGINGS(EquipmentSlot.LEGS, 15, "leggings"), BOOTS(EquipmentSlot.FEET, 13, "boots"), BODY(EquipmentSlot.BODY, 16, "body"); public static final Codec CODEC = StringRepresentable.fromValues(ArmorItem.Type::values); private final EquipmentSlot slot; private final String name; private final int durability; private Type(final EquipmentSlot slot, final int durability, final String name) { this.slot = slot; this.name = name; this.durability = durability; } public int getDurability(int durabilityFactor) { return this.durability * durabilityFactor; } public EquipmentSlot getSlot() { return this.slot; } public String getName() { return this.name; } public boolean hasTrims() { return this == HELMET || this == CHESTPLATE || this == LEGGINGS || this == BOOTS; } @Override public String getSerializedName() { return this.name; } } }