From 321c252f05125c1895d897006b1b5d03b32e274e Mon Sep 17 00:00:00 2001 From: BillyGalbreath Date: Thu, 17 Jun 2021 15:30:00 -0500 Subject: [PATCH] progress --- patches/server/0003-Ridables.patch | 2072 ++++++++++++++++- patches/server/0007-Llama-API.patch | 12 +- .../0011-LivingEntity-safeFallDistance.patch | 4 +- .../0027-Zombie-horse-naturally-spawn.patch | 4 +- ...0028-Charged-creeper-naturally-spawn.patch | 50 +- ...bit-naturally-spawn-toast-and-killer.patch | 8 +- .../server/0032-Tulips-change-fox-type.patch | 10 +- .../server/0033-Breedable-Polar-Bears.patch | 52 +- .../server/0034-Chickens-can-retaliate.patch | 36 +- ...cow-rotation-when-shearing-mooshroom.patch | 4 +- .../server/0040-Pigs-give-saddle-back.patch | 6 +- ...41-Snowman-drop-and-put-back-pumpkin.patch | 12 +- ...42-Ender-dragon-always-drop-full-exp.patch | 6 +- ...-skeleton-takes-wither-damage-option.patch | 4 +- ...derman-and-creeper-griefing-controls.patch | 6 +- .../0075-Configurable-jockey-options.patch | 6 +- ...o-disable-dolphin-treasure-searching.patch | 6 +- ...Stop-squids-floating-on-top-of-water.patch | 30 +- ...stomizable-wither-health-and-healing.patch | 27 +- ...sable-zombie-aggressiveness-towards-.patch | 4 +- 20 files changed, 2166 insertions(+), 193 deletions(-) diff --git a/patches/server/0003-Ridables.patch b/patches/server/0003-Ridables.patch index c8456b9c2..0b7864734 100644 --- a/patches/server/0003-Ridables.patch +++ b/patches/server/0003-Ridables.patch @@ -86,7 +86,7 @@ index 40d0dac02bb1922483d68f3cdd09a228f66d09f6..8e585ea6a070b2339cf396d70224a0d3 if ((entity instanceof AbstractFish && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) { ServerGamePacketListenerImpl.this.send(new ClientboundAddMobPacket((AbstractFish) entity)); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index cfab75b70b4cf4c95f3a7971c78f6dc42c0d23d0..f6f162b145bffe2d97b48b009641b0437fee5b1d 100644 +index cfab75b70b4cf4c95f3a7971c78f6dc42c0d23d0..5e9b67f0a5a8052b3f769b4a66b5c230401bd57f 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -230,7 +230,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n @@ -98,6 +98,15 @@ index cfab75b70b4cf4c95f3a7971c78f6dc42c0d23d0..f6f162b145bffe2d97b48b009641b043 public boolean horizontalCollision; public boolean verticalCollision; public boolean hurtMarked; +@@ -291,7 +291,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n + private final Set tags; + private final double[] pistonDeltas; + private long pistonDeltasGameTime; +- private EntityDimensions dimensions; ++ protected EntityDimensions dimensions; // Purpur - private -> protected + private float eyeHeight; + public boolean isInPowderSnow; + public boolean wasInPowderSnow; @@ -2408,6 +2408,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n this.passengers = ImmutableList.copyOf(list); } @@ -174,12 +183,12 @@ index cfab75b70b4cf4c95f3a7971c78f6dc42c0d23d0..f6f162b145bffe2d97b48b009641b043 + return false; + } + -+ public void onMount(Player player) { ++ public void onMount(Player rider) { + if (this instanceof Mob) { + ((Mob) this).setGoalTarget(null, null, false); + ((Mob) this).getNavigation().stopPathfinding(); + } -+ player.setJumping(false); // fixes jump on mount ++ rider.setJumping(false); // fixes jump on mount + } + + public void onDismount(Player player) { @@ -486,7 +495,7 @@ index ffc87d14cdc7edc22a7e2ac642d0e37037c52487..f2957d7f4c377a67ee486a9d0f7ae173 } diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index 153194d937d210e2e4fd8864e4a3c000f85d7e2e..87c5915564487d40ba9d160b2d1dc2cd2f2c5bb5 100644 +index 153194d937d210e2e4fd8864e4a3c000f85d7e2e..5708a1f88f3e62856a5ec15dc71d8a169353170d 100644 --- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java +++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java @@ -20,6 +20,7 @@ import net.minecraft.world.entity.EntityType; @@ -522,8 +531,8 @@ index 153194d937d210e2e4fd8864e4a3c000f85d7e2e..87c5915564487d40ba9d160b2d1dc2cd + } + + @Override -+ public void onMount(Player player) { -+ super.onMount(player); ++ public void onMount(Player rider) { ++ super.onMount(rider); + if (isResting()) { + setResting(false); + level.levelEvent(null, 1025, new BlockPos(this).above(), 0); @@ -570,6 +579,68 @@ index 153194d937d210e2e4fd8864e4a3c000f85d7e2e..87c5915564487d40ba9d160b2d1dc2cd super.customServerAiStep(); BlockPos blockposition = this.blockPosition(); BlockPos blockposition1 = blockposition.above(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java +index 17b54ac18ef862f0f39da2b3b48c8bb86d970744..c0413ad13bf13e981f460e65b3ebf499a6eb32b6 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java +@@ -108,12 +108,9 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { + @Override + protected void registerGoals() { + super.registerGoals(); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(0, new PanicGoal(this, 1.25D)); +- GoalSelector pathfindergoalselector = this.goalSelector; +- Predicate predicate = EntitySelector.NO_SPECTATORS; +- +- Objects.requireNonNull(predicate); +- pathfindergoalselector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6D, 1.4D, predicate::test)); ++ this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6D, 1.4D, EntitySelector.NO_SPECTATORS::test)); // Purpur - decompile fix + this.goalSelector.addGoal(4, new AbstractFish.FishSwimGoal(this)); + } + +@@ -125,7 +122,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { + @Override + public void travel(Vec3 movementInput) { + if (this.isEffectiveAi() && this.isInWater()) { +- this.moveRelative(0.01F, movementInput); ++ this.moveRelative(getRider() != null ? getSpeed() : 0.01F, movementInput); // Purpur + this.move(MoverType.SELF, this.getDeltaMovement()); + this.setDeltaMovement(this.getDeltaMovement().scale(0.9D)); + if (this.getTarget() == null) { +@@ -183,7 +180,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { + @Override + protected void playStepSound(BlockPos pos, BlockState state) {} + +- private static class FishMoveControl extends MoveControl { ++ private static class FishMoveControl extends net.pl3x.purpur.controller.WaterMoveControllerWASD { // Purpur + + private final AbstractFish fish; + +@@ -192,14 +189,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { + this.fish = owner; + } + ++ // Purpur start ++ @Override ++ public void purpurTick(Player rider) { ++ super.purpurTick(rider); ++ fish.setDeltaMovement(fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); ++ } ++ // Purpur end ++ + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur + if (this.fish.isEyeInFluid((Tag) FluidTags.WATER)) { + this.fish.setDeltaMovement(this.fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); + } + + if (this.operation == MoveControl.Operation.MOVE_TO && !this.fish.getNavigation().isDone()) { +- float f = (float) (this.speedModifier * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); ++ float f = (float) (this.getSpeedModifier() * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur + + this.fish.setSpeed(Mth.lerp(0.125F, this.fish.getSpeed(), f)); + double d0 = this.wantedX - this.fish.getX(); diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java index 2639f64f1a50faddc0284fb26b73b563b3e9eba9..8632a4047776723088b9b9fa27c6e8093fb17801 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Bee.java @@ -687,6 +758,111 @@ index 2639f64f1a50faddc0284fb26b73b563b3e9eba9..8632a4047776723088b9b9fa27c6e809 } } +diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java +index 15773d61deb357917e2478f0731f0b470669b8f0..14822b20971b63290a7022f8efe65693c41664d2 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java +@@ -121,6 +121,26 @@ public class Cat extends TamableAnimal { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.catRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.catRidableInWater; ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ setInSittingPose(false); ++ setLying(false); ++ setRelaxStateOne(false); ++ } ++ // Purpur end ++ + public ResourceLocation getResourceLocation() { + return (ResourceLocation) Cat.TEXTURE_BY_TYPE.getOrDefault(this.getCatType(), (ResourceLocation) Cat.TEXTURE_BY_TYPE.get(0)); + } +@@ -129,6 +149,7 @@ public class Cat extends TamableAnimal { + protected void registerGoals() { + this.temptGoal = new Cat.CatTemptGoal(this, 0.6D, Cat.TEMPT_INGREDIENT, true); + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new SitWhenOrderedToGoal(this)); + this.goalSelector.addGoal(2, new Cat.CatRelaxOnOwnerGoal(this)); + this.goalSelector.addGoal(3, this.temptGoal); +@@ -140,6 +161,7 @@ public class Cat extends TamableAnimal { + this.goalSelector.addGoal(10, new BreedGoal(this, 0.8D)); + this.goalSelector.addGoal(11, new WaterAvoidingRandomStrollGoal(this, 0.8D, 1.0000001E-5F)); + this.goalSelector.addGoal(12, new LookAtPlayerGoal(this, Player.class, 10.0F)); ++ this.targetSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Rabbit.class, false, (Predicate) null)); + this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR)); + } +@@ -394,6 +416,7 @@ public class Cat extends TamableAnimal { + + @Override + public InteractionResult mobInteract(Player player, InteractionHand hand) { ++ if (getRider() != null) return InteractionResult.PASS; // Purpur + ItemStack itemstack = player.getItemInHand(hand); + Item item = itemstack.getItem(); + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Chicken.java b/src/main/java/net/minecraft/world/entity/animal/Chicken.java +index 8460bed561c09a647f6e0209f7c5448e5a42b281..771e55cceaf17167c00554b1be7043a4cb3efb7e 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Chicken.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Chicken.java +@@ -52,9 +52,22 @@ public class Chicken extends Animal { + this.setPathfindingMalus(BlockPathTypes.WATER, 0.0F); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.chickenRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.chickenRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); + this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, Chicken.FOOD_ITEMS, false)); +diff --git a/src/main/java/net/minecraft/world/entity/animal/Cod.java b/src/main/java/net/minecraft/world/entity/animal/Cod.java +index ec9c235f00cc1b992340dfe0a0b79803361caac5..5275e4ed3d552d1e164ef580caf6c247ec5fd8c2 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Cod.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Cod.java +@@ -13,6 +13,18 @@ public class Cod extends AbstractSchoolingFish { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.codRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return true; ++ } ++ // Purpur end ++ + @Override + public ItemStack getBucketItemStack() { + return new ItemStack(Items.COD_BUCKET); diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java index c9dcbc2dcb2736d0f448496c67121db29b7d4deb..1cb5342d63011605b567a4fe16d07de831f04216 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Cow.java @@ -731,11 +907,745 @@ index c9dcbc2dcb2736d0f448496c67121db29b7d4deb..1cb5342d63011605b567a4fe16d07de8 } // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java +index f3093815066e6881a2bb638ae4643f69374450b3..2300abc4e80449e6b92992f6fb8cfe8e99dea351 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java +@@ -84,14 +84,82 @@ public class Dolphin extends WaterAnimal { + public static final Predicate ALLOWED_ITEMS = (entityitem) -> { + return !entityitem.hasPickUpDelay() && entityitem.isAlive() && entityitem.isInWater(); + }; ++ private int spitCooldown; // Purpur + + public Dolphin(EntityType type, Level world) { + super(type, world); +- this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); ++ // Purpur start ++ class DolphinMoveControl extends SmoothSwimmingMoveControl { ++ private final net.pl3x.purpur.controller.WaterMoveControllerWASD waterMoveControllerWASD; ++ private final Dolphin dolphin; ++ ++ public DolphinMoveControl(Dolphin dolphin, int pitchChange, int yawChange, float speedInWater, float speedInAir, boolean buoyant) { ++ super(dolphin, pitchChange, yawChange, speedInWater, speedInAir, buoyant); ++ this.dolphin = dolphin; ++ this.waterMoveControllerWASD = new net.pl3x.purpur.controller.WaterMoveControllerWASD(dolphin); ++ } ++ ++ @Override ++ public void tick() { ++ if (dolphin.getRider() != null) { ++ purpurTick(dolphin.getRider()); ++ } else { ++ super.tick(); ++ } ++ } ++ ++ public void purpurTick(Player rider) { ++ if (dolphin.getAirSupply() < 150) { ++ // if drowning override player WASD controls to find air ++ tick(); ++ } else { ++ waterMoveControllerWASD.purpurTick(rider); ++ dolphin.setDeltaMovement(dolphin.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); ++ } ++ } ++ }; ++ this.moveControl = new DolphinMoveControl(this, 85, 10, 0.02F, 0.1F, true); ++ // Purpur end + this.lookControl = new SmoothSwimmingLookControl(this, 10); + this.setCanPickUpLoot(true); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.dolphinRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return true; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (spitCooldown == 0 && getRider() != null) { ++ spitCooldown = level.purpurConfig.dolphinSpitCooldown; ++ ++ org.bukkit.craftbukkit.entity.CraftPlayer player = (org.bukkit.craftbukkit.entity.CraftPlayer) getRider().getBukkitEntity(); ++ if (!player.hasPermission("allow.special.dolphin")) { ++ return false; ++ } ++ ++ org.bukkit.Location loc = player.getEyeLocation(); ++ loc.setPitch(loc.getPitch() - 10); ++ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(10).add(loc.toVector()); ++ ++ net.pl3x.purpur.entity.DolphinSpit spit = new net.pl3x.purpur.entity.DolphinSpit(level, this); ++ spit.shoot(target.getX() - getX(), target.getY() - getY(), target.getZ() - getZ(), level.purpurConfig.dolphinSpitSpeed, 5.0F); ++ ++ level.addFreshEntity(spit); ++ playSound(SoundEvents.DOLPHIN_ATTACK, 1.0F, 1.0F + (random.nextFloat() - random.nextFloat()) * 0.2F); ++ return true; ++ } ++ return false; ++ } ++ // Purpur end ++ + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { +@@ -166,6 +234,7 @@ public class Dolphin extends WaterAnimal { + protected void registerGoals() { + this.goalSelector.addGoal(0, new BreathAirGoal(this)); + this.goalSelector.addGoal(0, new TryFindWaterGoal(this)); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this)); + this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0D)); + this.goalSelector.addGoal(4, new RandomSwimmingGoal(this, 1.0D, 10)); +@@ -176,6 +245,7 @@ public class Dolphin extends WaterAnimal { + this.goalSelector.addGoal(8, new Dolphin.PlayWithItemsGoal()); + this.goalSelector.addGoal(8, new FollowBoatGoal(this)); + this.goalSelector.addGoal(9, new AvoidEntityGoal<>(this, Guardian.class, 8.0F, 1.0D, 1.0D)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Guardian.class})).setAlertOthers(new Class[0])); // CraftBukkit - decompile error + } + +@@ -227,7 +297,7 @@ public class Dolphin extends WaterAnimal { + + @Override + protected boolean canRide(Entity entity) { +- return true; ++ return boardingCooldown <= 0; // Purpur - make dolphin honor ride cooldown like all other non-boss mobs; + } + + @Override +@@ -262,6 +332,11 @@ public class Dolphin extends WaterAnimal { + @Override + public void tick() { + super.tick(); ++ // Purpur start ++ if (spitCooldown > 0) { ++ spitCooldown--; ++ } ++ // Purpur end + if (this.isNoAi()) { + this.setAirSupply(this.getMaxAirSupply()); + } else { +diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java +index 31f4e4a93ea5fd3ffe7e60dff2e2a9642b51daa2..6cc8f6ef75e4b8b4282e4f664a83ce6491042df1 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java +@@ -138,6 +138,39 @@ public class Fox extends Animal { + this.setCanPickUpLoot(true); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.foxRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.foxRidableInWater; ++ } ++ ++ @Override ++ public float getJumpPower() { ++ return getRider() != null ? 0.5F : super.getJumpPower(); ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ setCanPickUpLoot(false); ++ clearStates(); ++ setIsPouncing(false); ++ spitOutItem(getItemBySlot(EquipmentSlot.MAINHAND)); ++ setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); ++ } ++ ++ @Override ++ public void onDismount(Player rider) { ++ super.onDismount(rider); ++ setCanPickUpLoot(true); ++ } ++ // Purpur end ++ + @Override + protected void defineSynchedData() { + super.defineSynchedData(); +@@ -157,6 +190,7 @@ public class Fox extends Animal { + return entityliving instanceof AbstractSchoolingFish; + }); + this.goalSelector.addGoal(0, new Fox.FoxFloatGoal()); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new Fox.FaceplantGoal()); + this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2D)); + this.goalSelector.addGoal(3, new Fox.FoxBreedGoal(1.0D)); +@@ -182,6 +216,7 @@ public class Fox extends Animal { + this.goalSelector.addGoal(11, new Fox.FoxSearchForItemsGoal()); + this.goalSelector.addGoal(12, new Fox.FoxLookAtPlayerGoal(this, Player.class, 24.0F)); + this.goalSelector.addGoal(13, new Fox.PerchAndSearchGoal()); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(3, new Fox.DefendTrustedTargetGoal(LivingEntity.class, false, false, (entityliving) -> { + return Fox.TRUSTED_TARGET_SELECTOR.test(entityliving) && !this.trusts(entityliving.getUUID()); + })); +@@ -737,16 +772,16 @@ public class Fox extends Animal { + return new Vec3(0.0D, (double) (0.55F * this.getEyeHeight()), (double) (this.getBbWidth() * 0.4F)); + } + +- public class FoxLookControl extends LookControl { ++ public class FoxLookControl extends net.pl3x.purpur.controller.LookControllerWASD { // Purpur + + public FoxLookControl() { + super(Fox.this); + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur + if (!Fox.this.isSleeping()) { +- super.tick(); ++ super.vanillaTick(); // Purpur + } + + } +@@ -757,16 +792,16 @@ public class Fox extends Animal { + } + } + +- private class FoxMoveControl extends MoveControl { ++ private class FoxMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur + + public FoxMoveControl() { + super(Fox.this); + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur + if (Fox.this.canMove()) { +- super.tick(); ++ super.vanillaTick(); // Purpur + } + + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java +index ec00c2dd8f969eb99ec6a014e3bcd09c7484b237..63b739c86d2ea22aa9a610796ad2f208b0db289e 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java ++++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java +@@ -70,8 +70,22 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + this.maxUpStep = 1.0F; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.ironGolemRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.ironGolemRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { ++ if (level.purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0D, true)); + this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9D, 32.0F)); + this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6D, false)); +@@ -79,6 +93,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + this.goalSelector.addGoal(5, new OfferFlowerGoal(this)); + this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, new DefendVillageTargetGoal(this)); + this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); +@@ -266,13 +281,13 @@ public class IronGolem extends AbstractGolem implements NeutralMob { + ItemStack itemstack = player.getItemInHand(hand); + + if (!itemstack.is(Items.IRON_INGOT)) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur + } else { + float f = this.getHealth(); + + this.heal(25.0F); + if (this.getHealth() == f) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur + } else { + float f1 = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F; + +diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java +index d9fb3df35de94ae5abbb86ace0328bbe6f5403b3..0e066782ee09bb5626715bcc500bc04f2252bc2e 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java +@@ -59,6 +59,18 @@ public class MushroomCow extends Cow implements Shearable { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.mooshroomRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.mooshroomRidableInWater; ++ } ++ // Purpur end ++ + @Override + public float getWalkTargetValue(BlockPos pos, LevelReader world) { + return world.getBlockState(pos.below()).is(Blocks.MYCELIUM) ? 10.0F : world.getBrightness(pos) - 0.5F; +@@ -120,7 +132,7 @@ public class MushroomCow extends Cow implements Shearable { + } else if (itemstack.is(Items.SHEARS) && this.readyForShearing()) { + // CraftBukkit start + if (!CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur + } + // CraftBukkit end + this.shear(SoundSource.PLAYERS); +@@ -141,7 +153,7 @@ public class MushroomCow extends Cow implements Shearable { + Optional> optional = this.getEffectFromItemStack(itemstack); + + if (!optional.isPresent()) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur + } + + Pair pair = (Pair) optional.get(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java +index 8104ac0f77e8e94f294b82f7badefccd72419223..db17b971bb2da8ae375347040029e17b1a6165f5 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java +@@ -68,6 +68,18 @@ public class Ocelot extends Animal { + this.reassessTrustingGoals(); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.ocelotRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.ocelotRidableInWater; ++ } ++ // Purpur end ++ + boolean isTrusting() { + return (Boolean) this.entityData.get(Ocelot.DATA_TRUSTING); + } +@@ -99,12 +111,14 @@ public class Ocelot extends Animal { + protected void registerGoals() { + this.temptGoal = new Ocelot.OcelotTemptGoal(this, 0.6D, Ocelot.TEMPT_INGREDIENT, true); + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(3, this.temptGoal); + this.goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3F)); + this.goalSelector.addGoal(8, new OcelotAttackGoal(this)); + this.goalSelector.addGoal(9, new BreedGoal(this, 0.8D)); + this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 0.8D, 1.0000001E-5F)); + this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0F)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Chicken.class, false)); + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR)); + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java +index 851ee58e52c6003d6ae7b58c9b6b9a9a9795fa85..4591b67537aa95ce0a7e6ad838b7db9da80346cc 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Panda.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java +@@ -108,6 +108,27 @@ public class Panda extends Animal { + + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.pandaRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.pandaRidableInWater; ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ setForwardMot(0.0F); ++ sit(false); ++ eat(false); ++ setOnBack(false); ++ } ++ // Purpur end ++ + @Override + public boolean canTakeItem(ItemStack stack) { + EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(stack); +@@ -263,6 +284,7 @@ public class Panda extends Animal { + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(2, new Panda.PandaPanicGoal(this, 2.0D)); + this.goalSelector.addGoal(2, new Panda.PandaBreedGoal(this, 1.0D)); + this.goalSelector.addGoal(3, new Panda.PandaAttackGoal(this, 1.2000000476837158D, true)); +@@ -278,6 +300,7 @@ public class Panda extends Animal { + this.goalSelector.addGoal(12, new Panda.PandaRollGoal(this)); + this.goalSelector.addGoal(13, new FollowParentGoal(this, 1.25D)); + this.goalSelector.addGoal(14, new WaterAvoidingRandomStrollGoal(this, 1.0D)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, (new Panda.PandaHurtByTargetGoal(this, new Class[0])).setAlertOthers(new Class[0])); + } + +@@ -615,7 +638,7 @@ public class Panda extends Animal { + ItemStack itemstack = player.getItemInHand(hand); + + if (this.isScared()) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur + } else if (this.isOnBack()) { + this.setOnBack(false); + return InteractionResult.sidedSuccess(this.level.isClientSide); +@@ -634,7 +657,7 @@ public class Panda extends Animal { + this.gameEvent(GameEvent.MOB_INTERACT, this.eyeBlockPosition()); + } else { + if (this.level.isClientSide || this.isSitting() || this.isInWater()) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur + } + + this.tryToSit(); +@@ -651,7 +674,7 @@ public class Panda extends Animal { + + return InteractionResult.SUCCESS; + } else { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur + } + } + +@@ -691,7 +714,7 @@ public class Panda extends Animal { + return !this.isOnBack() && !this.isScared() && !this.isEating() && !this.isRolling() && !this.isSitting(); + } + +- private static class PandaMoveControl extends MoveControl { ++ private static class PandaMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur + + private final Panda panda; + +@@ -701,9 +724,9 @@ public class Panda extends Animal { + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur + if (this.panda.canPerformAction()) { +- super.tick(); ++ super.vanillaTick(); // Purpur + } + } + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/Parrot.java b/src/main/java/net/minecraft/world/entity/animal/Parrot.java +index 345fe87d5d6c3883c28d2c1b34d1020e18864d97..0a3996b0943c9b0666f4aa3ac6ca9de5b1204fb3 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Parrot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Parrot.java +@@ -121,12 +121,63 @@ public class Parrot extends ShoulderRidingEntity implements FlyingAnimal { + + public Parrot(EntityType type, Level world) { + super(type, world); +- this.moveControl = new FlyingMoveControl(this, 10, false); ++ // Purpur start ++ final net.pl3x.purpur.controller.FlyingWithSpacebarMoveControllerWASD flyingController = new net.pl3x.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); ++ class ParrotMoveControl extends FlyingMoveControl { ++ public ParrotMoveControl(Mob entity, int maxPitchChange, boolean noGravity) { ++ super(entity, maxPitchChange, noGravity); ++ } ++ ++ @Override ++ public void tick() { ++ if (mob.getRider() != null) { ++ flyingController.purpurTick(mob.getRider()); ++ } else { ++ super.tick(); ++ } ++ } ++ ++ @Override ++ public boolean hasWanted() { ++ return mob.getRider() != null ? getForwardMot() != 0 || getStrafeMot() != 0 : super.hasWanted(); ++ } ++ } ++ this.moveControl = new ParrotMoveControl(this, 10, false); ++ // Purpur end + this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F); + this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, -1.0F); + this.setPathfindingMalus(BlockPathTypes.COCOA, -1.0F); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.parrotRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return level.purpurConfig.parrotRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level.purpurConfig.parrotMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.25, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ // Purpur end ++ + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { +@@ -145,8 +196,10 @@ public class Parrot extends ShoulderRidingEntity implements FlyingAnimal { + + @Override + protected void registerGoals() { +- this.goalSelector.addGoal(0, new PanicGoal(this, 1.25D)); ++ //this.goalSelector.addGoal(0, new PanicGoal(this, 1.25D)); // Purpur - move down + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur ++ this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D)); // Purpur + this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); + this.goalSelector.addGoal(2, new FollowOwnerGoal(this, 1.0D, 5.0F, 1.0F, true)); +diff --git a/src/main/java/net/minecraft/world/entity/animal/Pig.java b/src/main/java/net/minecraft/world/entity/animal/Pig.java +index 2c95b6eddfe46e5d2ad495bfc86ccc24ae75e704..80c8ceda47bf8b3ff370f89a61aa01869d606ee6 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Pig.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Pig.java +@@ -65,9 +65,22 @@ public class Pig extends Animal implements ItemSteerable, Saddleable { + this.steering = new ItemBasedSteering(this.entityData, Pig.DATA_BOOST_TIME, Pig.DATA_SADDLE_ID); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.pigRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.pigRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D)); + this.goalSelector.addGoal(3, new BreedGoal(this, 1.0D)); + this.goalSelector.addGoal(4, new TemptGoal(this, 1.2D, Ingredient.of(Items.CARROT_ON_A_STICK), false)); +diff --git a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java +index 0694cd0b994ee595adca43c988485e6dc13c7244..dc6bc8f10d147cb1d0e5c69b6f6df63b0e8d4531 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java ++++ b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java +@@ -61,11 +61,35 @@ public class PolarBear extends Animal implements NeutralMob { + private static final UniformInt PERSISTENT_ANGER_TIME = TimeUtil.rangeOfSeconds(20, 39); + private int remainingPersistentAngerTime; + private UUID persistentAngerTarget; ++ private int standTimer = 0; // Purpur + + public PolarBear(EntityType type, Level world) { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.polarBearRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.polarBearRidableInWater; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (!isStanding()) { ++ if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0) { ++ setStanding(true); ++ playSound(SoundEvents.POLAR_BEAR_WARNING, 1.0F, 1.0F); ++ } ++ } ++ return false; ++ } ++ // Purpur end ++ + @Override + public AgeableMob getBreedOffspring(ServerLevel world, AgeableMob entity) { + return EntityType.POLAR_BEAR.create(world); +@@ -80,12 +104,14 @@ public class PolarBear extends Animal implements NeutralMob { + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal()); + this.goalSelector.addGoal(1, new PolarBear.PolarBearPanicGoal()); + this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25D)); + this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0D)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, new PolarBear.PolarBearHurtByTargetGoal()); + this.targetSelector.addGoal(2, new PolarBear.PolarBearAttackPlayersGoal()); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); +@@ -201,6 +227,11 @@ public class PolarBear extends Animal implements NeutralMob { + this.updatePersistentAnger((ServerLevel)this.level, true); + } + ++ // Purpur start ++ if (isStanding() && --standTimer <= 0) { ++ setStanding(false); ++ } ++ // Purpur end + } + + @Override +@@ -230,6 +261,7 @@ public class PolarBear extends Animal implements NeutralMob { + + public void setStanding(boolean warning) { + this.entityData.set(DATA_STANDING_ID, warning); ++ standTimer = warning ? 20 : -1; // Purpur + } + + public float getStandingAnimationScale(float tickDelta) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java +index 1b76e267cd36010a57d31852086dec0585d4bce5..42446fd8ba1d78cd5992bc6c2e5259da361eb716 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java +@@ -45,6 +45,18 @@ public class Pufferfish extends AbstractFish { + this.refreshDimensions(); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.pufferfishRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return true; ++ } ++ // Purpur end ++ + @Override + protected void defineSynchedData() { + super.defineSynchedData(); diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -index 3a9391b512974e812cac0d89119f68ba6728bfc9..4a60afbb79ffb86d3c41b48d923ca8b3beca1c54 100644 +index 3a9391b512974e812cac0d89119f68ba6728bfc9..29551a3b87f06c5876de5fda80615acf6c1f4764 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java +++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -@@ -129,7 +129,7 @@ public class Rabbit extends Animal { +@@ -81,6 +81,7 @@ public class Rabbit extends Animal { + private boolean wasOnGround; + private int jumpDelayTicks; + int moreCarrotTicks; ++ private boolean actualJump; // Purpur + + public Rabbit(EntityType type, Level world) { + super(type, world); +@@ -89,6 +90,46 @@ public class Rabbit extends Animal { + this.initializePathFinderGoals(); // CraftBukkit - moved code + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.rabbitRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.rabbitRidableInWater; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (onGround) { ++ actualJump = true; ++ jumpFromGround(); ++ actualJump = false; ++ } ++ return true; ++ } ++ ++ private void handleJumping() { ++ if (onGround) { ++ RabbitJumpControl jumpController = (RabbitJumpControl) jumpControl; ++ if (!wasOnGround) { ++ setJumping(false); ++ jumpController.setCanJump(false); ++ } ++ if (!jumpController.wantJump()) { ++ if (moveControl.hasWanted()) { ++ startJumping(); ++ } ++ } else if (!jumpController.canJump()) { ++ jumpController.setCanJump(true); ++ } ++ } ++ wasOnGround = onGround; ++ } ++ // Purpur end ++ + // CraftBukkit start - code from constructor + public void initializePathFinderGoals(){ + this.setSpeedModifier(0.0D); +@@ -98,6 +139,7 @@ public class Rabbit extends Animal { + @Override + public void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new Rabbit.RabbitPanicGoal(this, 2.2D)); + this.goalSelector.addGoal(2, new BreedGoal(this, 0.8D)); + this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, Ingredient.of(Items.CARROT, Items.GOLDEN_CARROT, Blocks.DANDELION), false)); +@@ -111,6 +153,13 @@ public class Rabbit extends Animal { + + @Override + protected float getJumpPower() { ++ if (getRider() != null) { ++ if (getForwardMot() < 0) { ++ setSpeed(getForwardMot() * 2F); ++ } ++ return actualJump ? 0.5F : 0.3F; ++ } ++ // Purpur end + if (!this.horizontalCollision && (!this.moveControl.hasWanted() || this.moveControl.getWantedY() <= this.getY() + 0.5D)) { + Path pathentity = this.navigation.getPath(); + +@@ -129,7 +178,7 @@ public class Rabbit extends Animal { } @Override @@ -744,6 +1654,361 @@ index 3a9391b512974e812cac0d89119f68ba6728bfc9..4a60afbb79ffb86d3c41b48d923ca8b3 super.jumpFromGround(); double d0 = this.moveControl.getSpeedModifier(); +@@ -179,6 +228,13 @@ public class Rabbit extends Animal { + + @Override + public void customServerAiStep() { ++ // Purpur start ++ if (getRider() != null) { ++ handleJumping(); ++ return; ++ } ++ // Purpur end ++ + if (this.jumpDelayTicks > 0) { + --this.jumpDelayTicks; + } +@@ -451,7 +507,7 @@ public class Rabbit extends Animal { + } + } + +- private static class RabbitMoveControl extends MoveControl { ++ private static class RabbitMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur + + private final Rabbit rabbit; + private double nextJumpSpeed; +@@ -462,14 +518,14 @@ public class Rabbit extends Animal { + } + + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur + if (this.rabbit.onGround && !this.rabbit.jumping && !((Rabbit.RabbitJumpControl) this.rabbit.jumpControl).wantJump()) { + this.rabbit.setSpeedModifier(0.0D); + } else if (this.hasWanted()) { + this.rabbit.setSpeedModifier(this.nextJumpSpeed); + } + +- super.tick(); ++ super.vanillaTick(); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/Salmon.java b/src/main/java/net/minecraft/world/entity/animal/Salmon.java +index 574f91414ecacd18fadef5a56a4142d9cfdb6713..02a9ce0b98bab47d57b51cdfb2194f0e72a9f705 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Salmon.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Salmon.java +@@ -13,6 +13,18 @@ public class Salmon extends AbstractSchoolingFish { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.salmonRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return true; ++ } ++ // Purpur end ++ + @Override + public int getMaxSchoolSize() { + return 5; +diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java +index 9315c34e61aa0432175385736de51f1bfdafbf85..5890bf8aa714dc219059bca4950a1b5b1882dd3a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java +@@ -116,10 +116,23 @@ public class Sheep extends Animal implements Shearable { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.sheepRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.sheepRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { + this.eatBlockGoal = new EatBlockGoal(this); + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D)); + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); + this.goalSelector.addGoal(3, new TemptGoal(this, 1.1D, Ingredient.of(Items.WHEAT), false)); +diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java +index 2631f08496c8e45874b22760b559a91b7b2bf415..a76f3c1c409dc96f7033be8a7eeb06617053735b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java ++++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java +@@ -53,12 +53,26 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.snowGolemRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.snowGolemRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new RangedAttackGoal(this, 1.25D, 20, 10.0F)); + this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D, 1.0000001E-5F)); + this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entityliving) -> { + return entityliving instanceof Enemy; + })); +@@ -110,6 +124,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + return; + } + ++ if (getRider() != null && !level.purpurConfig.snowGolemLeaveTrailWhenRidden) return; // Purpur - don't leave snow trail when being ridden + BlockState iblockdata = Blocks.SNOW.defaultBlockState(); + + for (int l = 0; l < 4; ++l) { +@@ -152,7 +167,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + if (itemstack.is(Items.SHEARS) && this.readyForShearing()) { + // CraftBukkit start + if (!CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur + } + // CraftBukkit end + this.shear(SoundSource.PLAYERS); +@@ -165,7 +180,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM + + return InteractionResult.sidedSuccess(this.level.isClientSide); + } else { +- return InteractionResult.PASS; ++ return tryRide(player, hand); // Purpur + } + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java +index 56838c9f214c0f75041e75c45ad1a0c72fcacc66..0a744855f24ac54b22bc474a1c903da7af656364 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Squid.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java +@@ -54,9 +54,32 @@ public class Squid extends WaterAnimal { + this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.squidRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return true; ++ } ++ ++ private void rotateVectorAroundY(org.bukkit.util.Vector vector, double degrees) { ++ double rad = Math.toRadians(degrees); ++ double cos = Math.cos(rad); ++ double sine = Math.sin(rad); ++ double x = vector.getX(); ++ double z = vector.getZ(); ++ vector.setX(cos * x - sine * z); ++ vector.setZ(sine * x + cos * z); ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new Squid.SquidFleeGoal()); + } + +@@ -250,6 +273,38 @@ public class Squid extends WaterAnimal { + + @Override + public void tick() { ++ // Purpur start ++ Player rider = squid.getRider(); ++ if (rider != null) { ++ if (rider.jumping) { ++ squid.onSpacebar(); ++ } ++ float forward = rider.getForwardMot(); ++ float strafe = rider.getStrafeMot(); ++ float speed = (float) squid.getAttributeValue(Attributes.MOVEMENT_SPEED) * 10F; ++ if (forward < 0.0F) { ++ speed *= -0.5; ++ } ++ org.bukkit.util.Vector dir = rider.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(speed / 20.0F); ++ if (strafe != 0.0F) { ++ if (forward == 0.0F) { ++ dir.setY(0); ++ rotateVectorAroundY(dir, strafe > 0.0F ? -90 : 90); ++ } else if (forward < 0.0F) { ++ rotateVectorAroundY(dir, strafe > 0.0F ? 45 : -45); ++ } else { ++ rotateVectorAroundY(dir, strafe > 0.0F ? -45 : 45); ++ } ++ } ++ if (forward != 0.0F || strafe != 0.0F) { ++ squid.setMovementVector((float) dir.getX(), (float) dir.getY(), (float) dir.getZ()); ++ } else { ++ squid.setMovementVector(0.0F, 0.0F, 0.0F); ++ } ++ return; ++ } ++ // Purpur end ++ + int i = this.squid.getNoActionTime(); + + if (i > 100) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java +index 77f56978449ece43bdca28a50a0681cda9f89eba..4d5ceb4ce913248ad404393e4f0c75cad24029bb 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java +@@ -43,6 +43,18 @@ public class TropicalFish extends AbstractSchoolingFish { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.tropicalFishRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return true; ++ } ++ // Purpur end ++ + public static String getPredefinedName(int variant) { + return "entity.minecraft.tropical_fish.predefined." + variant; + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java +index 925f16d5eb092518ef774f69a8d99689feb0f5d7..b6d7692a779fb95d50aecb63b495336ae28d1933 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java +@@ -90,6 +90,18 @@ public class Turtle extends Animal { + this.maxUpStep = 1.0F; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.turtleRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.turtleRidableInWater; ++ } ++ // Purpur end ++ + public void setHomePos(BlockPos pos) { + this.entityData.set(Turtle.HOME_POS, pos); + } +@@ -192,6 +204,7 @@ public class Turtle extends Animal { + + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(0, new Turtle.TurtlePanicGoal(this, 1.2D)); + this.goalSelector.addGoal(1, new Turtle.TurtleBreedGoal(this, 1.0D)); + this.goalSelector.addGoal(1, new Turtle.TurtleLayEggGoal(this, 1.0D)); +@@ -349,13 +362,15 @@ public class Turtle extends Animal { + org.bukkit.craftbukkit.event.CraftEventFactory.entityDamage = null; // CraftBukkit + } + +- private static class TurtleMoveControl extends MoveControl { ++ private static class TurtleMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur + + private final Turtle turtle; ++ private final net.pl3x.purpur.controller.WaterMoveControllerWASD waterController; // Purpur + + TurtleMoveControl(Turtle turtle) { + super(turtle); + this.turtle = turtle; ++ waterController = new net.pl3x.purpur.controller.WaterMoveControllerWASD(turtle, 0.25D); // Purpur + } + + private void updateSpeed() { +@@ -374,8 +389,18 @@ public class Turtle extends Animal { + + } + ++ // Purpur start ++ public void purpurTick(Player rider) { ++ if (turtle.isInWater()) { ++ waterController.purpurTick(rider); ++ } else { ++ super.purpurTick(rider); ++ } ++ } ++ // Purpur end ++ + @Override +- public void tick() { ++ public void vanillaTick() { // Purpur + this.updateSpeed(); + if (this.operation == MoveControl.Operation.MOVE_TO && !this.turtle.getNavigation().isDone()) { + double d0 = this.wantedX - this.turtle.getX(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java +index 80caabee4d2100208f117a1c3e35247b65e318ad..bca3300e06d6eb0c6acdfb11d715a1e8447c9198 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java +@@ -93,9 +93,27 @@ public class Wolf extends TamableAnimal implements NeutralMob { + this.setTame(false); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.wolfRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.wolfRidableInWater; ++ } ++ ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ setInSittingPose(false); ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); ++ this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); + this.goalSelector.addGoal(3, new Wolf.WolfAvoidEntityGoal<>(this, Llama.class, 24.0F, 1.5D, 1.5D)); + this.goalSelector.addGoal(4, new LeapAtTargetGoal(this, 0.4F)); +@@ -106,6 +124,7 @@ public class Wolf extends TamableAnimal implements NeutralMob { + this.goalSelector.addGoal(9, new BegGoal(this, 8.0F)); + this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(10, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this)); + this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this)); + this.targetSelector.addGoal(3, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers(new Class[0])); // CraftBukkit - decompile error diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java index 25ebcb30cf5165675f26802983b6f68404b93b06..e076d03025690492c2226f03d777eba714819300 100644 --- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java @@ -807,6 +2072,791 @@ index 25ebcb30cf5165675f26802983b6f68404b93b06..e076d03025690492c2226f03d777eba7 } } +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java +index ba58e066cca533dfed7610a730c4dd7423fe124d..919410ce27e7e42e297c2caba7d3d7c1b623aede 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java +@@ -114,12 +114,22 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + + protected AbstractHorse(EntityType type, Level world) { + super(type, world); ++ this.moveControl = new net.minecraft.world.entity.ai.control.MoveControl(this); // Purpur - use vanilla controller ++ this.lookControl = new net.minecraft.world.entity.ai.control.LookControl(this); // Purpur - use vanilla controller + this.maxUpStep = 1.0F; + this.createInventory(); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return false; // vanilla handles ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new PanicGoal(this, 1.2D)); + this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D)); + this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D, AbstractHorse.class)); +@@ -127,6 +137,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, + this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 0.7D)); + this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.addBehaviourGoals(); + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java +index ab588b990c15ff809a1937321d11a03aab826f61..e5b13558f45966bf70593931922ca73f4a66c66a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java +@@ -15,6 +15,13 @@ public class Donkey extends AbstractChestedHorse { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.donkeyRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected SoundEvent getAmbientSound() { + super.getAmbientSound(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java +index 6326471fe48133bef94e98fd028e60a951bccf2b..c7b0d6a987644e0b589c143b0b6b68053be04f37 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java +@@ -39,6 +39,13 @@ public class Horse extends AbstractHorse { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.horseRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void randomizeAttributes() { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double)this.generateRandomMaxHealth()); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java +index 5c31519193126b715105e1e83bb54f6a1681d19e..0671185c358398fe0c4c1dbf4ede2f3e8c4794fb 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java +@@ -68,7 +68,46 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { + + public Llama(EntityType type, Level world) { + super(type, world); ++ // Purpur start ++ this.moveControl = new net.pl3x.purpur.controller.MoveControllerWASD(this) { ++ @Override ++ public void tick() { ++ if (entity.getRider() != null && isSaddled()) { ++ purpurTick(entity.getRider()); ++ } else { ++ vanillaTick(); ++ } ++ } ++ }; ++ this.lookControl = new net.pl3x.purpur.controller.LookControllerWASD(this) { ++ @Override ++ public void tick() { ++ if (entity.getRider() != null && isSaddled()) { ++ purpurTick(entity.getRider()); ++ } else { ++ vanillaTick(); ++ } ++ } ++ }; ++ // Purpur end ++ } ++ ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.llamaRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.llamaRidableInWater; ++ } ++ ++ @Override ++ public boolean isSaddled() { ++ return super.isSaddled() || (isTamed() && getSwag() != null); + } ++ // Purpur end + + public boolean isTraderLlama() { + return false; +@@ -113,6 +152,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new FloatGoal(this)); ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D)); + this.goalSelector.addGoal(2, new LlamaFollowCaravanGoal(this, (double)2.1F)); + this.goalSelector.addGoal(3, new RangedAttackGoal(this, 1.25D, 40, 20.0F)); +@@ -122,6 +162,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { + this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 0.7D)); + this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, new Llama.LlamaHurtByTargetGoal(this)); + this.targetSelector.addGoal(2, new Llama.LlamaAttackWolfGoal(this)); + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java b/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java +index 6b10aeab9d671327f6e85a31b0c85ef310a1d0b2..40cc7e20913938d6e30e6bca9f4ad70fb5e9435b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java +@@ -14,6 +14,13 @@ public class Mule extends AbstractChestedHorse { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.muleRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected SoundEvent getAmbientSound() { + super.getAmbientSound(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java +index 1d0a2296bab0140d3209c0749710d5fb952c79b4..d4057c300d39eca4ff2e11791ce5ba7993d9b66e 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java +@@ -29,6 +29,13 @@ public class SkeletonHorse extends AbstractHorse { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isTamed() { ++ return true; ++ } ++ // Purpur end ++ + public static AttributeSupplier.Builder createAttributes() { + return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0D).add(Attributes.MOVEMENT_SPEED, (double)0.2F); + } +@@ -40,6 +47,7 @@ public class SkeletonHorse extends AbstractHorse { + + @Override + protected void addBehaviourGoals() { ++ if (level.purpurConfig.skeletonHorseCanSwim) goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur + } + + @Override +@@ -135,7 +143,7 @@ public class SkeletonHorse extends AbstractHorse { + + @Override + public boolean rideableUnderWater() { +- return true; ++ return level.purpurConfig.skeletonHorseRidableInWater; // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java +index 885937d7001259d9a8ee8d5bc16629a196a13fe8..ff252d9ca75b90ab7606f63aa5f89b6230e33a36 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java +@@ -27,6 +27,23 @@ public class TraderLlama extends Llama { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.traderLlamaRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.traderLlamaRidableInWater; ++ } ++ ++ @Override ++ public boolean isSaddled() { ++ return super.isSaddled() || isTamed(); ++ } ++ // Purpur end ++ + @Override + public boolean isTraderLlama() { + return true; +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java +index c6c7096ec476d91ef91b164e32c5a9cd112f3dd7..d328e36015b6b7d6a9e093fbe232eb5ecda46d96 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java +@@ -22,6 +22,18 @@ public class ZombieHorse extends AbstractHorse { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.zombieHorseRidableInWater; ++ } ++ ++ @Override ++ public boolean isTamed() { ++ return true; ++ } ++ // Purpur end ++ + public static AttributeSupplier.Builder createAttributes() { + return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0D).add(Attributes.MOVEMENT_SPEED, (double)0.2F); + } +@@ -92,5 +104,6 @@ public class ZombieHorse extends AbstractHorse { + + @Override + protected void addBehaviourGoals() { ++ if (level.purpurConfig.zombieHorseCanSwim) goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur + } + } +diff --git a/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java b/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java +index 305a891e4b51d1031d9e9238ff00e2ea7de8d954..84625d09df800fcfd477fc493fb5f8246567b7e8 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java ++++ b/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java +@@ -21,6 +21,13 @@ public class EnderDragonPart extends Entity { + this.name = name; + } + ++ // Purpur start ++ @Override ++ public net.minecraft.world.InteractionResult interact(net.minecraft.world.entity.player.Player player, net.minecraft.world.InteractionHand hand) { ++ return parentMob.isAlive() ? parentMob.tryRide(player, hand) : net.minecraft.world.InteractionResult.PASS; ++ } ++ // Purpur end ++ + @Override + protected void defineSynchedData() { + } +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +index c98202092752a9015aaf95bd1471135b88e84425..a1a64591e6a6fb8a4550b91f89e3cdbd35c6d249 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +@@ -102,6 +102,7 @@ public class EnderDragon extends Mob implements Enemy { + private final int[] nodeAdjacency = new int[24]; + private final BinaryHeap openSet = new BinaryHeap(); + private Explosion explosionSource = new Explosion(null, this, null, null, Double.NaN, Double.NaN, Double.NaN, Float.NaN, true, Explosion.BlockInteraction.DESTROY); // CraftBukkit - reusable source for CraftTNTPrimed.getSource() ++ private boolean hadRider; // Purpur + + public EnderDragon(EntityType entitytypes, Level world) { + super(EntityType.ENDER_DRAGON, world); +@@ -116,8 +117,45 @@ public class EnderDragon extends Mob implements Enemy { + } + + this.phaseManager = new EnderDragonPhaseManager(this); ++ ++ // Purpur start ++ this.moveControl = new net.pl3x.purpur.controller.FlyingMoveControllerWASD(this) { ++ @Override ++ public void tick() { ++ // dragon doesn't use the controller. do nothing ++ } ++ }; ++ this.lookControl = new net.pl3x.purpur.controller.LookControllerWASD(this) { ++ @Override ++ public void tick() { ++ // dragon doesn't use the controller. do nothing ++ } ++ ++ @Override ++ public void purpurTick(Player rider) { ++ setYawPitch(rider.yRot - 180F, rider.xRotO * 0.5F); ++ } ++ }; ++ // Purpur end ++ } ++ ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.enderDragonRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.enderDragonRidableInWater; + } + ++ @Override ++ public double getMaxY() { ++ return level.purpurConfig.enderDragonMaxY; ++ } ++ // Purpur end ++ + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0D); + } +@@ -166,6 +204,37 @@ public class EnderDragon extends Mob implements Enemy { + + @Override + public void aiStep() { ++ // Purpur start ++ boolean hasRider = getRider() != null; ++ if (hasRider) { ++ if (!hadRider) { ++ hadRider = true; ++ noPhysics = false; ++ this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(4.0F, 2.0F); ++ } ++ ++ // dragon doesn't use controllers, so must tick manually ++ moveControl.tick(); ++ lookControl.tick(); ++ ++ moveRelative((float) getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.1F, new Vec3(-getStrafeMot(), getVerticalMot(), -getForwardMot())); ++ Vec3 mot = getDeltaMovement(); ++ setDeltaMovement(mot); ++ move(MoverType.PLAYER, mot); ++ ++ mot = mot.multiply(0.9F, 0.9F, 0.9F); ++ setDeltaMovement(mot); ++ ++ // control wing flap speed on client ++ phaseManager.setPhase(mot.x() * mot.x() + mot.z() * mot.z() < 0.005F ? EnderDragonPhase.HOVERING : EnderDragonPhase.HOLDING_PATTERN); ++ } else if (hadRider) { ++ hadRider = false; ++ noPhysics = true; ++ this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(16.0F, 8.0F); ++ phaseManager.setPhase(EnderDragonPhase.HOLDING_PATTERN); // HoldingPattern ++ } ++ // Purpur end ++ + this.processFlappingMovement(); + if (this.level.isClientSide) { + this.setHealth(this.getHealth()); +@@ -179,6 +248,8 @@ public class EnderDragon extends Mob implements Enemy { + float f; + + if (this.isDeadOrDying()) { ++ if (hasRider) ejectPassengers(); // Purpur ++ + float f1 = (this.random.nextFloat() - 0.5F) * 8.0F; + + f = (this.random.nextFloat() - 0.5F) * 4.0F; +@@ -191,9 +262,9 @@ public class EnderDragon extends Mob implements Enemy { + + f = 0.2F / ((float) vec3d.horizontalDistance() * 10.0F + 1.0F); + f *= (float) Math.pow(2.0D, vec3d.y); +- if (this.phaseManager.getCurrentPhase().isSitting()) { ++ if (!hasRider && this.phaseManager.getCurrentPhase().isSitting()) { // Purpur + this.flapTime += 0.1F; +- } else if (this.inWall) { ++ } else if (!hasRider && this.inWall) { // Purpur + this.flapTime += f * 0.5F; + } else { + this.flapTime += f; +@@ -238,7 +309,7 @@ public class EnderDragon extends Mob implements Enemy { + } + + this.phaseManager.getCurrentPhase().doClientTick(); +- } else { ++ } else if (!hasRider) { // Purpur + DragonPhaseInstance idragoncontroller = this.phaseManager.getCurrentPhase(); + + idragoncontroller.doServerTick(); +@@ -308,7 +379,7 @@ public class EnderDragon extends Mob implements Enemy { + this.tickPart(this.body, (double) (f11 * 0.5F), 0.0D, (double) (-f12 * 0.5F)); + this.tickPart(this.wing1, (double) (f12 * 4.5F), 2.0D, (double) (f11 * 4.5F)); + this.tickPart(this.wing2, (double) (f12 * -4.5F), 2.0D, (double) (f11 * -4.5F)); +- if (!this.level.isClientSide && this.hurtTime == 0) { ++ if (!hasRider && !this.level.isClientSide && this.hurtTime == 0) { // Purpur + this.knockBack(this.level.getEntities(this, this.wing1.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); + this.knockBack(this.level.getEntities(this, this.wing2.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); + this.hurt(this.level.getEntities(this, this.head.getBoundingBox().inflate(1.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); +@@ -352,7 +423,7 @@ public class EnderDragon extends Mob implements Enemy { + } + + if (!this.level.isClientSide) { +- this.inWall = this.checkWalls(this.head.getBoundingBox()) | this.checkWalls(this.neck.getBoundingBox()) | this.checkWalls(this.body.getBoundingBox()); ++ this.inWall = !hasRider && this.checkWalls(this.head.getBoundingBox()) | this.checkWalls(this.neck.getBoundingBox()) | this.checkWalls(this.body.getBoundingBox()); // Purpur + if (this.dragonFight != null) { + this.dragonFight.updateDragon(this); + } +diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +index 1c8f6863b976cfcb559de9b3e3cf9292831166ee..0b1f6fad51a985ebe4ccebde12a1db9e12a57bc0 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java ++++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +@@ -83,6 +83,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob + return entityliving.getMobType() != MobType.UNDEAD && entityliving.attackable(); + }; + private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0D).selector(WitherBoss.LIVING_ENTITY_SELECTOR); ++ private int shootCooldown = 0; // Purpur + // Paper start + private boolean canPortal = false; + +@@ -95,15 +96,117 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob + this.setHealth(this.getMaxHealth()); + this.getNavigation().setCanFloat(true); + this.xpReward = 50; ++ this.moveControl = new net.pl3x.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.1F); // Purpur + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.witherRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.witherRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level.purpurConfig.witherMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 5F; ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.5, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ this.entityData.set(DATA_TARGETS.get(0), 0); ++ this.entityData.set(DATA_TARGETS.get(1), 0); ++ this.entityData.set(DATA_TARGETS.get(2), 0); ++ getNavigation().stopPathfinding(); ++ shootCooldown = 20; ++ } ++ ++ @Override ++ public boolean onClick(net.minecraft.world.InteractionHand hand) { ++ return shoot(getRider(), hand == net.minecraft.world.InteractionHand.MAIN_HAND ? new int[]{1} : new int[]{2}); ++ } ++ ++ public boolean shoot(@Nullable Player rider, int[] heads) { ++ if (shootCooldown > 0) { ++ return false; ++ } ++ ++ shootCooldown = 20; ++ if (rider == null) { ++ return false; ++ } ++ ++ org.bukkit.craftbukkit.entity.CraftHumanEntity player = rider.getBukkitEntity(); ++ if (!player.hasPermission("allow.special.wither")) { ++ return false; ++ } ++ ++ net.minecraft.world.phys.HitResult rayTrace = getRayTrace(120, net.minecraft.world.level.ClipContext.Fluid.NONE); ++ if (rayTrace == null) { ++ return false; ++ } ++ ++ Vec3 loc; ++ if (rayTrace.getType() == net.minecraft.world.phys.HitResult.Type.BLOCK) { ++ BlockPos pos = ((net.minecraft.world.phys.BlockHitResult) rayTrace).getBlockPos(); ++ loc = new Vec3(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D); ++ } else if (rayTrace.getType() == net.minecraft.world.phys.HitResult.Type.ENTITY) { ++ Entity target = ((net.minecraft.world.phys.EntityHitResult) rayTrace).getEntity(); ++ loc = new Vec3(target.getX(), target.getY() + (target.getEyeHeight() / 2), target.getZ()); ++ } else { ++ org.bukkit.block.Block block = player.getTargetBlock(null, 120); ++ loc = new Vec3(block.getX() + 0.5D, block.getY() + 0.5D, block.getZ() + 0.5D); ++ } ++ ++ for (int head : heads) { ++ shoot(head, loc.x(), loc.y(), loc.z(), rider); ++ } ++ ++ return true; // handled ++ } ++ ++ public void shoot(int head, double x, double y, double z, Player rider) { ++ level.levelEvent(null, 1024, blockPosition(), 0); ++ double headX = getHeadX(head); ++ double headY = getHeadY(head); ++ double headZ = getHeadZ(head); ++ WitherSkull skull = new WitherSkull(level, this, x - headX, y - headY, z - headZ) { ++ @Override ++ public boolean canHitEntity(Entity target) { ++ // do not hit rider ++ return target != rider && super.canHitEntity(target); ++ } ++ }; ++ skull.setPosRaw(headX, headY, headZ); ++ level.addFreshEntity(skull); ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(0, new WitherBoss.WitherDoNothingGoal()); + this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0D, 40, 20.0F)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0])); + if(this.level.paperConfig.fixWitherTargetingBug) this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 0, false, false, null)); // Paper - Fix MC-29274 + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Mob.class, 0, false, false, WitherBoss.LIVING_ENTITY_SELECTOR)); +@@ -246,6 +349,16 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob + + @Override + protected void customServerAiStep() { ++ // Purpur start ++ if (getRider() != null) { ++ Vec3 mot = getDeltaMovement(); ++ setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z()); ++ } ++ if (shootCooldown > 0) { ++ shootCooldown--; ++ } ++ // Purpur end ++ + int i; + + if (this.getInvulnerableTicks() > 0) { +@@ -553,7 +666,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob + } + + public static AttributeSupplier.Builder createAttributes() { +- return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 300.0D).add(Attributes.MOVEMENT_SPEED, 0.6000000238418579D).add(Attributes.FOLLOW_RANGE, 40.0D).add(Attributes.ARMOR, 4.0D); ++ return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 300.0D).add(Attributes.MOVEMENT_SPEED, 0.6000000238418579D).add(Attributes.FOLLOW_RANGE, 40.0D).add(Attributes.ARMOR, 4.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur + } + + public float getHeadYRot(int headIndex) { +@@ -573,11 +686,11 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob + } + + public int getAlternativeTarget(int headIndex) { +- return (Integer) this.entityData.get((EntityDataAccessor) WitherBoss.DATA_TARGETS.get(headIndex)); ++ return getRider() != null ? 0 : this.entityData.get(WitherBoss.DATA_TARGETS.get(headIndex)); // Purpur + } + + public void setAlternativeTarget(int headIndex, int id) { +- this.entityData.set((EntityDataAccessor) WitherBoss.DATA_TARGETS.get(headIndex), id); ++ if (getRider() == null) this.entityData.set(WitherBoss.DATA_TARGETS.get(headIndex), id); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/Blaze.java b/src/main/java/net/minecraft/world/entity/monster/Blaze.java +index a1bbe0c34bd5693f041dca9028a5a52b2ca71bc5..a5294012d432d5d1fce570a1eb1b1716a24522de 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Blaze.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Blaze.java +@@ -32,6 +32,7 @@ public class Blaze extends Monster { + + public Blaze(EntityType type, Level world) { + super(type, world); ++ this.moveControl = new net.pl3x.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur + this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); + this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F); + this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 0.0F); +@@ -39,19 +40,50 @@ public class Blaze extends Monster { + this.xpReward = 10; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.blazeRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.blazeRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return level.purpurConfig.blazeMaxY; ++ } ++ ++ @Override ++ public void travel(Vec3 vec3) { ++ super.travel(vec3); ++ if (getRider() != null && !onGround) { ++ float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); ++ setSpeed(speed); ++ Vec3 mot = getDeltaMovement(); ++ move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed)); ++ setDeltaMovement(mot.scale(0.9D)); ++ } ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { ++ this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(4, new Blaze.BlazeAttackGoal(this)); + this.goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 1.0D)); + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D, 0.0F)); + this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)).setAlertOthers()); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); + } + + public static AttributeSupplier.Builder createAttributes() { +- return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0D).add(Attributes.MOVEMENT_SPEED, (double)0.23F).add(Attributes.FOLLOW_RANGE, 48.0D); ++ return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0D).add(Attributes.MOVEMENT_SPEED, (double)0.23F).add(Attributes.FOLLOW_RANGE, 48.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur + } + + @Override +@@ -106,6 +138,14 @@ public class Blaze extends Monster { + + @Override + protected void customServerAiStep() { ++ // Purpur start ++ if (getRider() != null) { ++ Vec3 mot = getDeltaMovement(); ++ setDeltaMovement(mot.x(), getVerticalMot() > 0 ? 0.07D : -0.07D, mot.z()); ++ return; ++ } ++ // Purpur end ++ + --this.nextHeightOffsetChangeTick; + if (this.nextHeightOffsetChangeTick <= 0) { + this.nextHeightOffsetChangeTick = 100; +diff --git a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java +index d980b906d9206560741576fa4153c57212f307a0..dd05c5f35d78d1385f793f4e34333ff242d136e1 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java +@@ -28,6 +28,18 @@ public class CaveSpider extends Spider { + return Spider.createAttributes().add(Attributes.MAX_HEALTH, 12.0D); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.caveSpiderRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.caveSpiderRidableInWater; ++ } ++ // Purpur end ++ + @Override + public boolean doHurtTarget(Entity target) { + if (super.doHurtTarget(target)) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java +index e8c36e8541f041a0d72a86f49ced2a3ce1549be0..1bf65519883585569a1acc780554505dc5d6c30b 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java +@@ -60,21 +60,89 @@ public class Creeper extends Monster implements PowerableMob { + public int maxSwell = 30; + public int explosionRadius = 3; + private int droppedSkulls; ++ // Purpur start ++ private int spacebarCharge = 0; ++ private int prevSpacebarCharge = 0; ++ private int powerToggleDelay = 0; ++ // Purpur end + + public Creeper(EntityType type, Level world) { + super(type, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return level.purpurConfig.creeperRidable; ++ } ++ ++ @Override ++ public boolean rideableUnderWater() { ++ return level.purpurConfig.creeperRidableInWater; ++ } ++ ++ @Override ++ protected void customServerAiStep() { ++ if (powerToggleDelay > 0) { ++ powerToggleDelay--; ++ } ++ if (getRider() != null) { ++ if (getRider().getForwardMot() != 0 || getRider().getStrafeMot() != 0) { ++ spacebarCharge = 0; ++ setIgnited(false); ++ } ++ if (spacebarCharge == prevSpacebarCharge) { ++ spacebarCharge = 0; ++ } ++ prevSpacebarCharge = spacebarCharge; ++ } ++ super.customServerAiStep(); ++ } ++ ++ @Override ++ public void onMount(Player rider) { ++ super.onMount(rider); ++ setIgnited(false); ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (powerToggleDelay > 0) { ++ return true; // just toggled power, do not jump or ignite ++ } ++ spacebarCharge++; ++ if (spacebarCharge > maxSwell - 2) { ++ spacebarCharge = 0; ++ if (getRider() != null && getRider().getBukkitEntity().hasPermission("allow.powered.creeper")) { ++ powerToggleDelay = 20; ++ setPowered(!isPowered()); ++ setIgnited(false); ++ return true; ++ } ++ } ++ if (!isIgnited()) { ++ if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0 && ++ getRider().getBukkitEntity().hasPermission("allow.special.creeper")) { ++ setIgnited(true); ++ return true; ++ } ++ } ++ return getForwardMot() == 0 && getStrafeMot() == 0; // do not jump if standing still ++ } ++ // Purpur end ++ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(2, new SwellGoal(this)); ++ this.goalSelector.addGoal(3, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Ocelot.class, 6.0F, 1.0D, 1.2D)); + this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Cat.class, 6.0F, 1.0D, 1.2D)); + this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0D, false)); + this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8D)); + this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); ++ this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, true)); + this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); + } +@@ -318,6 +386,7 @@ public class Creeper extends Monster implements PowerableMob { + com.destroystokyo.paper.event.entity.CreeperIgniteEvent event = new com.destroystokyo.paper.event.entity.CreeperIgniteEvent((org.bukkit.entity.Creeper) getBukkitEntity(), ignited); + if (event.callEvent()) { + this.entityData.set(Creeper.DATA_IS_IGNITED, event.isIgnited()); ++ if (!event.isIgnited()) setSwellDir(-1); // Purpur + } + } + // Paper end diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java index fdc01dee8a81f0376f3c0a154c4291d03ead7f8f..058f4e8729736f9650bb6b08e7aed28f9f78a89b 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Slime.java @@ -889,10 +2939,10 @@ index 74fc4fc2216cf82e1546ef3d567f2750b1240df1..c90dda3d62dab896f68481000c0b6db1 + } } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 361f7857e461578e90cb71e15027dadaf794cb69..5ad112baaa2dc0d56c0e7d36443eafd3ff0dc2c8 100644 +index 361f7857e461578e90cb71e15027dadaf794cb69..9d261356c549a41e4bd676d5be60f6470501f0ae 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -@@ -56,4 +56,530 @@ public class PurpurWorldConfig { +@@ -56,4 +56,532 @@ public class PurpurWorldConfig { PurpurConfig.config.addDefault("world-settings.default." + path, def); return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path)); } @@ -1369,9 +3419,11 @@ index 361f7857e461578e90cb71e15027dadaf794cb69..5ad112baaa2dc0d56c0e7d36443eafd3 + + public boolean witherRidable = false; + public boolean witherRidableInWater = false; ++ public double witherMaxY = 256D; + private void witherSettings() { + witherRidable = getBoolean("mobs.wither.ridable", witherRidable); + witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); ++ witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY); + } + + public boolean witherSkeletonRidable = false; diff --git a/patches/server/0007-Llama-API.patch b/patches/server/0007-Llama-API.patch index 54835c6f2..caf105c3d 100644 --- a/patches/server/0007-Llama-API.patch +++ b/patches/server/0007-Llama-API.patch @@ -25,7 +25,7 @@ index e037d618955de9a213a9cd90752b29d189faace4..34dec0a94840a8865f1d80857ec54a10 double d = this.llama.distanceToSqr(this.llama.getCaravanHead()); if (d > 676.0D) { diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java -index 5c31519193126b715105e1e83bb54f6a1681d19e..41b94ea6f3cc71b3521df8be15bf009404ce66d2 100644 +index 0671185c358398fe0c4c1dbf4ede2f3e8c4794fb..31d965119b0d6481a50fbc237600c529aac0702d 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java @@ -65,6 +65,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { @@ -36,7 +36,7 @@ index 5c31519193126b715105e1e83bb54f6a1681d19e..41b94ea6f3cc71b3521df8be15bf0094 public Llama(EntityType type, Level world) { super(type, world); -@@ -95,7 +96,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { +@@ -134,7 +135,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { if (!this.inventory.getItem(1).isEmpty()) { nbt.put("DecorItem", this.inventory.getItem(1).save(new CompoundTag())); } @@ -45,7 +45,7 @@ index 5c31519193126b715105e1e83bb54f6a1681d19e..41b94ea6f3cc71b3521df8be15bf0094 } @Override -@@ -107,6 +108,12 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { +@@ -146,6 +147,12 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { this.inventory.setItem(1, ItemStack.of(nbt.getCompound("DecorItem"))); } @@ -58,7 +58,7 @@ index 5c31519193126b715105e1e83bb54f6a1681d19e..41b94ea6f3cc71b3521df8be15bf0094 this.updateContainerEquipment(); } -@@ -426,6 +433,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { +@@ -467,6 +474,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { public void leaveCaravan() { if (this.caravanHead != null) { @@ -66,7 +66,7 @@ index 5c31519193126b715105e1e83bb54f6a1681d19e..41b94ea6f3cc71b3521df8be15bf0094 this.caravanHead.caravanTail = null; } -@@ -433,6 +441,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { +@@ -474,6 +482,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { } public void joinCaravan(Llama llama) { @@ -74,7 +74,7 @@ index 5c31519193126b715105e1e83bb54f6a1681d19e..41b94ea6f3cc71b3521df8be15bf0094 this.caravanHead = llama; this.caravanHead.caravanTail = this; } -@@ -450,6 +459,13 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { +@@ -491,6 +500,13 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { return this.caravanHead; } diff --git a/patches/server/0011-LivingEntity-safeFallDistance.patch b/patches/server/0011-LivingEntity-safeFallDistance.patch index cdd7f60d7..a8a0dbf88 100644 --- a/patches/server/0011-LivingEntity-safeFallDistance.patch +++ b/patches/server/0011-LivingEntity-safeFallDistance.patch @@ -37,10 +37,10 @@ index e733c1e8f0b180bf1508e4f004124d44407f6c07..0fc358d5491900affb61545d89a788bb protected void playBlockFallSound() { diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -index ba58e066cca533dfed7610a730c4dd7423fe124d..ff032dd031360cd4022dd19e772176d72e3e1340 100644 +index 919410ce27e7e42e297c2caba7d3d7c1b623aede..4dcacd1d156309abd29f48b9ac2d402395232e85 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -@@ -285,7 +285,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, +@@ -296,7 +296,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, @Override protected int calculateFallDamage(float fallDistance, float damageMultiplier) { diff --git a/patches/server/0027-Zombie-horse-naturally-spawn.patch b/patches/server/0027-Zombie-horse-naturally-spawn.patch index 8bf99af67..d7acb46c4 100644 --- a/patches/server/0027-Zombie-horse-naturally-spawn.patch +++ b/patches/server/0027-Zombie-horse-naturally-spawn.patch @@ -42,10 +42,10 @@ index 900b30c9ba0d7b9e0b19c23c1eb5b75dbf2d7141..e09f031f08efa7ed5145566de459b044 LightningBolt entitylightning = (LightningBolt) EntityType.LIGHTNING_BOLT.create((net.minecraft.world.level.Level) this); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 6790836b719bbab7c5ab8ead6efd9723b4f58cd1..d8011e5fe28458ae62f764cc355838bd08491f94 100644 +index 983ad996bef9f05772f176357ab3f78fd330f8f4..e66fd35e16e152d18b511d727558b50d5071633f 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -@@ -651,9 +651,11 @@ public class PurpurWorldConfig { +@@ -653,9 +653,11 @@ public class PurpurWorldConfig { public boolean zombieHorseRidableInWater = false; public boolean zombieHorseCanSwim = false; diff --git a/patches/server/0028-Charged-creeper-naturally-spawn.patch b/patches/server/0028-Charged-creeper-naturally-spawn.patch index 67d63116a..ec6f07f3e 100644 --- a/patches/server/0028-Charged-creeper-naturally-spawn.patch +++ b/patches/server/0028-Charged-creeper-naturally-spawn.patch @@ -5,59 +5,27 @@ Subject: [PATCH] Charged creeper naturally spawn diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index e8c36e8541f041a0d72a86f49ced2a3ce1549be0..27d8279b71f55ae711b0455bb4c5f1527a0e1ccb 100644 +index 1bf65519883585569a1acc780554505dc5d6c30b..f8fba694d53356036e302f66cfe92b15726242dc 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java +++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -11,6 +11,7 @@ import net.minecraft.server.level.ServerLevel; - import net.minecraft.sounds.SoundEvent; - import net.minecraft.sounds.SoundEvents; - import net.minecraft.util.Mth; -+import net.minecraft.world.DifficultyInstance; - import net.minecraft.world.InteractionHand; - import net.minecraft.world.InteractionResult; - import net.minecraft.world.damagesource.DamageSource; -@@ -20,7 +21,9 @@ import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntityType; - import net.minecraft.world.entity.LightningBolt; - import net.minecraft.world.entity.LivingEntity; -+import net.minecraft.world.entity.MobSpawnType; - import net.minecraft.world.entity.PowerableMob; -+import net.minecraft.world.entity.SpawnGroupData; - import net.minecraft.world.entity.ai.attributes.AttributeSupplier; - import net.minecraft.world.entity.ai.attributes.Attributes; - import net.minecraft.world.entity.ai.goal.AvoidEntityGoal; -@@ -38,10 +41,7 @@ import net.minecraft.world.entity.animal.goat.Goat; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.ItemStack; - import net.minecraft.world.item.Items; --import net.minecraft.world.level.Explosion; --import net.minecraft.world.level.GameRules; --import net.minecraft.world.level.ItemLike; --import net.minecraft.world.level.Level; -+import net.minecraft.world.level.*; - import net.minecraft.world.level.gameevent.GameEvent; - - // CraftBukkit start -@@ -65,6 +65,17 @@ public class Creeper extends Monster implements PowerableMob { - super(type, world); +@@ -129,6 +129,15 @@ public class Creeper extends Monster implements PowerableMob { + } + return getForwardMot() == 0 && getStrafeMot() == 0; // do not jump if standing still } - -+ // Purpur start ++ + @Override -+ public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { ++ public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor world, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, @Nullable net.minecraft.world.entity.SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { + double chance = world.getMinecraftWorld().purpurConfig.creeperChargedChance; + if (chance > 0D && random.nextDouble() <= chance) { + setPowered(true); + } + return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); + } -+ // Purpur end -+ + // Purpur end + @Override - protected void registerGoals() { - this.goalSelector.addGoal(1, new FloatGoal(this)); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index d8011e5fe28458ae62f764cc355838bd08491f94..375eb6499a91e73310e93d6d42eaa799751f22a2 100644 +index e66fd35e16e152d18b511d727558b50d5071633f..d2772e9d8cc9027994e98633594f20dc58a652cf 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -180,9 +180,11 @@ public class PurpurWorldConfig { diff --git a/patches/server/0029-Rabbit-naturally-spawn-toast-and-killer.patch b/patches/server/0029-Rabbit-naturally-spawn-toast-and-killer.patch index c8f66e1e3..bd71f0819 100644 --- a/patches/server/0029-Rabbit-naturally-spawn-toast-and-killer.patch +++ b/patches/server/0029-Rabbit-naturally-spawn-toast-and-killer.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Rabbit naturally spawn toast and killer diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -index 4a60afbb79ffb86d3c41b48d923ca8b3beca1c54..384f8abd0fd12906956d1459115f48738cc6e16d 100644 +index 29551a3b87f06c5876de5fda80615acf6c1f4764..8f99b4c28539c7c5a4951d7a3b82b01b77082794 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java +++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java -@@ -365,7 +365,11 @@ public class Rabbit extends Animal { +@@ -421,7 +421,11 @@ public class Rabbit extends Animal { if (!this.hasCustomName()) { this.setCustomName(new TranslatableComponent(Util.makeDescriptionId("entity", Rabbit.KILLER_BUNNY))); } @@ -20,7 +20,7 @@ index 4a60afbb79ffb86d3c41b48d923ca8b3beca1c54..384f8abd0fd12906956d1459115f4873 this.entityData.set(Rabbit.DATA_TYPE_ID, rabbitType); } -@@ -386,6 +390,16 @@ public class Rabbit extends Animal { +@@ -442,6 +446,16 @@ public class Rabbit extends Animal { } private int getRandomRabbitType(LevelAccessor world) { @@ -38,7 +38,7 @@ index 4a60afbb79ffb86d3c41b48d923ca8b3beca1c54..384f8abd0fd12906956d1459115f4873 int i = this.random.nextInt(100); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 375eb6499a91e73310e93d6d42eaa799751f22a2..100982bbf3f47a7c5d2da3e3f6957118c807b2f3 100644 +index d2772e9d8cc9027994e98633594f20dc58a652cf..c2a43e6f48da724ff737fec8d3bce0a3611b2465 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -456,9 +456,13 @@ public class PurpurWorldConfig { diff --git a/patches/server/0032-Tulips-change-fox-type.patch b/patches/server/0032-Tulips-change-fox-type.patch index 5d94265a2..931011fac 100644 --- a/patches/server/0032-Tulips-change-fox-type.patch +++ b/patches/server/0032-Tulips-change-fox-type.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Tulips change fox type diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java -index 31f4e4a93ea5fd3ffe7e60dff2e2a9642b51daa2..26470e4e07387fcf0c02c1f8845950eca4140a56 100644 +index 6cc8f6ef75e4b8b4282e4f664a83ce6491042df1..97101e7e0442417b57e15d6ec76d2a4c88862c81 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Fox.java +++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java @@ -34,6 +34,7 @@ import net.minecraft.tags.Tag; @@ -24,7 +24,7 @@ index 31f4e4a93ea5fd3ffe7e60dff2e2a9642b51daa2..26470e4e07387fcf0c02c1f8845950ec import net.minecraft.world.level.pathfinder.BlockPathTypes; import net.minecraft.world.phys.Vec3; -@@ -328,6 +330,11 @@ public class Fox extends Animal { +@@ -363,6 +365,11 @@ public class Fox extends Animal { } private void setTargetGoals() { @@ -36,7 +36,7 @@ index 31f4e4a93ea5fd3ffe7e60dff2e2a9642b51daa2..26470e4e07387fcf0c02c1f8845950ec if (this.getFoxType() == Fox.Type.RED) { this.targetSelector.addGoal(4, this.landTargetGoal); this.targetSelector.addGoal(4, this.turtleEggTargetGoal); -@@ -360,6 +367,7 @@ public class Fox extends Animal { +@@ -395,6 +402,7 @@ public class Fox extends Animal { public void setFoxType(Fox.Type type) { this.entityData.set(Fox.DATA_TYPE_ID, type.getId()); @@ -44,7 +44,7 @@ index 31f4e4a93ea5fd3ffe7e60dff2e2a9642b51daa2..26470e4e07387fcf0c02c1f8845950ec } List getTrustedUUIDs() { -@@ -690,6 +698,29 @@ public class Fox extends Animal { +@@ -725,6 +733,29 @@ public class Fox extends Animal { return this.getTrustedUUIDs().contains(uuid); } @@ -75,7 +75,7 @@ index 31f4e4a93ea5fd3ffe7e60dff2e2a9642b51daa2..26470e4e07387fcf0c02c1f8845950ec // Paper start - Cancellable death event protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(DamageSource source) { diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 100982bbf3f47a7c5d2da3e3f6957118c807b2f3..ce147273c7debd993af91df176cfe639ae95dfdc 100644 +index c2a43e6f48da724ff737fec8d3bce0a3611b2465..b949480d139ce6eb923c3efe788ac7a547f90c96 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -247,9 +247,11 @@ public class PurpurWorldConfig { diff --git a/patches/server/0033-Breedable-Polar-Bears.patch b/patches/server/0033-Breedable-Polar-Bears.patch index 7ef522bcd..924421325 100644 --- a/patches/server/0033-Breedable-Polar-Bears.patch +++ b/patches/server/0033-Breedable-Polar-Bears.patch @@ -5,36 +5,14 @@ Subject: [PATCH] Breedable Polar Bears diff --git a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java -index 0694cd0b994ee595adca43c988485e6dc13c7244..583bb80059b9351d27d15859b1687dd817ba165e 100644 +index dc6bc8f10d147cb1d0e5c69b6f6df63b0e8d4531..652e8a43af5830a9bc5a6bdd00ebec5a6e07dc3c 100644 --- a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java +++ b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java -@@ -32,6 +32,7 @@ import net.minecraft.world.entity.Pose; - import net.minecraft.world.entity.SpawnGroupData; - import net.minecraft.world.entity.ai.attributes.AttributeSupplier; - import net.minecraft.world.entity.ai.attributes.Attributes; -+import net.minecraft.world.entity.ai.goal.BreedGoal; - import net.minecraft.world.entity.ai.goal.FloatGoal; - import net.minecraft.world.entity.ai.goal.FollowParentGoal; - import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; -@@ -39,11 +40,13 @@ import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; - import net.minecraft.world.entity.ai.goal.PanicGoal; - import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; - import net.minecraft.world.entity.ai.goal.RandomStrollGoal; -+import net.minecraft.world.entity.ai.goal.TemptGoal; - import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; - import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; - import net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.ItemStack; -+import net.minecraft.world.item.crafting.Ingredient; - import net.minecraft.world.level.Level; - import net.minecraft.world.level.LevelAccessor; - import net.minecraft.world.level.ServerLevelAccessor; -@@ -66,6 +69,30 @@ public class PolarBear extends Animal implements NeutralMob { - super(type, world); +@@ -88,6 +88,28 @@ public class PolarBear extends Animal implements NeutralMob { + } + return false; } - -+ // Purpur start ++ + @Override + public boolean canMate(Animal other) { + if (other == this) { @@ -56,35 +34,33 @@ index 0694cd0b994ee595adca43c988485e6dc13c7244..583bb80059b9351d27d15859b1687dd8 + return this.isInLove() && bear.isInLove(); + } + } -+ // Purpur end -+ + // Purpur end + @Override - public AgeableMob getBreedOffspring(ServerLevel world, AgeableMob entity) { - return EntityType.POLAR_BEAR.create(world); -@@ -73,7 +100,7 @@ public class PolarBear extends Animal implements NeutralMob { +@@ -97,7 +119,7 @@ public class PolarBear extends Animal implements NeutralMob { @Override public boolean isFood(ItemStack stack) { - return false; -+ return level.purpurConfig.polarBearBreedableItem != null && stack.getItem() == level.purpurConfig.polarBearBreedableItem; // Purpur; ++ return level.purpurConfig.polarBearBreedableItem != null && stack.getItem() == level.purpurConfig.polarBearBreedableItem; // Purpur } @Override -@@ -82,6 +109,12 @@ public class PolarBear extends Animal implements NeutralMob { - this.goalSelector.addGoal(0, new FloatGoal(this)); +@@ -107,6 +129,12 @@ public class PolarBear extends Animal implements NeutralMob { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal()); this.goalSelector.addGoal(1, new PolarBear.PolarBearPanicGoal()); + // Purpur start + if (level.purpurConfig.polarBearBreedableItem != null) { -+ this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); -+ this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, Ingredient.of(level.purpurConfig.polarBearBreedableItem), false)); ++ this.goalSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.BreedGoal(this, 1.0D)); ++ this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.TemptGoal(this, 1.0D, net.minecraft.world.item.crafting.Ingredient.of(level.purpurConfig.polarBearBreedableItem), false)); + } + // Purpur end this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25D)); this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0D)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index ce147273c7debd993af91df176cfe639ae95dfdc..32b37da32b6cb2bb0a76a1759eacd28b8e32ece1 100644 +index b949480d139ce6eb923c3efe788ac7a547f90c96..3981e492b61d552735433fae05e13d1fe87637db 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -446,9 +446,14 @@ public class PurpurWorldConfig { diff --git a/patches/server/0034-Chickens-can-retaliate.patch b/patches/server/0034-Chickens-can-retaliate.patch index 33adab1dc..4cd5735de 100644 --- a/patches/server/0034-Chickens-can-retaliate.patch +++ b/patches/server/0034-Chickens-can-retaliate.patch @@ -5,38 +5,26 @@ Subject: [PATCH] Chickens can retaliate diff --git a/src/main/java/net/minecraft/world/entity/animal/Chicken.java b/src/main/java/net/minecraft/world/entity/animal/Chicken.java -index 8460bed561c09a647f6e0209f7c5448e5a42b281..56aee819372d4baacf73c345603ce889b3a60b52 100644 +index 771e55cceaf17167c00554b1be7043a4cb3efb7e..11bdc951087d8630a26f398f36a56a9e7c043d70 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Chicken.java +++ b/src/main/java/net/minecraft/world/entity/animal/Chicken.java -@@ -20,10 +20,12 @@ import net.minecraft.world.entity.ai.goal.BreedGoal; - import net.minecraft.world.entity.ai.goal.FloatGoal; - import net.minecraft.world.entity.ai.goal.FollowParentGoal; - import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; -+import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; - import net.minecraft.world.entity.ai.goal.PanicGoal; - import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; - import net.minecraft.world.entity.ai.goal.TemptGoal; - import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; -+import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.ItemStack; - import net.minecraft.world.item.Items; -@@ -52,16 +54,33 @@ public class Chicken extends Animal { - this.setPathfindingMalus(BlockPathTypes.WATER, 0.0F); +@@ -62,19 +62,34 @@ public class Chicken extends Animal { + public boolean rideableUnderWater() { + return level.purpurConfig.chickenRidableInWater; } - -+ // Purpur start ++ + @Override + protected void initAttributes() { + if (level.purpurConfig.chickenRetaliate) { + this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(2.0D); + } + } -+ // Purpur end -+ + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur - this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); + // this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); // Purpur - moved down this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); @@ -47,8 +35,8 @@ index 8460bed561c09a647f6e0209f7c5448e5a42b281..56aee819372d4baacf73c345603ce889 this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); + // Purpur start + if (level.purpurConfig.chickenRetaliate) { -+ this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0D, false)); -+ this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); ++ this.goalSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.0D, false)); ++ this.targetSelector.addGoal(1, new net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal(this)); + } else { + this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); + } @@ -56,7 +44,7 @@ index 8460bed561c09a647f6e0209f7c5448e5a42b281..56aee819372d4baacf73c345603ce889 } @Override -@@ -70,7 +89,7 @@ public class Chicken extends Animal { +@@ -83,7 +98,7 @@ public class Chicken extends Animal { } public static AttributeSupplier.Builder createAttributes() { @@ -66,7 +54,7 @@ index 8460bed561c09a647f6e0209f7c5448e5a42b281..56aee819372d4baacf73c345603ce889 @Override diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 32b37da32b6cb2bb0a76a1759eacd28b8e32ece1..f6f3910c5a9f011e1513174cb9d70080ddb5b024 100644 +index 3981e492b61d552735433fae05e13d1fe87637db..5154e14c88cf79c8da3290ff945fac0361e9e7c5 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -161,9 +161,11 @@ public class PurpurWorldConfig { diff --git a/patches/server/0039-Fix-cow-rotation-when-shearing-mooshroom.patch b/patches/server/0039-Fix-cow-rotation-when-shearing-mooshroom.patch index 22340d374..b011cf0a6 100644 --- a/patches/server/0039-Fix-cow-rotation-when-shearing-mooshroom.patch +++ b/patches/server/0039-Fix-cow-rotation-when-shearing-mooshroom.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix cow rotation when shearing mooshroom diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -index d9fb3df35de94ae5abbb86ace0328bbe6f5403b3..96f7ab847d05f461d4771a3fefbd32cab6366afa 100644 +index 0e066782ee09bb5626715bcc500bc04f2252bc2e..00f9553c5c653517b3e0c1c7d6b2ec4b7bd34b59 100644 --- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java +++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java -@@ -175,7 +175,13 @@ public class MushroomCow extends Cow implements Shearable { +@@ -187,7 +187,13 @@ public class MushroomCow extends Cow implements Shearable { entitycow.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); entitycow.setHealth(this.getHealth()); diff --git a/patches/server/0040-Pigs-give-saddle-back.patch b/patches/server/0040-Pigs-give-saddle-back.patch index afd0bc9b9..9e2537962 100644 --- a/patches/server/0040-Pigs-give-saddle-back.patch +++ b/patches/server/0040-Pigs-give-saddle-back.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Pigs give saddle back diff --git a/src/main/java/net/minecraft/world/entity/animal/Pig.java b/src/main/java/net/minecraft/world/entity/animal/Pig.java -index 2c95b6eddfe46e5d2ad495bfc86ccc24ae75e704..8a99b04e8179a640a289c4853777aa88c725216a 100644 +index 80c8ceda47bf8b3ff370f89a61aa01869d606ee6..ff3f8ba62eb086fbb007853535aafd085578ea21 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Pig.java +++ b/src/main/java/net/minecraft/world/entity/animal/Pig.java -@@ -155,6 +155,18 @@ public class Pig extends Animal implements ItemSteerable, Saddleable { +@@ -168,6 +168,18 @@ public class Pig extends Animal implements ItemSteerable, Saddleable { if (!flag && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) { if (!this.level.isClientSide) { @@ -28,7 +28,7 @@ index 2c95b6eddfe46e5d2ad495bfc86ccc24ae75e704..8a99b04e8179a640a289c4853777aa88 } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index e9a00422f9952c98d04c0cbb2ea32ea6231f50ed..e1da56c301be94c56c8377034ab948a1e4ecd071 100644 +index 0c7463c1d5c894c2d2bc9b6e422432e086a01446..84521916de0ce95333e95f458aac2a98e2ca1db0 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -433,9 +433,11 @@ public class PurpurWorldConfig { diff --git a/patches/server/0041-Snowman-drop-and-put-back-pumpkin.patch b/patches/server/0041-Snowman-drop-and-put-back-pumpkin.patch index 5d0ec38cc..908efa4ae 100644 --- a/patches/server/0041-Snowman-drop-and-put-back-pumpkin.patch +++ b/patches/server/0041-Snowman-drop-and-put-back-pumpkin.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Snowman drop and put back pumpkin diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -index 2631f08496c8e45874b22760b559a91b7b2bf415..226cadfc5f109b8f5060b5147034ac273f14133d 100644 +index a76f3c1c409dc96f7033be8a7eeb06617053735b..06b6afe0724b2738b350cc671bb3cb2570b1dbad 100644 --- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java +++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java -@@ -164,6 +164,14 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -179,6 +179,14 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM } return InteractionResult.sidedSuccess(this.level.isClientSide); @@ -19,11 +19,11 @@ index 2631f08496c8e45874b22760b559a91b7b2bf415..226cadfc5f109b8f5060b5147034ac27 + itemstack.shrink(1); + } + return InteractionResult.SUCCESS; -+ // Purpur end ++ // Purpur end } else { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } -@@ -174,6 +182,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM +@@ -189,6 +197,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM this.level.playSound((Player) null, (Entity) this, SoundEvents.SNOW_GOLEM_SHEAR, shearedSoundCategory, 1.0F, 1.0F); if (!this.level.isClientSide()) { this.setPumpkin(false); @@ -32,7 +32,7 @@ index 2631f08496c8e45874b22760b559a91b7b2bf415..226cadfc5f109b8f5060b5147034ac27 } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index e1da56c301be94c56c8377034ab948a1e4ecd071..4b039c4cd94c2ea1a61452530ca200d10829c166 100644 +index 84521916de0ce95333e95f458aac2a98e2ca1db0..6759bc46553d6fedb90597d73935d6255dbe5240 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -546,10 +546,14 @@ public class PurpurWorldConfig { diff --git a/patches/server/0042-Ender-dragon-always-drop-full-exp.patch b/patches/server/0042-Ender-dragon-always-drop-full-exp.patch index de3ac0f5d..a217c6f30 100644 --- a/patches/server/0042-Ender-dragon-always-drop-full-exp.patch +++ b/patches/server/0042-Ender-dragon-always-drop-full-exp.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Ender dragon always drop full exp diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -index c98202092752a9015aaf95bd1471135b88e84425..682b532967a501e21df93c28c4ee4b59eed073a7 100644 +index a1a64591e6a6fb8a4550b91f89e3cdbd35c6d249..3fd2d29e756d35a25e0cdd2ef10a5f1f48c230c0 100644 --- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -@@ -633,7 +633,7 @@ public class EnderDragon extends Mob implements Enemy { +@@ -704,7 +704,7 @@ public class EnderDragon extends Mob implements Enemy { boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT); short short0 = 500; @@ -18,7 +18,7 @@ index c98202092752a9015aaf95bd1471135b88e84425..682b532967a501e21df93c28c4ee4b59 } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 4b039c4cd94c2ea1a61452530ca200d10829c166..190c1d8878eb4d533d31c6b803b951cdf9747450 100644 +index 6759bc46553d6fedb90597d73935d6255dbe5240..6d88e8011add9c54470ab122aee325764e22bb2f 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -233,10 +233,12 @@ public class PurpurWorldConfig { diff --git a/patches/server/0054-Add-wither-skeleton-takes-wither-damage-option.patch b/patches/server/0054-Add-wither-skeleton-takes-wither-damage-option.patch index 80a23be64..dce102a52 100644 --- a/patches/server/0054-Add-wither-skeleton-takes-wither-damage-option.patch +++ b/patches/server/0054-Add-wither-skeleton-takes-wither-damage-option.patch @@ -17,10 +17,10 @@ index 033d6389e4b7d986fc63abd67e325b68a6132824..f290c7b50c48b798697c49c738700457 } } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 4d9c39e78f26ffb43d36a8c729bfd4ed136ff619..23b2895a3dd3e4d242ce11f89d4dad1c05e606fc 100644 +index b811b3db05e1bcc0fe5d641c6fa81cb4b1db9186..aa6e3b192fe80339df00c909d101449023d8f71f 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -@@ -745,9 +745,11 @@ public class PurpurWorldConfig { +@@ -747,9 +747,11 @@ public class PurpurWorldConfig { public boolean witherSkeletonRidable = false; public boolean witherSkeletonRidableInWater = false; diff --git a/patches/server/0057-Add-enderman-and-creeper-griefing-controls.patch b/patches/server/0057-Add-enderman-and-creeper-griefing-controls.patch index 8dd7e10e4..428e8263a 100644 --- a/patches/server/0057-Add-enderman-and-creeper-griefing-controls.patch +++ b/patches/server/0057-Add-enderman-and-creeper-griefing-controls.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add enderman and creeper griefing controls diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -index 27d8279b71f55ae711b0455bb4c5f1527a0e1ccb..689efb1a80a93d573cb109905105434281eba7d3 100644 +index f8fba694d53356036e302f66cfe92b15726242dc..72edd66a7e0b46b9575982210d8c9af03310c8d2 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java +++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java -@@ -270,7 +270,7 @@ public class Creeper extends Monster implements PowerableMob { +@@ -336,7 +336,7 @@ public class Creeper extends Monster implements PowerableMob { public void explodeCreeper() { if (!this.level.isClientSide) { @@ -38,7 +38,7 @@ index a39f4a1585ba888d27588a86130f6dae24f5a71b..b9cc542db0b5b9f7710c2f747cb9a4ed } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index c828459bc986aace14516985bc82f170bf34884c..60ea12540d41e6df52f2cf1f076c442501619148 100644 +index 7be145b284b0e618e9f52645a1e81c30e91ed186..f9756ee33ccfb011bda5c8b923d237d43e3a4093 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -284,10 +284,12 @@ public class PurpurWorldConfig { diff --git a/patches/server/0075-Configurable-jockey-options.patch b/patches/server/0075-Configurable-jockey-options.patch index 674a528e6..3d8aeeb96 100644 --- a/patches/server/0075-Configurable-jockey-options.patch +++ b/patches/server/0075-Configurable-jockey-options.patch @@ -184,7 +184,7 @@ index 233b390541acddcf815db4a8f299496eaea4f758..a50191aac887dffd3a7930455cb222fa public void setPersistentAngerTarget(@Nullable UUID uuid) { this.persistentAngerTarget = uuid; diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index aa984c2eebf2529e0be42b01ec7678d1f5157e0d..e39e1ff19f49b093ae27a98cba280ad2643df7a2 100644 +index 0453764a9b47e3997aa32cda489e7f71d94b7e04..87f9ad516e8dd0c92b08c9054e086d8315c87c41 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -399,9 +399,15 @@ public class PurpurWorldConfig { @@ -219,7 +219,7 @@ index aa984c2eebf2529e0be42b01ec7678d1f5157e0d..e39e1ff19f49b093ae27a98cba280ad2 } public boolean illusionerRidable = false; -@@ -877,9 +889,15 @@ public class PurpurWorldConfig { +@@ -879,9 +891,15 @@ public class PurpurWorldConfig { public boolean zombieRidable = false; public boolean zombieRidableInWater = false; @@ -235,7 +235,7 @@ index aa984c2eebf2529e0be42b01ec7678d1f5157e0d..e39e1ff19f49b093ae27a98cba280ad2 } public boolean zombieHorseRidableInWater = false; -@@ -893,15 +911,27 @@ public class PurpurWorldConfig { +@@ -895,15 +913,27 @@ public class PurpurWorldConfig { public boolean zombieVillagerRidable = false; public boolean zombieVillagerRidableInWater = false; diff --git a/patches/server/0096-Add-option-to-disable-dolphin-treasure-searching.patch b/patches/server/0096-Add-option-to-disable-dolphin-treasure-searching.patch index 70be3d37b..880ea29ef 100644 --- a/patches/server/0096-Add-option-to-disable-dolphin-treasure-searching.patch +++ b/patches/server/0096-Add-option-to-disable-dolphin-treasure-searching.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add option to disable dolphin treasure searching diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -index f3093815066e6881a2bb638ae4643f69374450b3..868a44fa2c54c43ed3dc3e3c346810588081ec1d 100644 +index 2300abc4e80449e6b92992f6fb8cfe8e99dea351..12a602a4a3b3e883ed04621fe627feb146f8afb9 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java +++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java -@@ -417,6 +417,7 @@ public class Dolphin extends WaterAnimal { +@@ -492,6 +492,7 @@ public class Dolphin extends WaterAnimal { @Override public boolean canUse() { @@ -17,7 +17,7 @@ index f3093815066e6881a2bb638ae4643f69374450b3..868a44fa2c54c43ed3dc3e3c34681058 } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 8797f781b97cece949dfb1014470f164503e61c4..5bead011214ca37dc59efafce845285ab07c409e 100644 +index fff9679bfc715e8df5f88c2850c9623e1eef270f..1ca413f7a6cc2d445a2b026e7266919880692575 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -465,11 +465,13 @@ public class PurpurWorldConfig { diff --git a/patches/server/0098-Stop-squids-floating-on-top-of-water.patch b/patches/server/0098-Stop-squids-floating-on-top-of-water.patch index 6926c16d0..627318e63 100644 --- a/patches/server/0098-Stop-squids-floating-on-top-of-water.patch +++ b/patches/server/0098-Stop-squids-floating-on-top-of-water.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Stop squids floating on top of water diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 3eebc432befec2223e487a6bd48f30d2160feb0a..1950cd258f69f9c9430cda9ddd479277cc0fb6c9 100644 +index 73d1efb6eb6a96368db57f316867cfc027159056..f9d8d5ef1ca960324351fa1151f79906950845b3 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -3632,11 +3632,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n @@ -28,32 +28,22 @@ index 3eebc432befec2223e487a6bd48f30d2160feb0a..1950cd258f69f9c9430cda9ddd479277 int j = Mth.ceil(axisalignedbb.maxX); int k = Mth.floor(axisalignedbb.minY); diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java -index 56838c9f214c0f75041e75c45ad1a0c72fcacc66..8c9454612e71f1d1a82c6a13c7788dd9b892fedc 100644 +index 0a744855f24ac54b22bc474a1c903da7af656364..d6e35d1fec3eee80a7eafaa1997fee16f6ef5d04 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Squid.java +++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java -@@ -29,6 +29,7 @@ import net.minecraft.world.level.Level; - import net.minecraft.world.level.LevelAccessor; - import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.level.material.FluidState; -+import net.minecraft.world.phys.AABB; - import net.minecraft.world.phys.Vec3; - - public class Squid extends WaterAnimal { -@@ -54,6 +55,14 @@ public class Squid extends WaterAnimal { - this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F; +@@ -74,6 +74,12 @@ public class Squid extends WaterAnimal { + vector.setX(cos * x - sine * z); + vector.setZ(sine * x + cos * z); } - -+ // Purpur start ++ + @Override -+ public AABB getAxisForFluidCheck() { ++ public net.minecraft.world.phys.AABB getAxisForFluidCheck() { + // Stops squids from floating just over the water + return this.getBoundingBox().deflate(0.001D).offsetY(level.purpurConfig.squidOffsetWaterCheck); + } -+ // Purpur end -+ + // Purpur end + @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java index 4eeb186231551a9df453ec9d6a8a9dc9f8835464..1e184724e112b28ff4abb6ecf5d564c260e795ba 100644 --- a/src/main/java/net/minecraft/world/phys/AABB.java @@ -70,7 +60,7 @@ index 4eeb186231551a9df453ec9d6a8a9dc9f8835464..1e184724e112b28ff4abb6ecf5d564c2 + // Purpur } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 5bead011214ca37dc59efafce845285ab07c409e..a339f842ec00253adc668fbb2b65c0513f23163a 100644 +index 1ca413f7a6cc2d445a2b026e7266919880692575..6e33bee4f01138bc0b553a318e87e3b6c6e0966d 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -871,9 +871,11 @@ public class PurpurWorldConfig { diff --git a/patches/server/0103-Customizable-wither-health-and-healing.patch b/patches/server/0103-Customizable-wither-health-and-healing.patch index cd9dde07c..f33a41cb4 100644 --- a/patches/server/0103-Customizable-wither-health-and-healing.patch +++ b/patches/server/0103-Customizable-wither-health-and-healing.patch @@ -6,24 +6,22 @@ Subject: [PATCH] Customizable wither health and healing Adds the ability to customize the health of the wither, as well as the amount that it heals, and how often. diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 1c8f6863b976cfcb559de9b3e3cf9292831166ee..7858e97db83085721310f7c9e35abe0b944b3b1f 100644 +index 0b1f6fad51a985ebe4ccebde12a1db9e12a57bc0..a91480bfecd17ef45e3380c726a42cd7534f07ae 100644 --- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -97,6 +97,13 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob - this.xpReward = 50; +@@ -196,6 +196,11 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob + skull.setPosRaw(headX, headY, headZ); + level.addFreshEntity(skull); } - -+ // Purpur start ++ + @Override + public void initAttributes() { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(level.purpurConfig.witherMaxHealth); + } -+ // Purpur end -+ + // Purpur end + @Override - protected void registerGoals() { - this.goalSelector.addGoal(0, new WitherBoss.WitherDoNothingGoal()); -@@ -288,7 +295,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -401,7 +406,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob this.setInvulnerableTicks(i); if (this.tickCount % 10 == 0) { @@ -32,7 +30,7 @@ index 1c8f6863b976cfcb559de9b3e3cf9292831166ee..7858e97db83085721310f7c9e35abe0b } } else { -@@ -381,8 +388,10 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob +@@ -494,8 +499,10 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob } } @@ -46,19 +44,20 @@ index 1c8f6863b976cfcb559de9b3e3cf9292831166ee..7858e97db83085721310f7c9e35abe0b this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index a6a6b766b5dc5b3743aecd0a2c8021d04df1d8d2..2681463ae89ea4e0746425114feb24aed0f34cb3 100644 +index ae46aafd1a19e183e9a77fec8c0556a35c70c521..be3b2cc6fb2f8f01e38fb4a47324c825fee2aee7 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -@@ -992,9 +992,20 @@ public class PurpurWorldConfig { - +@@ -993,10 +993,21 @@ public class PurpurWorldConfig { public boolean witherRidable = false; public boolean witherRidableInWater = false; + public double witherMaxY = 256D; + public float witherHealthRegenAmount = 1.0f; + public int witherHealthRegenDelay = 20; + public double witherMaxHealth = 300.0D; private void witherSettings() { witherRidable = getBoolean("mobs.wither.ridable", witherRidable); witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); + witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY); + witherHealthRegenAmount = (float) getDouble("mobs.wither.health-regen-amount", witherHealthRegenAmount); + witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay); + if (PurpurConfig.version < 8) { diff --git a/patches/server/0107-Add-option-to-disable-zombie-aggressiveness-towards-.patch b/patches/server/0107-Add-option-to-disable-zombie-aggressiveness-towards-.patch index 743dd6b2e..ea80d354d 100644 --- a/patches/server/0107-Add-option-to-disable-zombie-aggressiveness-towards-.patch +++ b/patches/server/0107-Add-option-to-disable-zombie-aggressiveness-towards-.patch @@ -71,10 +71,10 @@ index 747f872e0c9eef620f7713e674304e8f47738b1c..0f0df28c0d382cca5dc0556e03d7d465 this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -index 53bda6f49386eb606ca259519f1494e3c5f144a5..cd1373f113f434aa0d3d3ea07096095dc99dbc18 100644 +index 1d55be36c8d075b48db1862e63bc28bbabad3a18..2c963f72caff78488ceb2a43abbad18013e1433f 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java -@@ -1093,12 +1093,14 @@ public class PurpurWorldConfig { +@@ -1095,12 +1095,14 @@ public class PurpurWorldConfig { public boolean zombieJockeyOnlyBaby = true; public double zombieJockeyChance = 0.05D; public boolean zombieJockeyTryExistingChickens = true;