--- a/net/minecraft/world/entity/animal/horse/Llama.java
+++ b/net/minecraft/world/entity/animal/horse/Llama.java
@@ -1,6 +1,7 @@
 package net.minecraft.world.entity.animal.horse;
 
 import com.mojang.serialization.Codec;
+import java.util.Iterator;
 import java.util.function.IntFunction;
 import javax.annotation.Nullable;
 import net.minecraft.Util;
@@ -27,6 +28,7 @@
 import net.minecraft.world.entity.EntityType;
 import net.minecraft.world.entity.EquipmentSlot;
 import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.Mob;
 import net.minecraft.world.entity.MobSpawnType;
 import net.minecraft.world.entity.Pose;
 import net.minecraft.world.entity.SpawnGroupData;
@@ -63,38 +65,43 @@
 import net.minecraft.world.phys.Vec3;
 
 public class Llama extends AbstractChestedHorse implements VariantHolder<Llama.Variant>, RangedAttackMob {
+
     private static final int MAX_STRENGTH = 5;
     private static final EntityDataAccessor<Integer> DATA_STRENGTH_ID = SynchedEntityData.defineId(Llama.class, EntityDataSerializers.INT);
     private static final EntityDataAccessor<Integer> DATA_VARIANT_ID = SynchedEntityData.defineId(Llama.class, EntityDataSerializers.INT);
-    private static final EntityDimensions BABY_DIMENSIONS = EntityType.LLAMA
-        .getDimensions()
-        .withAttachments(EntityAttachments.builder().attach(EntityAttachment.PASSENGER, 0.0F, EntityType.LLAMA.getHeight() - 0.8125F, -0.3F))
-        .scale(0.5F);
+    private static final EntityDimensions BABY_DIMENSIONS = EntityType.LLAMA.getDimensions().withAttachments(EntityAttachments.builder().attach(EntityAttachment.PASSENGER, 0.0F, EntityType.LLAMA.getHeight() - 0.8125F, -0.3F)).scale(0.5F);
     boolean didSpit;
     @Nullable
     private Llama caravanHead;
     @Nullable
-    private Llama caravanTail;
+    public Llama caravanTail; // Paper
 
     public Llama(EntityType<? extends Llama> type, Level world) {
         super(type, world);
+        this.maxDomestication = 30; // Paper - Missing entity API; configure max temper instead of a hardcoded value
     }
 
     public boolean isTraderLlama() {
         return false;
     }
 
+    // CraftBukkit start
+    public void setStrengthPublic(int i) {
+        this.setStrength(i);
+    }
+    // CraftBukkit end
     private void setStrength(int strength) {
-        this.entityData.set(DATA_STRENGTH_ID, Math.max(1, Math.min(5, strength)));
+        this.entityData.set(Llama.DATA_STRENGTH_ID, Math.max(1, Math.min(5, strength)));
     }
 
     private void setRandomStrength(RandomSource random) {
         int i = random.nextFloat() < 0.04F ? 5 : 3;
+
         this.setStrength(1 + random.nextInt(i));
     }
 
     public int getStrength() {
-        return this.entityData.get(DATA_STRENGTH_ID);
+        return (Integer) this.entityData.get(Llama.DATA_STRENGTH_ID);
     }
 
     @Override
@@ -114,14 +121,16 @@
     @Override
     protected void registerGoals() {
         this.goalSelector.addGoal(0, new FloatGoal(this));
-        this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2));
-        this.goalSelector.addGoal(2, new LlamaFollowCaravanGoal(this, 2.1F));
-        this.goalSelector.addGoal(3, new RangedAttackGoal(this, 1.25, 40, 20.0F));
-        this.goalSelector.addGoal(3, new PanicGoal(this, 1.2));
-        this.goalSelector.addGoal(4, new BreedGoal(this, 1.0));
-        this.goalSelector.addGoal(5, new TemptGoal(this, 1.25, stack -> stack.is(ItemTags.LLAMA_TEMPT_ITEMS), false));
-        this.goalSelector.addGoal(6, new FollowParentGoal(this, 1.0));
-        this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.7));
+        this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D));
+        this.goalSelector.addGoal(2, new LlamaFollowCaravanGoal(this, 2.0999999046325684D));
+        this.goalSelector.addGoal(3, new RangedAttackGoal(this, 1.25D, 40, 20.0F));
+        this.goalSelector.addGoal(3, new PanicGoal(this, 1.2D));
+        this.goalSelector.addGoal(4, new BreedGoal(this, 1.0D));
+        this.goalSelector.addGoal(5, new TemptGoal(this, 1.25D, (itemstack) -> {
+            return itemstack.is(ItemTags.LLAMA_TEMPT_ITEMS);
+        }, false));
+        this.goalSelector.addGoal(6, new FollowParentGoal(this, 1.0D));
+        this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.7D));
         this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 6.0F));
         this.goalSelector.addGoal(9, new RandomLookAroundGoal(this));
         this.targetSelector.addGoal(1, new Llama.LlamaHurtByTargetGoal(this));
@@ -129,24 +138,23 @@
     }
 
     public static AttributeSupplier.Builder createAttributes() {
-        return createBaseChestedHorseAttributes().add(Attributes.FOLLOW_RANGE, 40.0);
+        return createBaseChestedHorseAttributes().add(Attributes.FOLLOW_RANGE, 40.0D);
     }
 
     @Override
     protected void defineSynchedData(SynchedEntityData.Builder builder) {
         super.defineSynchedData(builder);
-        builder.define(DATA_STRENGTH_ID, 0);
-        builder.define(DATA_VARIANT_ID, 0);
+        builder.define(Llama.DATA_STRENGTH_ID, 0);
+        builder.define(Llama.DATA_VARIANT_ID, 0);
     }
 
     @Override
     public Llama.Variant getVariant() {
-        return Llama.Variant.byId(this.entityData.get(DATA_VARIANT_ID));
+        return Llama.Variant.byId((Integer) this.entityData.get(Llama.DATA_VARIANT_ID));
     }
 
-    @Override
     public void setVariant(Llama.Variant variant) {
-        this.entityData.set(DATA_VARIANT_ID, variant.id);
+        this.entityData.set(Llama.DATA_VARIANT_ID, variant.id);
     }
 
     @Override
@@ -161,63 +169,55 @@
 
     @Override
     protected boolean handleEating(Player player, ItemStack item) {
-        int i = 0;
-        int j = 0;
+        byte b0 = 0;
+        byte b1 = 0;
         float f = 0.0F;
-        boolean bl = false;
+        boolean flag = false;
+
         if (item.is(Items.WHEAT)) {
-            i = 10;
-            j = 3;
+            b0 = 10;
+            b1 = 3;
             f = 2.0F;
         } else if (item.is(Blocks.HAY_BLOCK.asItem())) {
-            i = 90;
-            j = 6;
+            b0 = 90;
+            b1 = 6;
             f = 10.0F;
             if (this.isTamed() && this.getAge() == 0 && this.canFallInLove()) {
-                bl = true;
-                this.setInLove(player);
+                flag = true;
+                this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying
             }
         }
 
         if (this.getHealth() < this.getMaxHealth() && f > 0.0F) {
-            this.heal(f);
-            bl = true;
+            this.heal(f, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason
+            flag = true;
         }
 
-        if (this.isBaby() && i > 0) {
-            this.level().addParticle(ParticleTypes.HAPPY_VILLAGER, this.getRandomX(1.0), this.getRandomY() + 0.5, this.getRandomZ(1.0), 0.0, 0.0, 0.0);
+        if (this.isBaby() && b0 > 0) {
+            this.level().addParticle(ParticleTypes.HAPPY_VILLAGER, this.getRandomX(1.0D), this.getRandomY() + 0.5D, this.getRandomZ(1.0D), 0.0D, 0.0D, 0.0D);
             if (!this.level().isClientSide) {
-                this.ageUp(i);
+                this.ageUp(b0);
             }
 
-            bl = true;
+            flag = true;
         }
 
-        if (j > 0 && (bl || !this.isTamed()) && this.getTemper() < this.getMaxTemper()) {
-            bl = true;
+        if (b1 > 0 && (flag || !this.isTamed()) && this.getTemper() < this.getMaxTemper()) {
+            flag = true;
             if (!this.level().isClientSide) {
-                this.modifyTemper(j);
+                this.modifyTemper(b1);
             }
         }
 
-        if (bl && !this.isSilent()) {
-            SoundEvent soundEvent = this.getEatingSound();
-            if (soundEvent != null) {
-                this.level()
-                    .playSound(
-                        null,
-                        this.getX(),
-                        this.getY(),
-                        this.getZ(),
-                        this.getEatingSound(),
-                        this.getSoundSource(),
-                        1.0F,
-                        1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F
-                    );
+        if (flag && !this.isSilent()) {
+            SoundEvent soundeffect = this.getEatingSound();
+
+            if (soundeffect != null) {
+                this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), this.getEatingSound(), this.getSoundSource(), 1.0F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F);
             }
         }
 
-        return bl;
+        return flag;
     }
 
     @Override
@@ -228,18 +228,20 @@
     @Nullable
     @Override
     public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) {
-        RandomSource randomSource = world.getRandom();
-        this.setRandomStrength(randomSource);
-        Llama.Variant variant;
+        RandomSource randomsource = world.getRandom();
+
+        this.setRandomStrength(randomsource);
+        Llama.Variant entityllama_variant;
+
         if (entityData instanceof Llama.LlamaGroupData) {
-            variant = ((Llama.LlamaGroupData)entityData).variant;
+            entityllama_variant = ((Llama.LlamaGroupData) entityData).variant;
         } else {
-            variant = Util.getRandom(Llama.Variant.values(), randomSource);
-            entityData = new Llama.LlamaGroupData(variant);
+            entityllama_variant = (Llama.Variant) Util.getRandom((Object[]) Llama.Variant.values(), randomsource);
+            entityData = new Llama.LlamaGroupData(entityllama_variant);
         }
 
-        this.setVariant(variant);
-        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);
+        this.setVariant(entityllama_variant);
+        return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData);
     }
 
     @Override
@@ -306,70 +308,64 @@
     @Nullable
     private static DyeColor getDyeColor(ItemStack color) {
         Block block = Block.byItem(color.getItem());
-        return block instanceof WoolCarpetBlock ? ((WoolCarpetBlock)block).getColor() : null;
+
+        return block instanceof WoolCarpetBlock ? ((WoolCarpetBlock) block).getColor() : null;
     }
 
     @Nullable
     public DyeColor getSwag() {
-        return getDyeColor(this.getItemBySlot(EquipmentSlot.BODY));
+        return Llama.getDyeColor(this.getItemBySlot(EquipmentSlot.BODY));
     }
 
     @Override
     public int getMaxTemper() {
-        return 30;
+        return super.getMaxTemper(); // Paper - Missing entity API; delegate to parent
     }
 
     @Override
     public boolean canMate(Animal other) {
-        return other != this && other instanceof Llama && this.canParent() && ((Llama)other).canParent();
+        return other != this && other instanceof Llama && this.canParent() && ((Llama) other).canParent();
     }
 
     @Nullable
     @Override
-    public Llama getBreedOffspring(ServerLevel serverLevel, AgeableMob ageableMob) {
-        Llama llama = this.makeNewLlama();
-        if (llama != null) {
-            this.setOffspringAttributes(ageableMob, llama);
-            Llama llama2 = (Llama)ageableMob;
-            int i = this.random.nextInt(Math.max(this.getStrength(), llama2.getStrength())) + 1;
+    public Llama getBreedOffspring(ServerLevel world, AgeableMob entity) {
+        Llama entityllama = this.makeNewLlama();
+
+        if (entityllama != null) {
+            this.setOffspringAttributes(entity, entityllama);
+            Llama entityllama1 = (Llama) entity;
+            int i = this.random.nextInt(Math.max(this.getStrength(), entityllama1.getStrength())) + 1;
+
             if (this.random.nextFloat() < 0.03F) {
-                i++;
+                ++i;
             }
 
-            llama.setStrength(i);
-            llama.setVariant(this.random.nextBoolean() ? this.getVariant() : llama2.getVariant());
+            entityllama.setStrength(i);
+            entityllama.setVariant(this.random.nextBoolean() ? this.getVariant() : entityllama1.getVariant());
         }
 
-        return llama;
+        return entityllama;
     }
 
     @Nullable
     protected Llama makeNewLlama() {
-        return EntityType.LLAMA.create(this.level());
+        return (Llama) EntityType.LLAMA.create(this.level());
     }
 
     private void spit(LivingEntity target) {
-        LlamaSpit llamaSpit = new LlamaSpit(this.level(), this);
-        double d = target.getX() - this.getX();
-        double e = target.getY(0.3333333333333333) - llamaSpit.getY();
-        double f = target.getZ() - this.getZ();
-        double g = Math.sqrt(d * d + f * f) * 0.2F;
-        llamaSpit.shoot(d, e + g, f, 1.5F, 10.0F);
+        LlamaSpit entityllamaspit = new LlamaSpit(this.level(), this);
+        double d0 = target.getX() - this.getX();
+        double d1 = target.getY(0.3333333333333333D) - entityllamaspit.getY();
+        double d2 = target.getZ() - this.getZ();
+        double d3 = Math.sqrt(d0 * d0 + d2 * d2) * 0.20000000298023224D;
+
+        entityllamaspit.shoot(d0, d1 + d3, d2, 1.5F, 10.0F);
         if (!this.isSilent()) {
-            this.level()
-                .playSound(
-                    null,
-                    this.getX(),
-                    this.getY(),
-                    this.getZ(),
-                    SoundEvents.LLAMA_SPIT,
-                    this.getSoundSource(),
-                    1.0F,
-                    1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F
-                );
+            this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.LLAMA_SPIT, this.getSoundSource(), 1.0F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F);
         }
 
-        this.level().addFreshEntity(llamaSpit);
+        this.level().addFreshEntity(entityllamaspit);
         this.didSpit = true;
     }
 
@@ -380,14 +376,19 @@
     @Override
     public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) {
         int i = this.calculateFallDamage(fallDistance, damageMultiplier);
+
         if (i <= 0) {
             return false;
         } else {
             if (fallDistance >= 6.0F) {
-                this.hurt(damageSource, (float)i);
+                this.hurt(damageSource, (float) i);
                 if (this.isVehicle()) {
-                    for (Entity entity : this.getIndirectPassengers()) {
-                        entity.hurt(damageSource, (float)i);
+                    Iterator iterator = this.getIndirectPassengers().iterator();
+
+                    while (iterator.hasNext()) {
+                        Entity entity = (Entity) iterator.next();
+
+                        entity.hurt(damageSource, (float) i);
                     }
                 }
             }
@@ -425,7 +426,7 @@
 
     @Override
     protected double followLeashSpeed() {
-        return 2.0;
+        return 2.0D;
     }
 
     @Override
@@ -433,6 +434,7 @@
         if (!this.inCaravan() && this.isBaby()) {
             super.followMommy();
         }
+
     }
 
     @Override
@@ -447,12 +449,12 @@
 
     @Override
     public Vec3 getLeashOffset() {
-        return new Vec3(0.0, 0.75 * (double)this.getEyeHeight(), (double)this.getBbWidth() * 0.5);
+        return new Vec3(0.0D, 0.75D * (double) this.getEyeHeight(), (double) this.getBbWidth() * 0.5D);
     }
 
     @Override
     public EntityDimensions getDefaultDimensions(Pose pose) {
-        return this.isBaby() ? BABY_DIMENSIONS : super.getDefaultDimensions(pose);
+        return this.isBaby() ? Llama.BABY_DIMENSIONS : super.getDefaultDimensions(pose);
     }
 
     @Override
@@ -460,69 +462,76 @@
         return getDefaultPassengerAttachmentPoint(this, passenger, dimensions.attachments());
     }
 
-    static class LlamaAttackWolfGoal extends NearestAttackableTargetGoal<Wolf> {
-        public LlamaAttackWolfGoal(Llama llama) {
-            super(llama, Wolf.class, 16, false, true, wolf -> !((Wolf)wolf).isTame());
+    public static enum Variant implements StringRepresentable {
+
+        CREAMY(0, "creamy"), WHITE(1, "white"), BROWN(2, "brown"), GRAY(3, "gray");
+
+        public static final Codec<Llama.Variant> CODEC = StringRepresentable.fromEnum(Llama.Variant::values);
+        private static final IntFunction<Llama.Variant> BY_ID = ByIdMap.continuous(Llama.Variant::getId, values(), ByIdMap.OutOfBoundsStrategy.CLAMP);
+        final int id;
+        private final String name;
+
+        private Variant(final int i, final String s) {
+            this.id = i;
+            this.name = s;
         }
 
-        @Override
-        protected double getFollowDistance() {
-            return super.getFollowDistance() * 0.25;
+        public int getId() {
+            return this.id;
         }
-    }
 
-    static class LlamaGroupData extends AgeableMob.AgeableMobGroupData {
-        public final Llama.Variant variant;
+        public static Llama.Variant byId(int id) {
+            return (Llama.Variant) Llama.Variant.BY_ID.apply(id);
+        }
 
-        LlamaGroupData(Llama.Variant variant) {
-            super(true);
-            this.variant = variant;
+        @Override
+        public String getSerializedName() {
+            return this.name;
         }
     }
 
-    static class LlamaHurtByTargetGoal extends HurtByTargetGoal {
+    private static class LlamaHurtByTargetGoal extends HurtByTargetGoal {
+
         public LlamaHurtByTargetGoal(Llama llama) {
             super(llama);
         }
 
         @Override
         public boolean canContinueToUse() {
-            if (this.mob instanceof Llama llama && llama.didSpit) {
-                llama.setDidSpit(false);
-                return false;
+            Mob entityinsentient = this.mob;
+
+            if (entityinsentient instanceof Llama entityllama) {
+                if (entityllama.didSpit) {
+                    entityllama.setDidSpit(false);
+                    return false;
+                }
             }
 
             return super.canContinueToUse();
         }
     }
 
-    public static enum Variant implements StringRepresentable {
-        CREAMY(0, "creamy"),
-        WHITE(1, "white"),
-        BROWN(2, "brown"),
-        GRAY(3, "gray");
-
-        public static final Codec<Llama.Variant> CODEC = StringRepresentable.fromEnum(Llama.Variant::values);
-        private static final IntFunction<Llama.Variant> BY_ID = ByIdMap.continuous(Llama.Variant::getId, values(), ByIdMap.OutOfBoundsStrategy.CLAMP);
-        final int id;
-        private final String name;
+    private static class LlamaAttackWolfGoal extends NearestAttackableTargetGoal<Wolf> {
 
-        private Variant(final int id, final String name) {
-            this.id = id;
-            this.name = name;
+        public LlamaAttackWolfGoal(Llama llama) {
+            super(llama, Wolf.class, 16, false, true, (entityliving) -> {
+                return !((Wolf) entityliving).isTame();
+            });
         }
 
-        public int getId() {
-            return this.id;
+        @Override
+        protected double getFollowDistance() {
+            return super.getFollowDistance() * 0.25D;
         }
+    }
 
-        public static Llama.Variant byId(int id) {
-            return BY_ID.apply(id);
-        }
+    private static class LlamaGroupData extends AgeableMob.AgeableMobGroupData {
 
-        @Override
-        public String getSerializedName() {
-            return this.name;
+        public final Llama.Variant variant;
+
+        LlamaGroupData(Llama.Variant variant) {
+            super(true);
+            this.variant = variant;
         }
     }
 }
