From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: William Blake Galbreath Date: Sun, 5 Jul 2020 22:19:49 -0500 Subject: [PATCH] Ridables diff --git a/net/minecraft/gametest/framework/GameTestHelper.java b/net/minecraft/gametest/framework/GameTestHelper.java index 29d402620d2e1cbed94f941f933ae8eb5d786e7f..ec0998369158286fccb38c8e10c3cfa2a653a8aa 100644 --- a/net/minecraft/gametest/framework/GameTestHelper.java +++ b/net/minecraft/gametest/framework/GameTestHelper.java @@ -281,6 +281,8 @@ public class GameTestHelper { public void setAfk(final boolean afk) {} // Purpur - AFK API + public void resetLastActionTime() {} // Purpur - Ridables + @Override public boolean isLocalPlayer() { return true; diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java index 121b57c7f5345f5d8884eaa1d36dac79fb7d42ef..9afbfe9bf493e09ca1963e8956ab7573964479b4 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -1745,6 +1745,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - Add EntityMoveEvent serverLevel.updateLagCompensationTick(); // Paper - lag compensation net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers + serverLevel.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - Ridables profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location()); /* Drop global time updates if (this.tickCount % 20 == 0) { diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java index 5cf2c7f8fb05a91ed17f1d9c07f7d3e748738058..3770dc90d9412c6378c0bd57a651b9c3e62b9a72 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -217,6 +217,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current) + public boolean hasRidableMoveEvent = false; // Purpur - Ridables public LevelChunk getChunkIfLoaded(int x, int z) { return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java index 11b6149380ea6ca514a607801d499d740ce3d6dd..362e1bd5d19888535eb40f7ca7a9a5ef508f3c4a 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -848,6 +848,15 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc this.trackEnteredOrExitedLavaOnVehicle(); this.updatePlayerAttributes(); this.advancements.flushDirty(this); + + // Purpur start - Ridables + if (this.level().purpurConfig.useNightVisionWhenRiding && this.getVehicle() != null && this.getVehicle().getRider() == this && this.level().getGameTime() % 100 == 0) { // 5 seconds + MobEffectInstance nightVision = this.getEffect(MobEffects.NIGHT_VISION); + if (nightVision == null || nightVision.getDuration() <= 300) { // 15 seconds + this.addEffect(new MobEffectInstance(MobEffects.NIGHT_VISION, 400, 0)); // 20 seconds + } + } + // Purpur end - Ridables } private void updatePlayerAttributes() { diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java index d0dc5d6f25b7514bc3c65bbef5b40703f6d0eed7..f524f1de2093e0a3bd2f3cf8806232b2211d0583 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -2828,6 +2828,8 @@ public class ServerGamePacketListenerImpl ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event); + player.processClick(hand); // Purpur - Ridables + // Entity in bucket - SPIGOT-4048 and SPIGOT-6859a if ((target instanceof Bucketable && target instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) { target.resendPossiblyDesyncedEntityData(ServerGamePacketListenerImpl.this.player); // Paper - The entire mob gets deleted, so resend it diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java index 474e5b8163e82a76aea8c4402d6acfcd366acaef..e4ee886f33ee63ae740cd89067c8ec81c12f2a62 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -3155,6 +3155,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.passengers = ImmutableList.copyOf(list); } + // Purpur start - Ridables + if (isRidable() && this.passengers.get(0) == passenger && passenger instanceof Player player) { + onMount(player); + this.rider = player; + } + // Purpur end - Ridables + this.gameEvent(GameEvent.ENTITY_MOUNT, passenger); } } @@ -3196,6 +3203,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return false; } // CraftBukkit end + + // Purpur start - Ridables + if (this.rider != null && this.passengers.get(0) == this.rider) { + onDismount(this.rider); + this.rider = null; + } + // Purpur end - Ridables + if (this.passengers.size() == 1 && this.passengers.get(0) == passenger) { this.passengers = ImmutableList.of(); } else { @@ -5119,4 +5134,44 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return ((ServerLevel) this.level).isPositionEntityTicking(this.blockPosition()); } // Paper end - Expose entity id counter + // Purpur start - Ridables + @Nullable + private Player rider = null; + + @Nullable + public Player getRider() { + return rider; + } + + public boolean isRidable() { + return false; + } + + public boolean isControllable() { + return true; + } + + public void onMount(Player rider) { + if (this instanceof Mob) { + ((Mob) this).setTarget(null, null, false); + ((Mob) this).getNavigation().stop(); + } + rider.setJumping(false); // fixes jump on mount + } + + public void onDismount(Player player) { + } + + public boolean onSpacebar() { + return false; + } + + public boolean onClick(InteractionHand hand) { + return false; + } + + public boolean processClick(InteractionHand hand) { + return false; + } + // Purpur end - Ridables } diff --git a/net/minecraft/world/entity/GlowSquid.java b/net/minecraft/world/entity/GlowSquid.java index 95d78dcdb6777df73898694367ee17b1cb76d7a2..d0313fd5368baa53ec511c8c07fc78a1f1ecec4e 100644 --- a/net/minecraft/world/entity/GlowSquid.java +++ b/net/minecraft/world/entity/GlowSquid.java @@ -32,6 +32,19 @@ public class GlowSquid extends Squid { } // Purpur end - Flying squids! Oh my! + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.glowSquidRidable; + } + + + @Override + public boolean isControllable() { + return level().purpurConfig.glowSquidControllable; + } + // Purpur end - Ridables + @Override protected ParticleOptions getInkParticle() { return ParticleTypes.GLOW_SQUID_INK; diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java index f41d5ffe83e3cfb4c30d150f8b66f8f2568ae20c..8c2bdb1775f7c4110c5f967b1052eba6a8fcbbfa 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java @@ -250,9 +250,9 @@ public abstract class LivingEntity extends Entity implements Attackable { protected float rotOffs; public float lastHurt; public boolean jumping; - public float xxa; - public float yya; - public float zza; + public float xxa; public float getStrafeMot() { return xxa; } public void setStrafeMot(float strafe) { xxa = strafe; } // Purpur - OBFHELPER + public float yya; public float getVerticalMot() { return yya; } public void setVerticalMot(float vertical) { yya = vertical; } // Purpur - OBFHELPER + public float zza; public float getForwardMot() { return zza; } public void setForwardMot(float forward) { zza = forward; } // Purpur - OBFHELPER protected int lerpSteps; protected double lerpX; protected double lerpY; @@ -310,7 +310,7 @@ public abstract class LivingEntity extends Entity implements Attackable { protected LivingEntity(EntityType entityType, Level level) { super(entityType, level); - this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entityType)); + this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entityType), this); // Purpur - Ridables this.craftAttributes = new CraftAttributeMap(this.attributes); // CraftBukkit // CraftBukkit - this.setHealth(this.getMaxHealth()) inlined and simplified to skip the instanceof check for Player, as getBukkitEntity() is not initialized in constructor this.entityData.set(LivingEntity.DATA_HEALTH_ID, this.getMaxHealth()); @@ -377,6 +377,7 @@ public abstract class LivingEntity extends Entity implements Attackable { .add(Attributes.MOVEMENT_EFFICIENCY) .add(Attributes.ATTACK_KNOCKBACK); } + public boolean shouldSendAttribute(Attribute attribute) { return true; } // Purpur - Ridables @Override protected void checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos) { @@ -3537,8 +3538,10 @@ public abstract class LivingEntity extends Entity implements Attackable { this.pushEntities(); profilerFiller.pop(); // Paper start - Add EntityMoveEvent - if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof Player)) { - if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { + // Purpur start - Ridables + if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { + if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof Player)) { + // Purpur end - Ridables Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO); Location to = new Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); io.papermc.paper.event.entity.EntityMoveEvent event = new io.papermc.paper.event.entity.EntityMoveEvent(this.getBukkitLivingEntity(), from, to.clone()); @@ -3548,6 +3551,21 @@ public abstract class LivingEntity extends Entity implements Attackable { this.absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch()); } } + // Purpur start - Ridables + if (getRider() != null) { + getRider().resetLastActionTime(); + if (((ServerLevel) level()).hasRidableMoveEvent && this instanceof Mob) { + Location from = new Location(level().getWorld(), xo, yo, zo, this.yRotO, this.xRotO); + Location to = new Location(level().getWorld(), getX(), getY(), getZ(), this.getYRot(), this.getXRot()); + org.purpurmc.purpur.event.entity.RidableMoveEvent event = new org.purpurmc.purpur.event.entity.RidableMoveEvent((org.bukkit.entity.Mob) getBukkitLivingEntity(), (org.bukkit.entity.Player) getRider().getBukkitEntity(), from, to.clone()); + if (!event.callEvent()) { + absMoveTo(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch()); + } else if (!to.equals(event.getTo())) { + absMoveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); + } + } + } + // Purpur end - Ridables } // Paper end - Add EntityMoveEvent if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java index 26f7cd5ddacf5f908702adbf55b56dcc6fcbe162..c431f28c3f4f6cec946048f5752c364429af5ba1 100644 --- a/net/minecraft/world/entity/Mob.java +++ b/net/minecraft/world/entity/Mob.java @@ -151,8 +151,8 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab super(entityType, level); this.goalSelector = new GoalSelector(); this.targetSelector = new GoalSelector(); - this.lookControl = new LookControl(this); - this.moveControl = new MoveControl(this); + this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this); // Purpur - Ridables + this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this); // Purpur - Ridables this.jumpControl = new JumpControl(this); this.bodyRotationControl = this.createBodyControl(); this.navigation = this.createNavigation(level); @@ -1405,7 +1405,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab } protected InteractionResult mobInteract(Player player, InteractionHand hand) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur - Ridables } public boolean isWithinRestriction() { @@ -1723,4 +1723,58 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab public float[] getArmorDropChances() { return this.armorDropChances; } + + // Purpur start - Ridables + public double getMaxY() { + return level().getHeight(); + } + + public InteractionResult tryRide(Player player, InteractionHand hand) { + return tryRide(player, hand, InteractionResult.PASS); + } + + public InteractionResult tryRide(Player player, InteractionHand hand, InteractionResult result) { + if (!isRidable()) { + return result; + } + if (hand != InteractionHand.MAIN_HAND) { + return InteractionResult.PASS; + } + if (player.isShiftKeyDown()) { + return InteractionResult.PASS; + } + if (!player.getItemInHand(hand).isEmpty()) { + return InteractionResult.PASS; + } + if (!passengers.isEmpty() || player.isPassenger()) { + return InteractionResult.PASS; + } + if (this instanceof TamableAnimal tamable) { + if (tamable.isTame() && !tamable.isOwnedBy(player)) { + return InteractionResult.PASS; + } + if (!tamable.isTame() && !level().purpurConfig.untamedTamablesAreRidable) { + return InteractionResult.PASS; + } + } + if (this instanceof AgeableMob ageable) { + if (ageable.isBaby() && !level().purpurConfig.babiesAreRidable) { + return InteractionResult.PASS; + } + } + if (!player.getBukkitEntity().hasPermission("allow.ride." + net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getKey(getType()).getPath())) { + if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { + serverPlayer.sendMiniMessage(org.purpurmc.purpur.PurpurConfig.cannotRideMob); + } + return InteractionResult.PASS; + } + player.setYRot(this.getYRot()); + player.setXRot(this.getXRot()); + if (player.startRiding(this)) { + return InteractionResult.SUCCESS; + } else { + return InteractionResult.PASS; + } + } + // Purpur end - Ridables } diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java index 4c808c7ef336de74048f40bd1cc8b14131a9325d..a25d74592e89e3d6339479c6dc2b6f45d1932cfc 100644 --- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java +++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java @@ -23,14 +23,21 @@ public class AttributeMap { private final Set attributesToSync = new ObjectOpenHashSet<>(); private final Set attributesToUpdate = new ObjectOpenHashSet<>(); private final AttributeSupplier supplier; + private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables public AttributeMap(AttributeSupplier supplier) { - this.supplier = supplier; + // Purpur start - Ridables + this(supplier, null); + } + public AttributeMap(AttributeSupplier defaultAttributes, net.minecraft.world.entity.LivingEntity entity) { + this.entity = entity; + // Purpur end - Ridables + this.supplier = defaultAttributes; } private void onAttributeModified(AttributeInstance instance) { this.attributesToUpdate.add(instance); - if (instance.getAttribute().value().isClientSyncable()) { + if (instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur - Ridables this.attributesToSync.add(instance); } } @@ -44,7 +51,7 @@ public class AttributeMap { } public Collection getSyncableAttributes() { - return this.attributes.values().stream().filter(instance -> instance.getAttribute().value().isClientSyncable()).collect(Collectors.toList()); + return this.attributes.values().stream().filter(instance -> instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))).collect(Collectors.toList()); // Purpur - Ridables } @Nullable diff --git a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java index 33527a1825119f3667fb3c7ccec318f2c7328ec9..61ed4d687120fcbb7b91863e400f3657ebcde687 100644 --- a/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java +++ b/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java @@ -131,7 +131,7 @@ public class DefaultAttributes { .put(EntityType.OCELOT, Ocelot.createAttributes().build()) .put(EntityType.PANDA, Panda.createAttributes().build()) .put(EntityType.PARROT, Parrot.createAttributes().build()) - .put(EntityType.PHANTOM, Monster.createMonsterAttributes().build()) + .put(EntityType.PHANTOM, net.minecraft.world.entity.monster.Phantom.createAttributes().build()) // Purpur - Ridables .put(EntityType.PIG, Pig.createAttributes().build()) .put(EntityType.PIGLIN, Piglin.createAttributes().build()) .put(EntityType.PIGLIN_BRUTE, PiglinBrute.createAttributes().build()) diff --git a/net/minecraft/world/entity/ai/control/MoveControl.java b/net/minecraft/world/entity/ai/control/MoveControl.java index 0f9bf0cb0655a6ed449a86e99b17f89b4e3264df..1860b4ab2314f5da017313977c6423e735a4f96b 100644 --- a/net/minecraft/world/entity/ai/control/MoveControl.java +++ b/net/minecraft/world/entity/ai/control/MoveControl.java @@ -29,6 +29,20 @@ public class MoveControl implements Control { this.mob = mob; } + // Purpur start - Ridables + public void setSpeedModifier(double speed) { + this.speedModifier = speed; + } + + public void setForward(float forward) { + this.strafeForwards = forward; + } + + public void setStrafe(float strafe) { + this.strafeRight = strafe; + } + // Purpur end - Ridables + public boolean hasWanted() { return this.operation == MoveControl.Operation.MOVE_TO; } diff --git a/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java b/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java index d7f9b3b2b1077ea10e8f64b87c8f4c4354e90858..713f62b34a91fa76f40e49a5e390145f70755e58 100644 --- a/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java +++ b/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java @@ -3,7 +3,7 @@ package net.minecraft.world.entity.ai.control; import net.minecraft.util.Mth; import net.minecraft.world.entity.Mob; -public class SmoothSwimmingLookControl extends LookControl { +public class SmoothSwimmingLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables private final int maxYRotFromCenter; private static final int HEAD_TILT_X = 10; private static final int HEAD_TILT_Y = 20; @@ -14,7 +14,7 @@ public class SmoothSwimmingLookControl extends LookControl { } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (this.lookAtCooldown > 0) { this.lookAtCooldown--; this.getYRotD().ifPresent(rotationWanted -> this.mob.yHeadRot = this.rotateTowards(this.mob.yHeadRot, rotationWanted + 20.0F, this.yMaxRotSpeed)); diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java index 4d715a29f1ad31e87977562bd0e2aeddb54ee082..e7ea944e77175ee4051b8e7361c502d0cc2115d5 100644 --- a/net/minecraft/world/entity/ambient/Bat.java +++ b/net/minecraft/world/entity/ambient/Bat.java @@ -42,11 +42,58 @@ public class Bat extends AmbientCreature { public Bat(EntityType entityType, Level level) { super(entityType, level); + this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.075F); // Purpur - Ridables if (!level.isClientSide) { this.setResting(true); } } + // Purpur start - Ridables + @Override + public boolean shouldSendAttribute(net.minecraft.world.entity.ai.attributes.Attribute attribute) { return attribute != Attributes.FLYING_SPEED.value(); } // Fixes log spam on clients + + @Override + public boolean isRidable() { + return level().purpurConfig.batRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.batRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.batControllable; + } + + @Override + public double getMaxY() { + return level().purpurConfig.batMaxY; + } + + @Override + public void onMount(net.minecraft.world.entity.player.Player rider) { + super.onMount(rider); + if (isResting()) { + setResting(false); + level().levelEvent(null, 1025, new BlockPos(this).above(), 0); + } + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && this.isControllable() && !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 - Ridables + @Override public boolean isFlapping() { return !this.isResting() && this.tickCount % 10.0F == 0.0F; @@ -98,7 +145,7 @@ public class Bat extends AmbientCreature { } public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0); + return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - Ridables } public boolean isResting() { @@ -129,6 +176,14 @@ public class Bat extends AmbientCreature { @Override protected void customServerAiStep(ServerLevel level) { + // Purpur start - Ridables + if (getRider() != null && this.isControllable()) { + Vec3 mot = getDeltaMovement(); + setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z()); + return; + } + // Purpur end - Ridables + super.customServerAiStep(level); BlockPos blockPos = this.blockPosition(); BlockPos blockPos1 = blockPos.above(); diff --git a/net/minecraft/world/entity/animal/AbstractFish.java b/net/minecraft/world/entity/animal/AbstractFish.java index c0997c8c0f8ee4474d3acdd5938b1879c4e589a2..28ae152125ed83d8917674b6068f227f87890f30 100644 --- a/net/minecraft/world/entity/animal/AbstractFish.java +++ b/net/minecraft/world/entity/animal/AbstractFish.java @@ -87,6 +87,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { @Override protected void registerGoals() { super.registerGoals(); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(0, new PanicGoal(this, 1.25)); this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6, 1.4, EntitySelector.NO_SPECTATORS::test)); this.goalSelector.addGoal(4, new AbstractFish.FishSwimGoal(this)); @@ -100,7 +101,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { @Override public void travel(Vec3 travelVector) { if (this.isControlledByLocalInstance() && this.isInWater()) { - this.moveRelative(0.01F, travelVector); + this.moveRelative(getRider() != null ? getSpeed() : 0.01F, travelVector); // Purpur - Ridables this.move(MoverType.SELF, this.getDeltaMovement()); this.setDeltaMovement(this.getDeltaMovement().scale(0.9)); if (this.getTarget() == null) { @@ -160,7 +161,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { protected void playStepSound(BlockPos pos, BlockState block) { } - static class FishMoveControl extends MoveControl { + static class FishMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur - Ridables private final AbstractFish fish; FishMoveControl(AbstractFish mob) { @@ -168,14 +169,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { this.fish = mob; } + // Purpur start - Ridables @Override - public void tick() { + public void purpurTick(Player rider) { + super.purpurTick(rider); + fish.setDeltaMovement(fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); + } + // Purpur end - Ridables + + @Override + public void vanillaTick() { // Purpur - Ridables if (this.fish.isEyeInFluid(FluidTags.WATER)) { this.fish.setDeltaMovement(this.fish.getDeltaMovement().add(0.0, 0.005, 0.0)); } 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 - Ridables this.fish.setSpeed(Mth.lerp(0.125F, this.fish.getSpeed(), f)); double d = this.wantedX - this.fish.getX(); double d1 = this.wantedY - this.fish.getY(); diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java index 3793570827eb6ca21c6b990d76c679c00ad100f4..af0cf64b4c74d290dec8032f8a6127867e301130 100644 --- a/net/minecraft/world/entity/animal/Bee.java +++ b/net/minecraft/world/entity/animal/Bee.java @@ -145,6 +145,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { public Bee(EntityType entityType, Level level) { super(entityType, level); + final org.purpurmc.purpur.controller.FlyingMoveControllerWASD flyingController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.25F, 1.0F, false); // Purpur - Ridables // Paper start - Fix MC-167279 class BeeFlyingMoveControl extends FlyingMoveControl { public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) { @@ -153,11 +154,24 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @Override public void tick() { + // Purpur start - Ridables + if (mob.getRider() != null && mob.isControllable()) { + flyingController.purpurTick(mob.getRider()); + return; + } + // Purpur end - Ridables if (this.mob.getY() <= Bee.this.level().getMinY()) { this.mob.setNoGravity(false); } super.tick(); } + + // Purpur start - Ridables + @Override + public boolean hasWanted() { + return mob.getRider() != null || !mob.isControllable() || super.hasWanted(); + } + // Purpur end - Ridables } this.moveControl = new BeeFlyingMoveControl(this, 20, true); // Paper end - Fix MC-167279 @@ -169,6 +183,40 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { this.setPathfindingMalus(PathType.FENCE, -1.0F); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.beeRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.beeRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.beeControllable; + } + + @Override + public double getMaxY() { + return level().purpurConfig.beeMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && this.isControllable() && !onGround) { + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; + setSpeed(speed); + Vec3 mot = getDeltaMovement(); + move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } + // Purpur end - Ridables + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); @@ -183,6 +231,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(0, new Bee.BeeAttackGoal(this, 1.4F, true)); this.goalSelector.addGoal(1, new Bee.BeeEnterHiveGoal()); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0)); @@ -200,6 +249,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { this.goalSelector.addGoal(7, new Bee.BeeGrowCropGoal()); this.goalSelector.addGoal(8, new Bee.BeeWanderGoal()); this.goalSelector.addGoal(9, new FloatGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new Bee.BeeHurtByOtherGoal(this).setAlertOthers(new Class[0])); this.targetSelector.addGoal(2, new Bee.BeeBecomeAngryTargetGoal(this)); this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true)); @@ -1084,15 +1134,15 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { } } - class BeeLookControl extends LookControl { + class BeeLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables BeeLookControl(final Mob mob) { super(mob); } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (!Bee.this.isAngry()) { - super.tick(); + super.vanillaTick(); // Purpur - Ridables } } diff --git a/net/minecraft/world/entity/animal/Cat.java b/net/minecraft/world/entity/animal/Cat.java index 618f184ce9fed4d9b01f2df4d9a4476d20a55546..f066b0acfa0e954f6d71e62962c76afa1f05a4a5 100644 --- a/net/minecraft/world/entity/animal/Cat.java +++ b/net/minecraft/world/entity/animal/Cat.java @@ -93,10 +93,36 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CAT_FOOD), true); this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new TamableAnimal.TamableAnimalPanicGoal(1.5)); this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); this.goalSelector.addGoal(3, new Cat.CatRelaxOnOwnerGoal(this)); @@ -109,6 +135,7 @@ public class Cat extends TamableAnimal implements VariantHolder(this, Rabbit.class, false, null)); this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR)); } @@ -360,6 +387,7 @@ public class Cat extends TamableAnimal implements VariantHolder itemStack.is(ItemTags.CHICKEN_FOOD), false)); diff --git a/net/minecraft/world/entity/animal/Cod.java b/net/minecraft/world/entity/animal/Cod.java index 708bcc39e7242292d5d5bfcaf599e3738628df9b..6a19086e272363701260801f3c6db9b5c91b8ef5 100644 --- a/net/minecraft/world/entity/animal/Cod.java +++ b/net/minecraft/world/entity/animal/Cod.java @@ -13,6 +13,18 @@ public class Cod extends AbstractSchoolingFish { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.codRidable; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.codControllable; + } + // Purpur end - Ridables + @Override public ItemStack getBucketItemStack() { return new ItemStack(Items.COD_BUCKET); diff --git a/net/minecraft/world/entity/animal/Cow.java b/net/minecraft/world/entity/animal/Cow.java index 8c1f74c6be53cbf48bd6b5641511359578801c08..656babc0c8810a85eb9f78ced1f3ad9551fdc286 100644 --- a/net/minecraft/world/entity/animal/Cow.java +++ b/net/minecraft/world/entity/animal/Cow.java @@ -38,9 +38,27 @@ public class Cow extends Animal { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.cowRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.cowRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.cowControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new PanicGoal(this, 2.0)); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0)); this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, itemStack -> level().purpurConfig.cowFeedMushrooms > 0 && (itemStack.is(net.minecraft.world.level.block.Blocks.RED_MUSHROOM.asItem()) || itemStack.is(net.minecraft.world.level.block.Blocks.BROWN_MUSHROOM.asItem())) || itemStack.is(ItemTags.COW_FOOD), false)); // Purpur - Cows eat mushrooms @@ -86,13 +104,14 @@ public class Cow extends Animal { @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { + if (getRider() != null) return InteractionResult.PASS; // Purpur - Ridables ItemStack itemInHand = player.getItemInHand(hand); if (itemInHand.is(Items.BUCKET) && !this.isBaby()) { // CraftBukkit start - Got milk? org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemInHand, Items.MILK_BUCKET, hand); if (event.isCancelled()) { player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur - Ridables } // CraftBukkit end player.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F); diff --git a/net/minecraft/world/entity/animal/Dolphin.java b/net/minecraft/world/entity/animal/Dolphin.java index 8be0dd148d88dfdfb9efab91124c829e60b5dea5..35bce598bb5857356823594d2a001006ce19f835 100644 --- a/net/minecraft/world/entity/animal/Dolphin.java +++ b/net/minecraft/world/entity/animal/Dolphin.java @@ -72,14 +72,82 @@ public class Dolphin extends AgeableWaterCreature { public static final Predicate ALLOWED_ITEMS = itemEntity -> !itemEntity.hasPickUpDelay() && itemEntity.isAlive() && itemEntity.isInWater(); public static final float BABY_SCALE = 0.65F; private boolean isNaturallyAggressiveToPlayers; // Purpur - Dolphins naturally aggressive to players chance + private int spitCooldown; // Purpur - Ridables public Dolphin(EntityType entityType, Level level) { super(entityType, level); - this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); + // Purpur start - Ridables + class DolphinMoveControl extends SmoothSwimmingMoveControl { + private final org.purpurmc.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 org.purpurmc.purpur.controller.WaterMoveControllerWASD(dolphin); + } + + @Override + public void tick() { + if (dolphin.getRider() != null && dolphin.isControllable()) { + purpurTick(dolphin.getRider()); + } else { + super.tick(); + } + } + + public void purpurTick(Player rider) { + if (dolphin.getAirSupply() < 150) { + // if drowning override player WASD controls to find air + super.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 - Ridables this.lookControl = new SmoothSwimmingLookControl(this, 10); this.setCanPickUpLoot(true); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.dolphinRidable; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.dolphinControllable; + } + + @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()); + + org.purpurmc.purpur.entity.projectile.DolphinSpit spit = new org.purpurmc.purpur.entity.projectile.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 - Ridables + @Nullable @Override public SpawnGroupData finalizeSpawn( @@ -172,6 +240,7 @@ public class Dolphin extends AgeableWaterCreature { this.goalSelector.addGoal(0, new BreathAirGoal(this)); this.goalSelector.addGoal(0, new TryFindWaterGoal(this)); this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2000000476837158D, true)); // Purpur - Dolphins naturally aggressive to players chance + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this)); this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0)); this.goalSelector.addGoal(4, new RandomSwimmingGoal(this, 1.0, 10)); @@ -182,6 +251,7 @@ public class Dolphin extends AgeableWaterCreature { 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.0, 1.0)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Guardian.class).setAlertOthers()); this.targetSelector.addGoal(2, new net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (ignored, ignored2) -> isNaturallyAggressiveToPlayers)); // Purpur - Dolphins naturally aggressive to players chance } @@ -227,7 +297,7 @@ public class Dolphin extends AgeableWaterCreature { @Override protected boolean canRide(Entity entity) { - return true; + return boardingCooldown <= 0; // Purpur - make dolphin honor ride cooldown like all other non-boss mobs; } @Override @@ -256,6 +326,11 @@ public class Dolphin extends AgeableWaterCreature { @Override public void tick() { super.tick(); + // Purpur start - Ridables + if (spitCooldown > 0) { + spitCooldown--; + } + // Purpur end - Ridables if (this.isNoAi()) { this.setAirSupply(this.getMaxAirSupply()); } else { diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java index ddc252c76cedec0a0e9e268d8a874015a5ad52fe..8b0a813f9dd001c6dd108ba7aac04d134a20fbc1 100644 --- a/net/minecraft/world/entity/animal/Fox.java +++ b/net/minecraft/world/entity/animal/Fox.java @@ -129,6 +129,44 @@ public class Fox extends Animal implements VariantHolder { this.getNavigation().setRequiredPathLength(32.0F); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.foxRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.foxRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.foxControllable; + } + + @Override + public float getJumpPower() { + return getRider() != null && this.isControllable() ? 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 - Ridables + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); @@ -148,6 +186,7 @@ public class Fox extends Animal implements VariantHolder { this, AbstractFish.class, 20, false, false, (entity, level) -> entity instanceof AbstractSchoolingFish ); this.goalSelector.addGoal(0, new Fox.FoxFloatGoal()); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(0, new ClimbOnTopOfPowderSnowGoal(this, this.level())); this.goalSelector.addGoal(1, new Fox.FaceplantGoal()); this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2)); @@ -175,6 +214,7 @@ public class Fox extends Animal implements VariantHolder { 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 org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector .addGoal( 3, @@ -1095,15 +1135,15 @@ public class Fox extends Animal implements VariantHolder { } } - public class FoxLookControl extends LookControl { + public class FoxLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables public FoxLookControl() { super(Fox.this); } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (!Fox.this.isSleeping()) { - super.tick(); + super.vanillaTick(); // Purpur - Ridables } } @@ -1139,15 +1179,15 @@ public class Fox extends Animal implements VariantHolder { } } - class FoxMoveControl extends MoveControl { + class FoxMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables public FoxMoveControl() { super(Fox.this); } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (Fox.this.canMove()) { - super.tick(); + super.vanillaTick(); // Purpur - Ridables } } } diff --git a/net/minecraft/world/entity/animal/IronGolem.java b/net/minecraft/world/entity/animal/IronGolem.java index 46921562c9c5caf7e04ee180325a638273d6bad2..223c4796f659a24062a719045e484a22d31ab2f0 100644 --- a/net/minecraft/world/entity/animal/IronGolem.java +++ b/net/minecraft/world/entity/animal/IronGolem.java @@ -73,9 +73,28 @@ public class IronGolem extends AbstractGolem implements NeutralMob { } // Purpur end - Summoner API + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.ironGolemRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ironGolemRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.ironGolemControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { if (this.level().purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.ReceiveFlower(this)); // Purpur - Iron golem calm anger options + if (level().purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur - Ridables + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0, true)); this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9, 32.0F)); this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6, false)); @@ -83,6 +102,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 org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new DefendVillageTargetGoal(this)); this.targetSelector.addGoal(2, new HurtByTargetGoal(this)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); @@ -271,12 +291,12 @@ public class IronGolem extends AbstractGolem implements NeutralMob { protected InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemInHand = player.getItemInHand(hand); if (!itemInHand.is(Items.IRON_INGOT)) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur - Ridables } else { float health = this.getHealth(); this.heal(25.0F); if (this.getHealth() == health) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur - Ridables } else { float f = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F; this.playSound(SoundEvents.IRON_GOLEM_REPAIR, 1.0F, f); diff --git a/net/minecraft/world/entity/animal/MushroomCow.java b/net/minecraft/world/entity/animal/MushroomCow.java index a8aeb79b1c1413d74a5d18a57bd4ba4beca6039c..1292146341022483f78a9128ef9d7a88089274a0 100644 --- a/net/minecraft/world/entity/animal/MushroomCow.java +++ b/net/minecraft/world/entity/animal/MushroomCow.java @@ -55,6 +55,23 @@ public class MushroomCow extends Cow implements Shearable, VariantHolder drops = this.generateDefaultDrops(serverLevel, itemInHand); org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); if (event != null) { - if (event.isCancelled()) return InteractionResult.PASS; + if (event.isCancelled()) return tryRide(player, hand); // Purpur - Ridables drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); // Paper end - custom shear drops } diff --git a/net/minecraft/world/entity/animal/Ocelot.java b/net/minecraft/world/entity/animal/Ocelot.java index e193696b2e3eb1c1c689c05592ab4318a98772ad..d26a8658c8c56c3b0df4e5908de1ac23ac2dd351 100644 --- a/net/minecraft/world/entity/animal/Ocelot.java +++ b/net/minecraft/world/entity/animal/Ocelot.java @@ -62,6 +62,23 @@ public class Ocelot extends Animal { this.reassessTrustingGoals(); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.ocelotRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ocelotRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.ocelotControllable; + } + // Purpur end - Ridables + public boolean isTrusting() { return this.entityData.get(DATA_TRUSTING); } @@ -93,12 +110,14 @@ public class Ocelot extends Animal { protected void registerGoals() { this.temptGoal = new Ocelot.OcelotTemptGoal(this, 0.6, itemStack -> itemStack.is(ItemTags.OCELOT_FOOD), true); this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables 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.8)); this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 0.8, 1.0000001E-5F)); this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0F)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables 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/net/minecraft/world/entity/animal/Panda.java b/net/minecraft/world/entity/animal/Panda.java index 283ddf7d13a17c0a6df5a52b7fd26ed7b7a4826b..19aa39af6685a03eb584820853239a3f4fa1a515 100644 --- a/net/minecraft/world/entity/animal/Panda.java +++ b/net/minecraft/world/entity/animal/Panda.java @@ -105,6 +105,32 @@ public class Panda extends Animal { } } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.pandaRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pandaRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.pandaControllable; + } + + @Override + public void onMount(Player rider) { + super.onMount(rider); + setForwardMot(0.0F); + sit(false); + eat(false); + setOnBack(false); + } + // Purpur end - Ridables + @Override protected boolean canDispenserEquipIntoSlot(EquipmentSlot slot) { return slot == EquipmentSlot.MAINHAND && this.canPickUpLoot(); @@ -258,6 +284,7 @@ public class Panda extends Animal { @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(2, new Panda.PandaPanicGoal(this, 2.0)); this.goalSelector.addGoal(2, new Panda.PandaBreedGoal(this, 1.0)); this.goalSelector.addGoal(3, new Panda.PandaAttackGoal(this, 1.2F, true)); @@ -273,6 +300,7 @@ public class Panda extends Animal { this.goalSelector.addGoal(12, new Panda.PandaRollGoal(this)); this.goalSelector.addGoal(13, new FollowParentGoal(this, 1.25)); this.goalSelector.addGoal(14, new WaterAvoidingRandomStrollGoal(this, 1.0)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new Panda.PandaHurtByTargetGoal(this).setAlertOthers(new Class[0])); } @@ -616,7 +644,7 @@ public class Panda extends Animal { public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemInHand = player.getItemInHand(hand); if (this.isScared()) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur - Ridables } else if (this.isOnBack()) { this.setOnBack(false); return InteractionResult.SUCCESS; @@ -652,7 +680,7 @@ public class Panda extends Animal { return InteractionResult.SUCCESS_SERVER; } else { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur - Ridables } } @@ -964,7 +992,7 @@ public class Panda extends Animal { } } - static class PandaMoveControl extends MoveControl { + static class PandaMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables private final Panda panda; public PandaMoveControl(Panda mob) { @@ -973,9 +1001,9 @@ public class Panda extends Animal { } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (this.panda.canPerformAction()) { - super.tick(); + super.vanillaTick(); // Purpur - Ridables } } } diff --git a/net/minecraft/world/entity/animal/Parrot.java b/net/minecraft/world/entity/animal/Parrot.java index 1d840fe1c718ea4431c471e3cbbdee074ed53179..445614d09d2364daee5245c217baeb31e186c168 100644 --- a/net/minecraft/world/entity/animal/Parrot.java +++ b/net/minecraft/world/entity/animal/Parrot.java @@ -124,12 +124,68 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder entityType, Level level) { super(entityType, level); - this.moveControl = new FlyingMoveControl(this, 10, false); + // Purpur start - Ridables + final org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD flyingController = new org.purpurmc.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 && mob.isControllable()) { + flyingController.purpurTick(mob.getRider()); + } else { + super.tick(); + } + } + + @Override + public boolean hasWanted() { + return mob.getRider() != null && mob.isControllable() ? getForwardMot() != 0 || getStrafeMot() != 0 : super.hasWanted(); + } + } + this.moveControl = new ParrotMoveControl(this, 10, false); + // Purpur end - Ridables this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F); this.setPathfindingMalus(PathType.DAMAGE_FIRE, -1.0F); this.setPathfindingMalus(PathType.COCOA, -1.0F); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.parrotRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.parrotRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.parrotControllable; + } + + @Override + public double getMaxY() { + return level().purpurConfig.parrotMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && this.isControllable() && !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 - Ridables + @Nullable @Override public SpawnGroupData finalizeSpawn( @@ -150,9 +206,11 @@ public class Parrot extends ShoulderRidingEntity implements VariantHolder itemStack.is(Items.CARROT_ON_A_STICK), false)); diff --git a/net/minecraft/world/entity/animal/PolarBear.java b/net/minecraft/world/entity/animal/PolarBear.java index fbd35f074a3045d483aabd9bc7e1c9c4f10a3167..711ed0d753494a92a003fc683146f289505ed7f6 100644 --- a/net/minecraft/world/entity/animal/PolarBear.java +++ b/net/minecraft/world/entity/animal/PolarBear.java @@ -59,6 +59,7 @@ public class PolarBear extends Animal implements NeutralMob { private int remainingPersistentAngerTime; @Nullable private UUID persistentAngerTarget; + private int standTimer = 0; // Purpur - Ridables public PolarBear(EntityType entityType, Level level) { super(entityType, level); @@ -87,6 +88,34 @@ public class PolarBear extends Animal implements NeutralMob { } // Purpur end - Breedable Polar Bears + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.polarBearRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.polarBearRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.polarBearControllable; + } + + @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 - Ridables + @Nullable @Override public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) { @@ -102,6 +131,7 @@ public class PolarBear extends Animal implements NeutralMob { protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal()); this.goalSelector.addGoal(1, new PanicGoal(this, 2.0, mob -> mob.isBaby() ? DamageTypeTags.PANIC_CAUSES : DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES)); // Purpur start - Breedable Polar Bears @@ -114,6 +144,7 @@ public class PolarBear extends Animal implements NeutralMob { this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables 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)); @@ -232,6 +263,12 @@ public class PolarBear extends Animal implements NeutralMob { if (!this.level().isClientSide) { this.updatePersistentAnger((ServerLevel)this.level(), true); } + + // Purpur start - Ridables + if (isStanding() && --standTimer <= 0) { + setStanding(false); + } + // Purpur end - Ridables } @Override @@ -251,6 +288,7 @@ public class PolarBear extends Animal implements NeutralMob { public void setStanding(boolean standing) { this.entityData.set(DATA_STANDING_ID, standing); + standTimer = standing ? 20 : -1; // Purpur - Ridables } public float getStandingAnimationScale(float partialTick) { diff --git a/net/minecraft/world/entity/animal/Pufferfish.java b/net/minecraft/world/entity/animal/Pufferfish.java index d94a7cfcd0f7a15ce97d3b12daa8b2c71acf997a..f7e9abf778186ad1c78dbe411980a83c5e68792e 100644 --- a/net/minecraft/world/entity/animal/Pufferfish.java +++ b/net/minecraft/world/entity/animal/Pufferfish.java @@ -45,6 +45,18 @@ public class Pufferfish extends AbstractFish { this.refreshDimensions(); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.pufferfishRidable; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.pufferfishControllable; + } + // Purpur end - Ridables + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); diff --git a/net/minecraft/world/entity/animal/Rabbit.java b/net/minecraft/world/entity/animal/Rabbit.java index b2cbe9f7a771dbfc381effa0821d44421c98b33e..8cac46951938c80fae3499e8b53709c25d86e9bd 100644 --- a/net/minecraft/world/entity/animal/Rabbit.java +++ b/net/minecraft/world/entity/animal/Rabbit.java @@ -83,6 +83,7 @@ public class Rabbit extends Animal implements VariantHolder { private boolean wasOnGround; private int jumpDelayTicks; public int moreCarrotTicks; + private boolean actualJump; // Purpur - Ridables public Rabbit(EntityType entityType, Level level) { super(entityType, level); @@ -91,9 +92,55 @@ public class Rabbit extends Animal implements VariantHolder { //this.setSpeedModifier(0.0); // CraftBukkit } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.rabbitRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.rabbitRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.rabbitControllable; + } + + @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 - Ridables + @Override public void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level())); this.goalSelector.addGoal(1, new Rabbit.RabbitPanicGoal(this, 2.2)); this.goalSelector.addGoal(2, new BreedGoal(this, 0.8)); @@ -108,6 +155,14 @@ public class Rabbit extends Animal implements VariantHolder { @Override protected float getJumpPower() { + // Purpur start - Ridables + if (getRider() != null && this.isControllable()) { + if (getForwardMot() < 0) { + setSpeed(getForwardMot() * 2F); + } + return actualJump ? 0.5F : 0.3F; + } + // Purpur end - Ridables float f = 0.3F; if (this.moveControl.getSpeedModifier() <= 0.6) { f = 0.2F; @@ -175,6 +230,12 @@ public class Rabbit extends Animal implements VariantHolder { @Override public void customServerAiStep(ServerLevel level) { + // Purpur start - Ridables + if (getRider() != null && this.isControllable()) { + handleJumping(); + return; + } + // Purpur end - Ridables if (this.jumpDelayTicks > 0) { this.jumpDelayTicks--; } @@ -483,7 +544,7 @@ public class Rabbit extends Animal implements VariantHolder { } } - static class RabbitMoveControl extends MoveControl { + static class RabbitMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables private final Rabbit rabbit; private double nextJumpSpeed; @@ -493,14 +554,14 @@ public class Rabbit extends Animal implements VariantHolder { } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (this.rabbit.onGround() && !this.rabbit.jumping && !((Rabbit.RabbitJumpControl)this.rabbit.jumpControl).wantJump()) { this.rabbit.setSpeedModifier(0.0); } else if (this.hasWanted() || this.operation == MoveControl.Operation.JUMPING) { this.rabbit.setSpeedModifier(this.nextJumpSpeed); } - super.tick(); + super.vanillaTick(); // Purpur - Ridables } @Override diff --git a/net/minecraft/world/entity/animal/Salmon.java b/net/minecraft/world/entity/animal/Salmon.java index 41366f7b9af176a33b20ea26dd53d50994d2c600..ebbd6d39c3f5d6c66445c2c743785ed369408389 100644 --- a/net/minecraft/world/entity/animal/Salmon.java +++ b/net/minecraft/world/entity/animal/Salmon.java @@ -35,6 +35,18 @@ public class Salmon extends AbstractSchoolingFish implements VariantHolder stack.is(ItemTags.SHEEP_FOOD), false)); diff --git a/net/minecraft/world/entity/animal/SnowGolem.java b/net/minecraft/world/entity/animal/SnowGolem.java index 29427515b648b84248f486c156c5cd7a0995ba14..52de92b118b613217b8f92ff672c01ddf798a1fc 100644 --- a/net/minecraft/world/entity/animal/SnowGolem.java +++ b/net/minecraft/world/entity/animal/SnowGolem.java @@ -61,12 +61,31 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM } // Purpur end - Summoner API + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.snowGolemRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.snowGolemRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.snowGolemControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new RangedAttackGoal(this, level().purpurConfig.snowGolemAttackDistance, level().purpurConfig.snowGolemSnowBallMin, level().purpurConfig.snowGolemSnowBallMax, level().purpurConfig.snowGolemSnowBallModifier)); // Purpur - Snow Golem rate of fire config 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 org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entity, level) -> entity instanceof Enemy)); } @@ -113,6 +132,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM return; } + if (getRider() != null && this.isControllable() && !level().purpurConfig.snowGolemLeaveTrailWhenRidden) return; // Purpur - don't leave snow trail when being ridden BlockState blockState = Blocks.SNOW.defaultBlockState(); for (int i = 0; i < 4; i++) { @@ -155,7 +175,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); if (event != null) { if (event.isCancelled()) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur - Ridables } drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops()); // Paper end - custom shear drops @@ -176,7 +196,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM return InteractionResult.SUCCESS; // Purpur end - Snowman drop and put back pumpkin } else { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur - Ridables } } diff --git a/net/minecraft/world/entity/animal/Squid.java b/net/minecraft/world/entity/animal/Squid.java index c776d40896a6514ab9c66df206c93469ec682b23..e3f43e8c6ddbae289a82157cab4beb18f682dd75 100644 --- a/net/minecraft/world/entity/animal/Squid.java +++ b/net/minecraft/world/entity/animal/Squid.java @@ -69,9 +69,32 @@ public class Squid extends AgeableWaterCreature { } // Purpur end - Flying squids! Oh my! + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.squidRidable; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.squidControllable; + } + + protected static 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 - Ridables + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new Squid.SquidFleeGoal()); } @@ -327,6 +350,37 @@ public class Squid extends AgeableWaterCreature { @Override public void tick() { + // Purpur start - Ridables + net.minecraft.world.entity.player.Player rider = squid.getRider(); + if (rider != null && squid.isControllable()) { + 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.movementVector = new Vec3((float) dir.getX(), (float) dir.getY(), (float) dir.getZ()); + } else { + squid.movementVector = Vec3.ZERO; + } + return; + } + // Purpur end - Ridables int noActionTime = this.squid.getNoActionTime(); if (noActionTime > 100) { this.squid.movementVector = Vec3.ZERO; diff --git a/net/minecraft/world/entity/animal/TropicalFish.java b/net/minecraft/world/entity/animal/TropicalFish.java index fa5f7f7d54083f9ea2095dd44362069d00e0b9a5..1e31a39b276e1c5ae767da7af0b536007c87189e 100644 --- a/net/minecraft/world/entity/animal/TropicalFish.java +++ b/net/minecraft/world/entity/animal/TropicalFish.java @@ -67,6 +67,18 @@ public class TropicalFish extends AbstractSchoolingFish implements VariantHolder super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.tropicalFishRidable; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.tropicalFishControllable; + } + // Purpur end - Ridables + public static String getPredefinedName(int variantId) { return "entity.minecraft.tropical_fish.predefined." + variantId; } diff --git a/net/minecraft/world/entity/animal/Turtle.java b/net/minecraft/world/entity/animal/Turtle.java index 354ec2b987882d8f40ef4ac5257183d2fda73bb8..98cb91574c8d2bdb6d180256f657ecc67987a6fe 100644 --- a/net/minecraft/world/entity/animal/Turtle.java +++ b/net/minecraft/world/entity/animal/Turtle.java @@ -84,6 +84,23 @@ public class Turtle extends Animal { this.moveControl = new Turtle.TurtleMoveControl(this); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.turtleRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.turtleRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.turtleControllable; + } + // Purpur end - Ridables + public void setHomePos(BlockPos homePos) { this.entityData.set(HOME_POS, homePos); } @@ -188,6 +205,7 @@ public class Turtle extends Animal { @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(0, new Turtle.TurtlePanicGoal(this, 1.2)); this.goalSelector.addGoal(1, new Turtle.TurtleBreedGoal(this, 1.0)); this.goalSelector.addGoal(1, new Turtle.TurtleLayEggGoal(this, 1.0)); @@ -539,12 +557,14 @@ public class Turtle extends Animal { } } - static class TurtleMoveControl extends MoveControl { + static class TurtleMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables private final Turtle turtle; + private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterController; // Purpur - Ridables TurtleMoveControl(Turtle mob) { super(mob); this.turtle = mob; + waterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(turtle, 0.25D); // Purpur - Ridables } private void updateSpeed() { @@ -563,7 +583,7 @@ public class Turtle extends Animal { } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables this.updateSpeed(); if (this.operation == MoveControl.Operation.MOVE_TO && !this.turtle.getNavigation().isDone()) { double d = this.wantedX - this.turtle.getX(); @@ -577,7 +597,7 @@ public class Turtle extends Animal { float f = (float)(Mth.atan2(d2, d) * 180.0F / (float)Math.PI) - 90.0F; this.turtle.setYRot(this.rotlerp(this.turtle.getYRot(), f, 90.0F)); this.turtle.yBodyRot = this.turtle.getYRot(); - float f1 = (float)(this.speedModifier * this.turtle.getAttributeValue(Attributes.MOVEMENT_SPEED)); + float f1 = (float)(this.getSpeedModifier() * this.turtle.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables this.turtle.setSpeed(Mth.lerp(0.125F, this.turtle.getSpeed(), f1)); this.turtle.setDeltaMovement(this.turtle.getDeltaMovement().add(0.0, this.turtle.getSpeed() * d1 * 0.1, 0.0)); } diff --git a/net/minecraft/world/entity/animal/Wolf.java b/net/minecraft/world/entity/animal/Wolf.java index 6cc3893742b443ec84942252910cf444cdbf0c96..90609ff3060322110ece27630de0abae1a6370a8 100644 --- a/net/minecraft/world/entity/animal/Wolf.java +++ b/net/minecraft/world/entity/animal/Wolf.java @@ -180,9 +180,32 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder(this, Llama.class, 24.0F, 1.5, 1.5)); @@ -195,6 +218,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder entityType, Level level) { super(entityType, level); - this.moveControl = new FlyingMoveControl(this, 20, true); + // Purpur start - Ridables + this.purpurController = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this, 0.1F, 0.5F); + this.moveControl = new FlyingMoveControl(this, 20, true) { + @Override + public void tick() { + if (mob.getRider() != null && mob.isControllable()) { + purpurController.purpurTick(mob.getRider()); + } else { + super.tick(); + } + } + }; + // Purpur end - Ridables this.setCanPickUpLoot(this.canPickUpLoot()); this.vibrationUser = new Allay.VibrationUser(); this.vibrationData = new VibrationSystem.Data(); @@ -138,6 +151,28 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS } // CraftBukkit end + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.allayRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.allayRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.allayControllable; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + } + // Purpur end - Ridables + @Override protected Brain.Provider brainProvider() { return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); @@ -247,6 +282,7 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS protected void customServerAiStep(ServerLevel level) { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("allayBrain"); + //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider this.getBrain().tick(level, this); profilerFiller.pop(); profilerFiller.push("allayActivityUpdate"); diff --git a/net/minecraft/world/entity/animal/armadillo/Armadillo.java b/net/minecraft/world/entity/animal/armadillo/Armadillo.java index dfdbcb31458095a71c187efc2774ecc4945dd11b..87a190d8646d8bbed8c182f9f0f7d8c398e63d26 100644 --- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java +++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java @@ -80,6 +80,23 @@ public class Armadillo extends Animal { return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 12.0).add(Attributes.MOVEMENT_SPEED, 0.14); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.armadilloRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.armadilloRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.armadilloControllable; + } + // Purpur end - Ridables + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); diff --git a/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/net/minecraft/world/entity/animal/axolotl/Axolotl.java index 9faa929734035c167e54569ce34d841291856589..2054e4624da0c9b04ea69b9bf39443c4574d48be 100644 --- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java +++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java @@ -115,6 +115,23 @@ public class Axolotl extends Animal implements VariantHolder, B this.lookControl = new Axolotl.AxolotlLookControl(this, 20); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.axolotlRidable; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.axolotlControllable; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + } + // Purpur end - Ridables + @Override public float getWalkTargetValue(BlockPos pos, LevelReader level) { return 0.0F; @@ -304,6 +321,7 @@ public class Axolotl extends Animal implements VariantHolder, B protected void customServerAiStep(ServerLevel level) { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("axolotlBrain"); + //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider this.getBrain().tick(level, this); profilerFiller.pop(); profilerFiller.push("axolotlActivityUpdate"); @@ -555,23 +573,31 @@ public class Axolotl extends Animal implements VariantHolder, B } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (!Axolotl.this.isPlayingDead()) { - super.tick(); + super.vanillaTick(); // Purpur - Ridables } } } static class AxolotlMoveControl extends SmoothSwimmingMoveControl { private final Axolotl axolotl; + private final org.purpurmc.purpur.controller.WaterMoveControllerWASD waterController; // Purpur - Ridables public AxolotlMoveControl(Axolotl axolotl) { super(axolotl, 85, 10, 0.1F, 0.5F, false); this.axolotl = axolotl; + waterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(axolotl, 0.5D); // Purpur - Ridables } @Override public void tick() { + // Purpur start - Ridables + if (axolotl.getRider() != null && axolotl.isControllable()) { + waterController.purpurTick(axolotl.getRider()); + return; + } + // Purpur end - Ridables if (!this.axolotl.isPlayingDead()) { super.tick(); } diff --git a/net/minecraft/world/entity/animal/camel/Camel.java b/net/minecraft/world/entity/animal/camel/Camel.java index 3ac169f83c5619b5c00c866354a2e066a0a738cc..11311d2ec37d825e73e2218e60e2606dd3a25a1d 100644 --- a/net/minecraft/world/entity/animal/camel/Camel.java +++ b/net/minecraft/world/entity/animal/camel/Camel.java @@ -83,6 +83,13 @@ public class Camel extends AbstractHorse { groundPathNavigation.setCanWalkOverFences(true); } + // Purpur start - Ridables + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.camelRidableInWater; + } + // Purpur end - Ridables + @Override public void addAdditionalSaveData(CompoundTag compound) { super.addAdditionalSaveData(compound); diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java index 12c655b60087a2f6122ffa508b3224159d8777b0..9a400c8bf2b54aa5fbcbe65b61670cac5fbebf05 100644 --- a/net/minecraft/world/entity/animal/frog/Frog.java +++ b/net/minecraft/world/entity/animal/frog/Frog.java @@ -106,6 +106,8 @@ public class Frog extends Animal implements VariantHolder> { public final AnimationState croakAnimationState = new AnimationState(); public final AnimationState tongueAnimationState = new AnimationState(); public final AnimationState swimIdleAnimationState = new AnimationState(); + private org.purpurmc.purpur.controller.MoveControllerWASD purpurLandController; // Purpur - Ridables + private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurWaterController; // Purpur - Ridables public Frog(EntityType entityType, Level level) { super(entityType, level); @@ -113,7 +115,55 @@ public class Frog extends Animal implements VariantHolder> { this.setPathfindingMalus(PathType.WATER, 4.0F); this.setPathfindingMalus(PathType.TRAPDOOR, -1.0F); this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); + // Purpur start - Ridables + this.purpurLandController = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.2F); + this.purpurWaterController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F); + this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) { + @Override + public void tick() { + net.minecraft.world.entity.player.Player rider = mob.getRider(); + if (rider != null && mob.isControllable()) { + if (mob.isInWater()) { + purpurWaterController.purpurTick(rider); + mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, -0.005D, 0.0D)); + } else { + purpurLandController.purpurTick(rider); + } + } else { + super.tick(); + } + } + }; + // Purpur end - Ridables + } + + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.frogRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.frogRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.frogControllable; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + } + + @Override + public float getJumpPower() { + return (getRider() != null && isControllable()) ? level().purpurConfig.frogRidableJumpHeight * this.getBlockJumpFactor() : super.getJumpPower(); } + // Purpur end - Ridables @Override protected Brain.Provider brainProvider() { @@ -188,6 +238,7 @@ public class Frog extends Animal implements VariantHolder> { protected void customServerAiStep(ServerLevel level) { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("frogBrain"); + //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider this.getBrain().tick(level, this); profilerFiller.pop(); profilerFiller.push("frogActivityUpdate"); @@ -380,7 +431,7 @@ public class Frog extends Animal implements VariantHolder> { return level.getBlockState(pos.below()).is(BlockTags.FROGS_SPAWNABLE_ON) && isBrightEnoughToSpawn(level, pos); } - class FrogLookControl extends LookControl { + class FrogLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables FrogLookControl(final Mob mob) { super(mob); } diff --git a/net/minecraft/world/entity/animal/frog/Tadpole.java b/net/minecraft/world/entity/animal/frog/Tadpole.java index 97adf8142cdd322c4873c420ed760e9dee34da23..e888e606b4b14fa6485de7426bc146b6005962af 100644 --- a/net/minecraft/world/entity/animal/frog/Tadpole.java +++ b/net/minecraft/world/entity/animal/frog/Tadpole.java @@ -63,13 +63,50 @@ public class Tadpole extends AbstractFish { MemoryModuleType.IS_PANICKING ); public boolean ageLocked; // Paper + private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurController; // Purpur - Ridables public Tadpole(EntityType entityType, Level level) { super(entityType, level); - this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); + // Purpur start - Ridables + this.purpurController = new org.purpurmc.purpur.controller.WaterMoveControllerWASD(this, 0.5F); + this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true) { + @Override + public void tick() { + Player rider = mob.getRider(); + if (rider != null && mob.isControllable()) { + purpurController.purpurTick(rider); + mob.setDeltaMovement(mob.getDeltaMovement().add(0.0D, 0.002D, 0.0D)); + } else { + super.tick(); + } + } + }; + // Purpur end - Ridables this.lookControl = new SmoothSwimmingLookControl(this, 10); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.tadpoleRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.tadpoleRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.tadpoleControllable; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + } + // Purpur end - Ridables + @Override protected PathNavigation createNavigation(Level level) { return new WaterBoundPathNavigation(this, level); @@ -99,6 +136,7 @@ public class Tadpole extends AbstractFish { protected void customServerAiStep(ServerLevel level) { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("tadpoleBrain"); + //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider this.getBrain().tick(level, this); profilerFiller.pop(); profilerFiller.push("tadpoleActivityUpdate"); diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java index 30fd6bfad846c7a268ab87254974bad2ee0e0422..c4c78885373347ee052be9575b9f3b8dd9f2b781 100644 --- a/net/minecraft/world/entity/animal/goat/Goat.java +++ b/net/minecraft/world/entity/animal/goat/Goat.java @@ -111,6 +111,23 @@ public class Goat extends Animal { .orElseGet(() -> new ItemStack(Items.GOAT_HORN)); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.goatRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.goatRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.goatControllable; + } + // Purpur end - Ridables + @Override protected Brain.Provider brainProvider() { return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); @@ -188,6 +205,7 @@ public class Goat extends Animal { protected void customServerAiStep(ServerLevel level) { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("goatBrain"); + //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider this.getBrain().tick(level, this); profilerFiller.pop(); profilerFiller.push("goatActivityUpdate"); diff --git a/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/net/minecraft/world/entity/animal/horse/AbstractHorse.java index d52a8315f1e6876c26c732f4c4caa47bc6bebf6e..828406060e50ff62586929371aafb46ef7d81f92 100644 --- a/net/minecraft/world/entity/animal/horse/AbstractHorse.java +++ b/net/minecraft/world/entity/animal/horse/AbstractHorse.java @@ -206,11 +206,21 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, protected AbstractHorse(EntityType entityType, Level level) { super(entityType, level); + 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.createInventory(); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return false; // vanilla handles + } + // Purpur end - Ridables + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new PanicGoal(this, 1.2)); this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2)); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0, AbstractHorse.class)); @@ -221,6 +231,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, if (this.canPerformRearing()) { this.goalSelector.addGoal(9, new RandomStandGoal(this)); } + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HorseHasRider(this)); // Purpur - Ridables this.addBehaviourGoals(); } diff --git a/net/minecraft/world/entity/animal/horse/Donkey.java b/net/minecraft/world/entity/animal/horse/Donkey.java index 9b97f3d3675f5051b18a68ff7fa056d859a283e9..ee3fa710e95f2e84f7f9bdce1159d1136815172d 100644 --- a/net/minecraft/world/entity/animal/horse/Donkey.java +++ b/net/minecraft/world/entity/animal/horse/Donkey.java @@ -16,6 +16,13 @@ public class Donkey extends AbstractChestedHorse { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.donkeyRidableInWater; + } + // Purpur end - Ridables + @Override protected SoundEvent getAmbientSound() { return SoundEvents.DONKEY_AMBIENT; diff --git a/net/minecraft/world/entity/animal/horse/Horse.java b/net/minecraft/world/entity/animal/horse/Horse.java index c6d0700f29d6c8123e96efe225faf2d99202ac81..361bf346153912bcbfcf962d7f716dfe12ae2a7b 100644 --- a/net/minecraft/world/entity/animal/horse/Horse.java +++ b/net/minecraft/world/entity/animal/horse/Horse.java @@ -43,6 +43,13 @@ public class Horse extends AbstractHorse implements VariantHolder { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.horseRidableInWater; + } + // Purpur end - Ridables + @Override protected void randomizeAttributes(RandomSource random) { this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(generateMaxHealth(random::nextInt)); diff --git a/net/minecraft/world/entity/animal/horse/Llama.java b/net/minecraft/world/entity/animal/horse/Llama.java index 7d4aad3c45d710488aba540ee5a535098ddd27ee..164a429d432badcb315e8ece406e29e576a11265 100644 --- a/net/minecraft/world/entity/animal/horse/Llama.java +++ b/net/minecraft/world/entity/animal/horse/Llama.java @@ -78,7 +78,51 @@ public class Llama extends AbstractChestedHorse implements VariantHolder entityType, Level level) { super(EntityType.ENDER_DRAGON, level); @@ -106,6 +107,37 @@ public class EnderDragon extends Mob implements Enemy { this.noPhysics = true; this.phaseManager = new EnderDragonPhaseManager(this); this.explosionSource = new net.minecraft.world.level.ServerExplosion(level.getMinecraftWorld(), this, null, null, new Vec3(Double.NaN, Double.NaN, Double.NaN), Float.NaN, true, net.minecraft.world.level.Explosion.BlockInteraction.DESTROY); // Paper + + // Purpur start - Ridables + this.moveControl = new org.purpurmc.purpur.controller.FlyingMoveControllerWASD(this) { + @Override + public void vanillaTick() { + // dragon doesn't use the controller. do nothing + } + }; + this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) { + @Override + public void vanillaTick() { + // dragon doesn't use the controller. do nothing + } + + @Override + public void purpurTick(Player rider) { + setYawPitch(rider.getYRot() - 180F, rider.xRotO * 0.5F); + } + }; + // Purpur end - Ridables + } + + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.enderDragonRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.enderDragonRidableInWater; } public void setDragonFight(EndDragonFight dragonFight) { @@ -120,6 +152,17 @@ public class EnderDragon extends Mob implements Enemy { return this.fightOrigin; } + @Override + public boolean isControllable() { + return level().purpurConfig.enderDragonControllable; + } + + @Override + public double getMaxY() { + return level().purpurConfig.enderDragonMaxY; + } + // Purpur end - Ridables + public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0); } @@ -169,6 +212,37 @@ public class EnderDragon extends Mob implements Enemy { @Override public void aiStep() { + // Purpur start - Ridables + boolean hasRider = getRider() != null && this.isControllable(); + 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 - Ridables + this.processFlappingMovement(); if (this.level().isClientSide) { this.setHealth(this.getHealth()); @@ -197,6 +271,8 @@ public class EnderDragon extends Mob implements Enemy { this.oFlapTime = this.flapTime; if (this.isDeadOrDying()) { + if (hasRider) ejectPassengers(); // Purpur - Ridables + float f = (this.random.nextFloat() - 0.5F) * 8.0F; float f1 = (this.random.nextFloat() - 0.5F) * 4.0F; float f2 = (this.random.nextFloat() - 0.5F) * 8.0F; @@ -206,9 +282,9 @@ public class EnderDragon extends Mob implements Enemy { Vec3 deltaMovement = this.getDeltaMovement(); float f1 = 0.2F / ((float)deltaMovement.horizontalDistance() * 10.0F + 1.0F); f1 *= (float)Math.pow(2.0, deltaMovement.y); - if (this.phaseManager.getCurrentPhase().isSitting()) { + if (!hasRider && this.phaseManager.getCurrentPhase().isSitting()) { // Purpur - Ridables this.flapTime += 0.1F; - } else if (this.inWall) { + } else if (!hasRider && this.inWall) { // Purpur - Ridables this.flapTime += f1 * 0.5F; } else { this.flapTime += f1; @@ -219,7 +295,7 @@ public class EnderDragon extends Mob implements Enemy { this.flapTime = 0.5F; } else { this.flightHistory.record(this.getY(), this.getYRot()); - if (this.level() instanceof ServerLevel serverLevel1) { + if (this.level() instanceof ServerLevel serverLevel1 && !hasRider) { // Purpur - Ridables DragonPhaseInstance currentPhase = this.phaseManager.getCurrentPhase(); currentPhase.doServerTick(serverLevel1); if (this.phaseManager.getCurrentPhase() != currentPhase) { @@ -298,7 +374,7 @@ public class EnderDragon extends Mob implements Enemy { this.tickPart(this.body, sin1 * 0.5F, 0.0, -cos1 * 0.5F); this.tickPart(this.wing1, cos1 * 4.5F, 2.0, sin1 * 4.5F); this.tickPart(this.wing2, cos1 * -4.5F, 2.0, sin1 * -4.5F); - if (this.level() instanceof ServerLevel serverLevel2 && this.hurtTime == 0) { + if (this.level() instanceof ServerLevel serverLevel2 && this.hurtTime == 0 && !hasRider) { // Purpur - Ridables this.knockBack( serverLevel2, serverLevel2.getEntities( @@ -348,9 +424,9 @@ public class EnderDragon extends Mob implements Enemy { } if (this.level() instanceof ServerLevel serverLevel3) { - this.inWall = this.checkWalls(serverLevel3, this.head.getBoundingBox()) + this.inWall = !hasRider && this.checkWalls(serverLevel3, this.head.getBoundingBox()) | this.checkWalls(serverLevel3, this.neck.getBoundingBox()) - | this.checkWalls(serverLevel3, this.body.getBoundingBox()); + | this.checkWalls(serverLevel3, this.body.getBoundingBox()); // Purpur - Ridables if (this.dragonFight != null) { this.dragonFight.updateDragon(this); } diff --git a/net/minecraft/world/entity/boss/wither/WitherBoss.java b/net/minecraft/world/entity/boss/wither/WitherBoss.java index 95cf215e8804cc2d7b681723dfebd1dcb8cbaeee..5d97ae09292fb3209e7362df778e88dc508815a3 100644 --- a/net/minecraft/world/entity/boss/wither/WitherBoss.java +++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java @@ -69,6 +69,7 @@ public class WitherBoss extends Monster implements RangedAttackMob { private final int[] nextHeadUpdate = new int[2]; private final int[] idleHeadUpdates = new int[2]; private int destroyBlocksTick; + private int shootCooldown = 0; // Purpur - Ridables private boolean canPortal = false; // Paper public final ServerBossEvent bossEvent = (ServerBossEvent)new ServerBossEvent( this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS @@ -78,9 +79,23 @@ public class WitherBoss extends Monster implements RangedAttackMob { && entity.attackable(); private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0).selector(LIVING_ENTITY_SELECTOR); @Nullable private java.util.UUID summoner; // Purpur - Summoner API + private org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD purpurController; // Purpur - Ridables public WitherBoss(EntityType entityType, Level level) { super(entityType, level); + // Purpur start - Ridables + this.purpurController = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.1F); + this.moveControl = new FlyingMoveControl(this, 10, false) { + @Override + public void tick() { + if (mob.getRider() != null && mob.isControllable()) { + purpurController.purpurTick(mob.getRider()); + } else { + super.tick(); + } + } + }; + // Purpur end - Ridables this.moveControl = new FlyingMoveControl(this, 10, false); this.setHealth(this.getMaxHealth()); this.xpReward = 50; @@ -97,6 +112,105 @@ public class WitherBoss extends Monster implements RangedAttackMob { } // Purpur end - Summoner API + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.witherRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.witherControllable; + } + + @Override + public double getMaxY() { + return level().purpurConfig.witherMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && this.isControllable() && !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().stop(); + 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); + Vec3 vec3d = new Vec3(x - headX, y - headY, z - headZ); + WitherSkull skull = new WitherSkull(level(), this, vec3d.normalize()); + skull.setPosRaw(headX, headY, headZ); + level().addFreshEntity(skull); + } + // Purpur end - Ridables + @Override protected PathNavigation createNavigation(Level level) { FlyingPathNavigation flyingPathNavigation = new FlyingPathNavigation(this, level); @@ -107,11 +221,13 @@ public class WitherBoss extends Monster implements RangedAttackMob { @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(0, new WitherBoss.WitherDoNothingGoal()); this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0, 40, 20.0F)); this.goalSelector.addGoal(5, new WaterAvoidingRandomFlyingGoal(this, 1.0)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 0, false, false, LIVING_ENTITY_SELECTOR)); } @@ -271,6 +387,15 @@ public class WitherBoss extends Monster implements RangedAttackMob { @Override protected void customServerAiStep(ServerLevel level) { + // Purpur start - Ridables + if (getRider() != null && this.isControllable()) { + Vec3 mot = getDeltaMovement(); + setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z()); + } + if (shootCooldown > 0) { + shootCooldown--; + } + // Purpur end - Ridables if (this.getInvulnerableTicks() > 0) { int i = this.getInvulnerableTicks() - 1; this.bossEvent.setProgress(1.0F - i / 220.0F); @@ -577,11 +702,11 @@ public class WitherBoss extends Monster implements RangedAttackMob { } public int getAlternativeTarget(int head) { - return this.entityData.get(DATA_TARGETS.get(head)); + return getRider() != null && this.isControllable() ? 0 : this.entityData.get(DATA_TARGETS.get(head)); // Purpur - Ridables } public void setAlternativeTarget(int targetOffset, int newId) { - this.entityData.set(DATA_TARGETS.get(targetOffset), newId); + if (getRider() == null || !this.isControllable()) this.entityData.set(DATA_TARGETS.get(targetOffset), newId); // Purpur - Ridables } public boolean isPowered() { diff --git a/net/minecraft/world/entity/monster/AbstractSkeleton.java b/net/minecraft/world/entity/monster/AbstractSkeleton.java index 1e97cb34aa22ad3150b598232dd339213b236f5c..e186aee80b052b7fc4bfe02763010bfb2d55ea35 100644 --- a/net/minecraft/world/entity/monster/AbstractSkeleton.java +++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java @@ -73,12 +73,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(2, new RestrictSunGoal(this)); this.goalSelector.addGoal(3, new FleeSunGoal(this, 1.0)); this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Wolf.class, 6.0F, 1.0, 1.2)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); diff --git a/net/minecraft/world/entity/monster/Blaze.java b/net/minecraft/world/entity/monster/Blaze.java index 419c729502ee708bba9e750f1b951450eca82695..201b08a75c42d90e657c3d56fc6691839e87199c 100644 --- a/net/minecraft/world/entity/monster/Blaze.java +++ b/net/minecraft/world/entity/monster/Blaze.java @@ -33,6 +33,7 @@ public class Blaze extends Monster { public Blaze(EntityType entityType, Level level) { super(entityType, level); + this.moveControl = new org.purpurmc.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur - Ridables this.setPathfindingMalus(PathType.WATER, -1.0F); this.setPathfindingMalus(PathType.LAVA, 8.0F); this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); @@ -40,19 +41,55 @@ public class Blaze extends Monster { this.xpReward = 10; } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.blazeRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.blazeRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.blazeControllable; + } + + @Override + public double getMaxY() { + return level().purpurConfig.blazeMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && this.isControllable() && !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 - Ridables + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(4, new Blaze.BlazeAttackGoal(this)); this.goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 1.0)); this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0, 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 org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables 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.0).add(Attributes.MOVEMENT_SPEED, 0.23F).add(Attributes.FOLLOW_RANGE, 48.0); + return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0).add(Attributes.MOVEMENT_SPEED, 0.23F).add(Attributes.FOLLOW_RANGE, 48.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - Ridables } @Override @@ -117,6 +154,13 @@ public class Blaze extends Monster { @Override protected void customServerAiStep(ServerLevel level) { + // Purpur start - Ridables + if (getRider() != null && this.isControllable()) { + Vec3 mot = getDeltaMovement(); + setDeltaMovement(mot.x(), getVerticalMot() > 0 ? 0.07D : -0.07D, mot.z()); + return; + } + // Purpur end - Ridables this.nextHeightOffsetChangeTick--; if (this.nextHeightOffsetChangeTick <= 0) { this.nextHeightOffsetChangeTick = 100; diff --git a/net/minecraft/world/entity/monster/Bogged.java b/net/minecraft/world/entity/monster/Bogged.java index f01670f7106a39957c9b37839fcca0d9f29208f0..2b603c1242aac307f28bae5a85bcaad309f929f5 100644 --- a/net/minecraft/world/entity/monster/Bogged.java +++ b/net/minecraft/world/entity/monster/Bogged.java @@ -41,6 +41,23 @@ public class Bogged extends AbstractSkeleton implements Shearable { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.boggedRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.boggedRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.boggedControllable; + } + // Purpur end - Ridables + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); diff --git a/net/minecraft/world/entity/monster/CaveSpider.java b/net/minecraft/world/entity/monster/CaveSpider.java index 2e32567fca7a2a4cd87bc078a6eeb30e3ffabfce..4873a3d8dd9c160ecdbda594ee546c35ec03a1e7 100644 --- a/net/minecraft/world/entity/monster/CaveSpider.java +++ b/net/minecraft/world/entity/monster/CaveSpider.java @@ -26,6 +26,23 @@ public class CaveSpider extends Spider { return Spider.createAttributes().add(Attributes.MAX_HEALTH, 12.0); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.caveSpiderRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.caveSpiderRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.caveSpiderControllable; + } + // Purpur end - Ridables + @Override public boolean doHurtTarget(ServerLevel level, Entity source) { if (super.doHurtTarget(level, source)) { diff --git a/net/minecraft/world/entity/monster/Creeper.java b/net/minecraft/world/entity/monster/Creeper.java index 9aff3c911a56885ab3c34bb34bb05e7b1c00d3bd..cdcee233ed0c272e4a68a2a709fe92b21bc6c22c 100644 --- a/net/minecraft/world/entity/monster/Creeper.java +++ b/net/minecraft/world/entity/monster/Creeper.java @@ -51,21 +51,98 @@ public class Creeper extends Monster { private int droppedSkulls; public Entity entityIgniter; // CraftBukkit private boolean exploding = false; // Purpur - Config to make Creepers explode on death + // Purpur start - Ridables + private int spacebarCharge = 0; + private int prevSpacebarCharge = 0; + private int powerToggleDelay = 0; + // Purpur end - Ridables public Creeper(EntityType entityType, Level level) { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.creeperRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.creeperRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.creeperControllable; + } + + @Override + protected void customServerAiStep(ServerLevel world) { + if (powerToggleDelay > 0) { + powerToggleDelay--; + } + if (getRider() != null && this.isControllable()) { + if (getRider().getForwardMot() != 0 || getRider().getStrafeMot() != 0) { + spacebarCharge = 0; + setIgnited(false); + setSwellDir(-1); + } + if (spacebarCharge == prevSpacebarCharge) { + spacebarCharge = 0; + } + prevSpacebarCharge = spacebarCharge; + } + super.customServerAiStep(world); + } + + @Override + public void onMount(Player rider) { + super.onMount(rider); + setIgnited(false); + setSwellDir(-1); + } + + @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); + setSwellDir(-1); + return true; + } + } + if (!isIgnited()) { + if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0 && + getRider().getBukkitEntity().hasPermission("allow.special.creeper")) { + setIgnited(true); + setSwellDir(1); + return true; + } + } + return getForwardMot() == 0 && getStrafeMot() == 0; // do not jump if standing still + } + // Purpur end - Ridables + @Override protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); this.goalSelector.addGoal(2, new SwellGoal(this)); + this.goalSelector.addGoal(3, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Ocelot.class, 6.0F, 1.0, 1.2)); this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Cat.class, 6.0F, 1.0, 1.2)); this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, false)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(2, new HurtByTargetGoal(this)); } @@ -312,6 +389,7 @@ public class Creeper extends Monster { 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(DATA_IS_IGNITED, event.isIgnited()); + if (!event.isIgnited()) setSwellDir(-1); // Purpur - Ridables } } } diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java index 6c1e816356243686f7d0bfa031badc75b54b215d..c1da9ebee7e870a9143e6224be9e9f4e62232459 100644 --- a/net/minecraft/world/entity/monster/Drowned.java +++ b/net/minecraft/world/entity/monster/Drowned.java @@ -75,6 +75,23 @@ public class Drowned extends Zombie implements RangedAttackMob { return Zombie.createAttributes().add(Attributes.STEP_HEIGHT, 1.0); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.drownedRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.drownedRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.drownedControllable; + } + // Purpur end - Ridables + @Override protected void addBehaviourGoals() { this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0)); @@ -408,7 +425,7 @@ public class Drowned extends Zombie implements RangedAttackMob { } } - static class DrownedMoveControl extends MoveControl { + static class DrownedMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables private final Drowned drowned; public DrownedMoveControl(Drowned mob) { @@ -417,7 +434,7 @@ public class Drowned extends Zombie implements RangedAttackMob { } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables LivingEntity target = this.drowned.getTarget(); if (this.drowned.wantsToSwim() && this.drowned.isInWater()) { if (target != null && target.getY() > this.drowned.getY() || this.drowned.searchingForLand) { @@ -437,7 +454,7 @@ public class Drowned extends Zombie implements RangedAttackMob { float f = (float)(Mth.atan2(d2, d) * 180.0F / (float)Math.PI) - 90.0F; this.drowned.setYRot(this.rotlerp(this.drowned.getYRot(), f, 90.0F)); this.drowned.yBodyRot = this.drowned.getYRot(); - float f1 = (float)(this.speedModifier * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); + float f1 = (float)(this.getSpeedModifier() * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables float f2 = Mth.lerp(0.125F, this.drowned.getSpeed(), f1); this.drowned.setSpeed(f2); this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(f2 * d * 0.005, f2 * d1 * 0.1, f2 * d2 * 0.005)); @@ -446,7 +463,7 @@ public class Drowned extends Zombie implements RangedAttackMob { this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(0.0, -0.008, 0.0)); } - super.tick(); + super.vanillaTick(); // Purpur - Ridables } } } diff --git a/net/minecraft/world/entity/monster/ElderGuardian.java b/net/minecraft/world/entity/monster/ElderGuardian.java index 4585b7c867685f8419c4d2b5b90af5946d337f90..c6eeaf7b460408acfdf89d988b47b08eab7df4c5 100644 --- a/net/minecraft/world/entity/monster/ElderGuardian.java +++ b/net/minecraft/world/entity/monster/ElderGuardian.java @@ -31,6 +31,18 @@ public class ElderGuardian extends Guardian { } } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.elderGuardianRidable; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.elderGuardianControllable; + } + // Purpur end - Ridables + public static AttributeSupplier.Builder createAttributes() { return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.3F).add(Attributes.ATTACK_DAMAGE, 8.0).add(Attributes.MAX_HEALTH, 80.0); } diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java index 8709588083fd5ca6a31d9a8d4096475d117915a1..cf511c78638e0d7aa652d1c880b3cd8172d5b3cf 100644 --- a/net/minecraft/world/entity/monster/EnderMan.java +++ b/net/minecraft/world/entity/monster/EnderMan.java @@ -90,9 +90,27 @@ public class EnderMan extends Monster implements NeutralMob { this.setPathfindingMalus(PathType.WATER, -1.0F); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.endermanRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.endermanRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.endermanControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new EnderMan.EndermanFreezeWhenLookedAt(this)); this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0, false)); this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0, 0.0F)); @@ -100,6 +118,7 @@ public class EnderMan extends Monster implements NeutralMob { this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); this.goalSelector.addGoal(10, new EnderMan.EndermanLeaveBlockGoal(this)); this.goalSelector.addGoal(11, new EnderMan.EndermanTakeBlockGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt)); this.targetSelector.addGoal(2, new HurtByTargetGoal(this)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, 10, true, false, (entityliving, ignored) -> entityliving.level().purpurConfig.endermanAggroEndermites && entityliving instanceof Endermite endermite && (!entityliving.level().purpurConfig.endermanAggroEndermitesOnlyIfPlayerSpawned || endermite.isPlayerSpawned()))); // Purpur @@ -272,7 +291,7 @@ public class EnderMan extends Monster implements NeutralMob { @Override protected void customServerAiStep(ServerLevel level) { - if (level.isDay() && this.tickCount >= this.targetChangeTime + 600) { + if ((getRider() == null || !this.isControllable()) && level.isDay() && this.tickCount >= this.targetChangeTime + 600) { // Purpur - Ridables - no random teleporting float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue(); if (lightLevelDependentMagicValue > 0.5F && level.canSeeSky(this.blockPosition()) @@ -385,6 +404,7 @@ public class EnderMan extends Monster implements NeutralMob { public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { if (this.isInvulnerableTo(level, damageSource)) { return false; + } else if (getRider() != null && this.isControllable()) { return super.hurtServer(level, damageSource, amount); // Purpur - no teleporting on damage } else if (org.purpurmc.purpur.PurpurConfig.endermanShortHeight && damageSource.is(net.minecraft.world.damagesource.DamageTypes.IN_WALL)) { return false; // Purpur - no suffocation damage if short height - Short enderman height } else { boolean flag = damageSource.getDirectEntity() instanceof ThrownPotion; diff --git a/net/minecraft/world/entity/monster/Endermite.java b/net/minecraft/world/entity/monster/Endermite.java index 4e00daa6ece386f70502c074084b7b1b64caac2f..f4ab2e984dd87d2372aa10d2cbfd03a3f6fb1249 100644 --- a/net/minecraft/world/entity/monster/Endermite.java +++ b/net/minecraft/world/entity/monster/Endermite.java @@ -45,14 +45,33 @@ public class Endermite extends Monster { } // Purpur end - Add back player spawned endermite API + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.endermiteRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.endermiteRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.endermiteControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new ClimbOnTopOfPowderSnowGoal(this, this.level())); this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0, false)); this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 1.0)); this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers()); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); } diff --git a/net/minecraft/world/entity/monster/Evoker.java b/net/minecraft/world/entity/monster/Evoker.java index b70ea1af39cada6bb17001c6b65502510e34c4b2..2eaeb0c0c0cb917506443ed1380b81f317961d53 100644 --- a/net/minecraft/world/entity/monster/Evoker.java +++ b/net/minecraft/world/entity/monster/Evoker.java @@ -50,10 +50,28 @@ public class Evoker extends SpellcasterIllager { this.xpReward = 10; } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.evokerRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.evokerRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.evokerControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new Evoker.EvokerCastingSpellGoal()); this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 0.6, 1.0)); this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 0.6, 1.0)); @@ -63,6 +81,7 @@ public class Evoker extends SpellcasterIllager { this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6)); this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true).setUnseenMemoryTicks(300)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false).setUnseenMemoryTicks(300)); diff --git a/net/minecraft/world/entity/monster/Ghast.java b/net/minecraft/world/entity/monster/Ghast.java index b97bbfbbc8c1a4f38b4b858ef4915b637cc8a627..00c05fb5736c90c94f6fe51793acf8b65b1d0505 100644 --- a/net/minecraft/world/entity/monster/Ghast.java +++ b/net/minecraft/world/entity/monster/Ghast.java @@ -42,11 +42,47 @@ public class Ghast extends FlyingMob implements Enemy { this.moveControl = new Ghast.GhastMoveControl(this); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.ghastRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ghastRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.ghastControllable; + } + + @Override + public double getMaxY() { + return level().purpurConfig.ghastMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && this.isControllable() && !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 - Ridables + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(5, new Ghast.RandomFloatAroundGoal(this)); this.goalSelector.addGoal(7, new Ghast.GhastLookGoal(this)); this.goalSelector.addGoal(7, new Ghast.GhastShootFireballGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector .addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entity, level) -> Math.abs(entity.getY() - this.getY()) <= 4.0)); } @@ -101,7 +137,7 @@ public class Ghast extends FlyingMob implements Enemy { } public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.FOLLOW_RANGE, 100.0); + return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.FOLLOW_RANGE, 100.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur - Ridables } @Override @@ -191,7 +227,7 @@ public class Ghast extends FlyingMob implements Enemy { } } - static class GhastMoveControl extends MoveControl { + static class GhastMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - Ridables private final Ghast ghast; private int floatDuration; @@ -201,7 +237,7 @@ public class Ghast extends FlyingMob implements Enemy { } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (this.operation == MoveControl.Operation.MOVE_TO) { if (this.floatDuration-- <= 0) { this.floatDuration = this.floatDuration + this.ghast.getRandom().nextInt(5) + 2; diff --git a/net/minecraft/world/entity/monster/Giant.java b/net/minecraft/world/entity/monster/Giant.java index 969eb604851d1cce50f0f99ed479189061d5de0c..135f83484ac31db7dcc225ba6f94e2e4ca27eea8 100644 --- a/net/minecraft/world/entity/monster/Giant.java +++ b/net/minecraft/world/entity/monster/Giant.java @@ -12,6 +12,29 @@ public class Giant extends Monster { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.giantRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.giantRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.giantControllable; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); + } + // Purpur end - Ridables + public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 100.0).add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.ATTACK_DAMAGE, 50.0); } diff --git a/net/minecraft/world/entity/monster/Guardian.java b/net/minecraft/world/entity/monster/Guardian.java index c8e249b8f7ee8e9c075169ec988f5a0d459a3767..c20c744522459d938c772077e542ba433bc4c80e 100644 --- a/net/minecraft/world/entity/monster/Guardian.java +++ b/net/minecraft/world/entity/monster/Guardian.java @@ -66,14 +66,35 @@ public class Guardian extends Monster { this.xpReward = 10; this.setPathfindingMalus(PathType.WATER, 0.0F); this.moveControl = new Guardian.GuardianMoveControl(this); + // Purpur start - Ridables + this.lookControl = new org.purpurmc.purpur.controller.LookControllerWASD(this) { + @Override + public void setYawPitch(float yaw, float pitch) { + super.setYawPitch(yaw, pitch * 0.35F); + } + }; + // Purpur end - Ridables this.clientSideTailAnimation = this.random.nextFloat(); this.clientSideTailAnimationO = this.clientSideTailAnimation; } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.guardianRidable; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.guardianControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { MoveTowardsRestrictionGoal moveTowardsRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0); this.randomStrollGoal = new RandomStrollGoal(this, 1.0, 80); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(4, this.guardianAttackGoal = new Guardian.GuardianAttackGoal(this)); // CraftBukkit - assign field this.goalSelector.addGoal(5, moveTowardsRestrictionGoal); this.goalSelector.addGoal(7, this.randomStrollGoal); @@ -82,6 +103,7 @@ public class Guardian extends Monster { this.goalSelector.addGoal(9, new RandomLookAroundGoal(this)); this.randomStrollGoal.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); moveTowardsRestrictionGoal.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 10, true, false, new Guardian.GuardianAttackSelector(this))); } @@ -344,7 +366,7 @@ public class Guardian extends Monster { @Override public void travel(Vec3 travelVector) { if (this.isControlledByLocalInstance() && this.isInWater()) { - this.moveRelative(0.1F, travelVector); + this.moveRelative(getRider() != null && this.isControllable() ? getSpeed() : 0.1F, travelVector); // Purpur - Ridables this.move(MoverType.SELF, this.getDeltaMovement()); this.setDeltaMovement(this.getDeltaMovement().scale(0.9)); if (!this.isMoving() && this.getTarget() == null) { @@ -452,7 +474,7 @@ public class Guardian extends Monster { } } - static class GuardianMoveControl extends MoveControl { + static class GuardianMoveControl extends org.purpurmc.purpur.controller.WaterMoveControllerWASD { // Purpur - Ridables private final Guardian guardian; public GuardianMoveControl(Guardian mob) { @@ -460,8 +482,17 @@ public class Guardian extends Monster { this.guardian = mob; } + // Purpur start - Ridables @Override - public void tick() { + public void purpurTick(Player rider) { + super.purpurTick(rider); + guardian.setDeltaMovement(guardian.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); + guardian.setMoving(guardian.getForwardMot() > 0.0F); // control tail speed + } + // Purpur end - Ridables + + @Override + public void vanillaTick() { // Purpur - Ridables if (this.operation == MoveControl.Operation.MOVE_TO && !this.guardian.getNavigation().isDone()) { Vec3 vec3 = new Vec3(this.wantedX - this.guardian.getX(), this.wantedY - this.guardian.getY(), this.wantedZ - this.guardian.getZ()); double len = vec3.length(); @@ -471,7 +502,7 @@ public class Guardian extends Monster { float f = (float)(Mth.atan2(vec3.z, vec3.x) * 180.0F / (float)Math.PI) - 90.0F; this.guardian.setYRot(this.rotlerp(this.guardian.getYRot(), f, 90.0F)); this.guardian.yBodyRot = this.guardian.getYRot(); - float f1 = (float)(this.speedModifier * this.guardian.getAttributeValue(Attributes.MOVEMENT_SPEED)); + float f1 = (float)(this.getSpeedModifier() * this.guardian.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur - Ridables float f2 = Mth.lerp(0.125F, this.guardian.getSpeed(), f1); this.guardian.setSpeed(f2); double d3 = Math.sin((this.guardian.tickCount + this.guardian.getId()) * 0.5) * 0.05; diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java index 6155c544ad2722a49c5e41dd7d7b02fedc56474e..23936305045299352561e866b6a28aa515cd614a 100644 --- a/net/minecraft/world/entity/monster/Husk.java +++ b/net/minecraft/world/entity/monster/Husk.java @@ -21,6 +21,23 @@ public class Husk extends Zombie { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.huskRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.huskRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.huskControllable; + } + // Purpur end - Ridables + public static boolean checkHuskSpawnRules( EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random ) { diff --git a/net/minecraft/world/entity/monster/Illusioner.java b/net/minecraft/world/entity/monster/Illusioner.java index 40ca12e391b2adac6b132f1832b1427acb3748bc..bd0f4d77260f5b123856fc7e72d5f8e74bb45321 100644 --- a/net/minecraft/world/entity/monster/Illusioner.java +++ b/net/minecraft/world/entity/monster/Illusioner.java @@ -57,10 +57,28 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { } } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.illusionerRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.illusionerRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.illusionerControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new SpellcasterIllager.SpellcasterCastingSpellGoal()); this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2)); this.goalSelector.addGoal(4, new Illusioner.IllusionerMirrorSpellGoal()); @@ -69,6 +87,7 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6)); this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true).setUnseenMemoryTicks(300)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false).setUnseenMemoryTicks(300)); diff --git a/net/minecraft/world/entity/monster/MagmaCube.java b/net/minecraft/world/entity/monster/MagmaCube.java index 905ecbd8b22c785ee4ea18004ac50eb1b7005d3f..f10b204c18b88e9110cebf050b60c23367ea3aa0 100644 --- a/net/minecraft/world/entity/monster/MagmaCube.java +++ b/net/minecraft/world/entity/monster/MagmaCube.java @@ -24,6 +24,28 @@ public class MagmaCube extends Slime { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.magmaCubeRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.magmaCubeRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.magmaCubeControllable; + } + + @Override + public float getJumpPower() { + return 0.42F * this.getBlockJumpFactor(); // from EntityLiving + } + // Purpur end - Ridables + public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2F); } @@ -71,6 +93,7 @@ public class MagmaCube extends Slime { float f = this.getSize() * 0.1F; this.setDeltaMovement(deltaMovement.x, this.getJumpPower() + f, deltaMovement.z); this.hasImpulse = true; + this.actualJump = false; // Purpur - Ridables } @Override diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java index 9ea3acd5ff3d7751875d61861aa5f6c717d0b5e2..75c6a43a3ab4851a47990402bee49f7e8305cd60 100644 --- a/net/minecraft/world/entity/monster/Phantom.java +++ b/net/minecraft/world/entity/monster/Phantom.java @@ -60,6 +60,64 @@ public class Phantom extends FlyingMob implements Enemy { this.lookControl = new Phantom.PhantomLookControl(this); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.phantomRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.phantomRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.phantomControllable; + } + + @Override + public double getMaxY() { + return level().purpurConfig.phantomMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && this.isControllable() && !onGround) { + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); + setSpeed(speed); + Vec3 mot = getDeltaMovement(); + move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, speed, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } + + public static net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder createAttributes() { + return Monster.createMonsterAttributes().add(Attributes.FLYING_SPEED, 3.0D); + } + + @Override + public boolean onSpacebar() { + if (getRider() != null && getRider().getBukkitEntity().hasPermission("allow.special.phantom")) { + shoot(); + } + return false; + } + + public boolean shoot() { + org.bukkit.Location loc = ((org.bukkit.entity.LivingEntity) getBukkitEntity()).getEyeLocation(); + loc.setPitch(-loc.getPitch()); + org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(100).add(loc.toVector()); + + org.purpurmc.purpur.entity.projectile.PhantomFlames flames = new org.purpurmc.purpur.entity.projectile.PhantomFlames(level(), this); + flames.canGrief = level().purpurConfig.phantomAllowGriefing; + flames.shoot(target.getX() - getX(), target.getY() - getY(), target.getZ() - getZ(), 1.0F, 5.0F); + level().addFreshEntity(flames); + return true; + } + // Purpur end - Ridables + @Override public boolean isFlapping() { return (this.getUniqueFlapTickOffset() + this.tickCount) % TICKS_PER_FLAP == 0; @@ -72,9 +130,11 @@ public class Phantom extends FlyingMob implements Enemy { @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new Phantom.PhantomAttackStrategyGoal()); this.goalSelector.addGoal(2, new Phantom.PhantomSweepAttackGoal()); this.goalSelector.addGoal(3, new Phantom.PhantomCircleAroundAnchorGoal()); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal()); } @@ -90,6 +150,7 @@ public class Phantom extends FlyingMob implements Enemy { private void updatePhantomSizeInfo() { this.refreshDimensions(); + if (level().purpurConfig.phantomFlamesOnSwoop && attackPhase == AttackPhase.SWOOP) shoot(); // Purpur - Ridables - Phantom flames on swoop this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(6 + this.getPhantomSize()); } @@ -147,6 +208,7 @@ public class Phantom extends FlyingMob implements Enemy { @Override public void aiStep() { if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API + if (getRider() == null || !this.isControllable()) // Purpur - Ridables this.igniteForSeconds(8.0F); } @@ -411,25 +473,42 @@ public class Phantom extends FlyingMob implements Enemy { } } - static class PhantomLookControl extends LookControl { + static class PhantomLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables public PhantomLookControl(Mob mob) { super(mob); } + // Purpur start - Ridables + public void purpurTick(Player rider) { + setYawPitch(rider.getYRot(), -rider.xRotO * 0.75F); + } + // Purpur end - Ridables + @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables } } - class PhantomMoveControl extends MoveControl { + class PhantomMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - Ridables private float speed = 0.1F; public PhantomMoveControl(final Mob mob) { super(mob); } + // Purpur start - Ridables + public void purpurTick(Player rider) { + if (!Phantom.this.onGround) { + // phantom is always in motion when flying + // TODO - FIX THIS + // rider.setForward(1.0F); + } + super.purpurTick(rider); + } + // Purpur end - Ridables + @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (Phantom.this.horizontalCollision) { Phantom.this.setYRot(Phantom.this.getYRot() + 180.0F); this.speed = 0.1F; diff --git a/net/minecraft/world/entity/monster/Pillager.java b/net/minecraft/world/entity/monster/Pillager.java index e855ebc5be2cef3b96e2c01a8c1d388e433c0d52..4e799981f04cd17a34f043dda82869adcf16ea98 100644 --- a/net/minecraft/world/entity/monster/Pillager.java +++ b/net/minecraft/world/entity/monster/Pillager.java @@ -63,16 +63,35 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.pillagerRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.pillagerRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.pillagerControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2)); this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F)); this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0, 8.0F)); this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6)); this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 15.0F, 1.0F)); this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 15.0F)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); diff --git a/net/minecraft/world/entity/monster/Ravager.java b/net/minecraft/world/entity/monster/Ravager.java index 6f0fad37a05e9cd53b6e15c119127da492737c95..fb4e91c4f37619ce273ada0909932b32ba3b53f5 100644 --- a/net/minecraft/world/entity/monster/Ravager.java +++ b/net/minecraft/world/entity/monster/Ravager.java @@ -66,15 +66,40 @@ public class Ravager extends Raider { this.setPathfindingMalus(PathType.LEAVES, 0.0F); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.ravagerRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.ravagerRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.ravagerControllable; + } + + @Override + public void onMount(Player rider) { + super.onMount(rider); + getNavigation().stop(); + } + // Purpur end - Ridables + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); if (level().purpurConfig.ravagerAvoidRabbits) this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, net.minecraft.world.entity.animal.Rabbit.class, 6.0F, 1.0D, 1.2D)); // Purpur - option to make ravagers afraid of rabbits + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, true)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.4)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(2, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true, (entity, level) -> !entity.isBaby())); @@ -131,7 +156,7 @@ public class Ravager extends Raider { @Override public void aiStep() { super.aiStep(); - if (this.isAlive()) { + if (this.isAlive() && (getRider() == null || !this.isControllable())) { // Purpur - Ridables if (this.isImmobile()) { this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.0); } else { diff --git a/net/minecraft/world/entity/monster/Shulker.java b/net/minecraft/world/entity/monster/Shulker.java index 3f2668c79dd3d9e7973c1bba3e424b8220749682..e0a496a0c584e1f90967a8528a73536fd991e774 100644 --- a/net/minecraft/world/entity/monster/Shulker.java +++ b/net/minecraft/world/entity/monster/Shulker.java @@ -104,12 +104,31 @@ public class Shulker extends AbstractGolem implements VariantHolder(this, Player.class, true)); } diff --git a/net/minecraft/world/entity/monster/Skeleton.java b/net/minecraft/world/entity/monster/Skeleton.java index f0022458e3e01f6d01df0f8d69b2db73c77fb914..d4426daf3b8079a7e769013d43f44c72b0fce697 100644 --- a/net/minecraft/world/entity/monster/Skeleton.java +++ b/net/minecraft/world/entity/monster/Skeleton.java @@ -25,6 +25,23 @@ public class Skeleton extends AbstractSkeleton { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.skeletonRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.skeletonRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.skeletonControllable; + } + // Purpur end - Ridables + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); diff --git a/net/minecraft/world/entity/monster/Slime.java b/net/minecraft/world/entity/monster/Slime.java index 8db4cba1be6d7a5538295ba8da1fdaf7a77a16d0..7d31d68ac0fce102af480a47db73409926611428 100644 --- a/net/minecraft/world/entity/monster/Slime.java +++ b/net/minecraft/world/entity/monster/Slime.java @@ -57,6 +57,7 @@ public class Slime extends Mob implements Enemy { public float oSquish; private boolean wasOnGround; private boolean canWander = true; // Paper - Slime pathfinder events + protected boolean actualJump; // Purpur - Ridables public Slime(EntityType entityType, Level level) { super(entityType, level); @@ -64,12 +65,48 @@ public class Slime extends Mob implements Enemy { this.moveControl = new Slime.SlimeMoveControl(this); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.slimeRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.slimeRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.slimeControllable; + } + + @Override + public float getJumpPower() { + float height = super.getJumpPower(); + return getRider() != null && this.isControllable() && actualJump ? height * 1.5F : height; + } + + @Override + public boolean onSpacebar() { + if (onGround && getRider() != null && this.isControllable()) { + actualJump = true; + if (getRider().getForwardMot() == 0 || getRider().getStrafeMot() == 0) { + jumpFromGround(); // jump() here if not moving + } + } + return true; // do not jump() in wasd controller, let vanilla controller handle + } + // Purpur end - Ridables + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new Slime.SlimeFloatGoal(this)); this.goalSelector.addGoal(2, new Slime.SlimeAttackGoal(this)); this.goalSelector.addGoal(3, new Slime.SlimeRandomDirectionGoal(this)); this.goalSelector.addGoal(5, new Slime.SlimeKeepOnJumpingGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector .addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entity, level) -> Math.abs(entity.getY() - this.getY()) <= 4.0)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); @@ -371,6 +408,7 @@ public class Slime extends Mob implements Enemy { Vec3 deltaMovement = this.getDeltaMovement(); this.setDeltaMovement(deltaMovement.x, this.getJumpPower(), deltaMovement.z); this.hasImpulse = true; + this.actualJump = false; // Purpur - Ridables } @Nullable @@ -535,7 +573,7 @@ public class Slime extends Mob implements Enemy { } } - static class SlimeMoveControl extends MoveControl { + static class SlimeMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables private float yRot; private int jumpDelay; private final Slime slime; @@ -553,21 +591,33 @@ public class Slime extends Mob implements Enemy { } public void setWantedMovement(double speed) { - this.speedModifier = speed; + this.setSpeedModifier(speed); // Purpur - Ridables this.operation = MoveControl.Operation.MOVE_TO; } @Override public void tick() { + // Purpur start - Ridables + if (slime.getRider() != null && slime.isControllable()) { + purpurTick(slime.getRider()); + if (slime.getForwardMot() != 0 || slime.getStrafeMot() != 0) { + if (jumpDelay > 10) { + jumpDelay = 6; + } + } else { + jumpDelay = 20; + } + } else { + // Purpur end - Ridables this.mob.setYRot(this.rotlerp(this.mob.getYRot(), this.yRot, 90.0F)); this.mob.yHeadRot = this.mob.getYRot(); this.mob.yBodyRot = this.mob.getYRot(); - if (this.operation != MoveControl.Operation.MOVE_TO) { + } if ((slime.getRider() == null || !slime.isControllable()) && this.operation != MoveControl.Operation.MOVE_TO) { // Purpur - Ridables this.mob.setZza(0.0F); } else { this.operation = MoveControl.Operation.WAIT; if (this.mob.onGround()) { - this.mob.setSpeed((float)(this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED))); + this.mob.setSpeed((float)(this.getSpeedModifier() * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED) * (slime.getRider() != null && slime.isControllable() && (slime.getRider().getForwardMot() != 0 || slime.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur - Ridables if (this.jumpDelay-- <= 0) { this.jumpDelay = this.slime.getJumpDelay(); if (this.isAggressive) { @@ -584,7 +634,7 @@ public class Slime extends Mob implements Enemy { this.mob.setSpeed(0.0F); } } else { - this.mob.setSpeed((float)(this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED))); + this.mob.setSpeed((float)(this.getSpeedModifier() * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED) * (slime.getRider() != null && slime.isControllable() && (slime.getRider().getForwardMot() != 0 || slime.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur - Ridables } } } diff --git a/net/minecraft/world/entity/monster/Spider.java b/net/minecraft/world/entity/monster/Spider.java index af0305079a367899708ee2bbac82aefaa9129d2f..ea83335dd0d128b32d2fe513eab82e642b533b4c 100644 --- a/net/minecraft/world/entity/monster/Spider.java +++ b/net/minecraft/world/entity/monster/Spider.java @@ -50,15 +50,34 @@ public class Spider extends Monster { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.spiderRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.spiderRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.spiderControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Armadillo.class, 6.0F, 1.0, 1.2, livingEntity -> !((Armadillo)livingEntity).isScared())); this.goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4F)); this.goalSelector.addGoal(4, new Spider.SpiderAttackGoal(this)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); this.targetSelector.addGoal(2, new Spider.SpiderTargetGoal<>(this, Player.class)); this.targetSelector.addGoal(3, new Spider.SpiderTargetGoal<>(this, IronGolem.class)); diff --git a/net/minecraft/world/entity/monster/Stray.java b/net/minecraft/world/entity/monster/Stray.java index 5fa2b7920a233afb3659b02cbd7ab82307ea9aaf..ed7ba19870a09ac78c1f069040a25e47c4b19d3a 100644 --- a/net/minecraft/world/entity/monster/Stray.java +++ b/net/minecraft/world/entity/monster/Stray.java @@ -22,6 +22,23 @@ public class Stray extends AbstractSkeleton { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.strayRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.strayRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.strayControllable; + } + // Purpur end - Ridables + public static boolean checkStraySpawnRules( EntityType entityType, ServerLevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random ) { diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java index ce690b564ea8ee055823928169fe605893498f3d..78671f02ef28f4a3b796b357d21fb4c9b64c153e 100644 --- a/net/minecraft/world/entity/monster/Strider.java +++ b/net/minecraft/world/entity/monster/Strider.java @@ -94,6 +94,23 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.striderRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.striderRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.striderControllable; + } + // Purpur end - Ridables + public static boolean checkStriderSpawnRules( EntityType entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random ) { @@ -156,6 +173,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { @Override protected void registerGoals() { this.goalSelector.addGoal(1, new PanicGoal(this, 1.65)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(2, new BreedGoal(this, 1.0)); this.temptGoal = new TemptGoal(this, 1.4, itemStack -> itemStack.is(ItemTags.STRIDER_TEMPT_ITEMS), false); this.goalSelector.addGoal(3, this.temptGoal); @@ -437,7 +455,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { InteractionResult interactionResult = super.mobInteract(player, hand); if (!interactionResult.consumesAction()) { ItemStack itemInHand = player.getItemInHand(hand); - return (InteractionResult)(itemInHand.is(Items.SADDLE) ? itemInHand.interactLivingEntity(player, this, hand) : InteractionResult.PASS); + return (InteractionResult)(itemInHand.is(Items.SADDLE) ? itemInHand.interactLivingEntity(player, this, hand) : tryRide(player, hand)); // Purpur - Ridables } else { if (isFood && !this.isSilent()) { this.level() diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java index 7f1cdea810db24182f8f87076c42a19b1b43e98a..26528bc9a9cffb68f82917a3e70900cfb65304d7 100644 --- a/net/minecraft/world/entity/monster/Vex.java +++ b/net/minecraft/world/entity/monster/Vex.java @@ -58,6 +58,50 @@ public class Vex extends Monster implements TraceableEntity { this.xpReward = 3; } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.vexRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vexRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.vexControllable; + } + + @Override + public double getMaxY() { + return level().purpurConfig.vexMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && this.isControllable()) { + float speed; + if (onGround) { + speed = (float) getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.1F; + } else { + 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)); + } + } + + @Override + public boolean causeFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource) { + return false; // no fall damage please + } + // Purpur end - Ridables + @Override public boolean isFlapping() { return this.tickCount % TICKS_PER_FLAP == 0; @@ -70,7 +114,7 @@ public class Vex extends Monster implements TraceableEntity { @Override public void tick() { - this.noPhysics = true; + this.noPhysics = getRider() == null || !this.isControllable(); // Purpur - Ridables super.tick(); this.noPhysics = false; this.setNoGravity(true); @@ -84,17 +128,19 @@ public class Vex extends Monster implements TraceableEntity { protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(4, new Vex.VexChargeAttackGoal()); this.goalSelector.addGoal(8, new Vex.VexRandomMoveGoal()); this.goalSelector.addGoal(9, new LookAtPlayerGoal(this, Player.class, 3.0F, 1.0F)); this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); this.targetSelector.addGoal(2, new Vex.VexCopyOwnerTargetGoal(this)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true)); } public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 14.0).add(Attributes.ATTACK_DAMAGE, 4.0); + return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 14.0).add(Attributes.ATTACK_DAMAGE, 4.0).add(Attributes.FLYING_SPEED, 0.6D); // Purpur; } @Override @@ -301,13 +347,13 @@ public class Vex extends Monster implements TraceableEntity { } } - class VexMoveControl extends MoveControl { + class VexMoveControl extends org.purpurmc.purpur.controller.FlyingMoveControllerWASD { // Purpur - Ridables public VexMoveControl(final Vex mob) { super(mob); } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (this.operation == MoveControl.Operation.MOVE_TO) { Vec3 vec3 = new Vec3(this.wantedX - Vex.this.getX(), this.wantedY - Vex.this.getY(), this.wantedZ - Vex.this.getZ()); double len = vec3.length(); @@ -315,7 +361,7 @@ public class Vex extends Monster implements TraceableEntity { this.operation = MoveControl.Operation.WAIT; Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().scale(0.5)); } else { - Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3.scale(this.speedModifier * 0.05 / len))); + Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3.scale(this.getSpeedModifier() * 0.05 / len))); // Purpur - Ridables if (Vex.this.getTarget() == null) { Vec3 deltaMovement = Vex.this.getDeltaMovement(); Vex.this.setYRot(-((float)Mth.atan2(deltaMovement.x, deltaMovement.z)) * (180.0F / (float)Math.PI)); diff --git a/net/minecraft/world/entity/monster/Vindicator.java b/net/minecraft/world/entity/monster/Vindicator.java index 5e7506f64159ac4838eee8594c995387e2fceed0..c1a1bb0be8bc77a1c0f771924f3bb8b4936d367b 100644 --- a/net/minecraft/world/entity/monster/Vindicator.java +++ b/net/minecraft/world/entity/monster/Vindicator.java @@ -55,15 +55,34 @@ public class Vindicator extends AbstractIllager { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.vindicatorRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.vindicatorRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.vindicatorControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Creaking.class, 8.0F, 1.0, 1.2)); this.goalSelector.addGoal(2, new Vindicator.VindicatorBreakDoorGoal(this)); this.goalSelector.addGoal(3, new AbstractIllager.RaiderOpenDoorGoal(this)); this.goalSelector.addGoal(4, new Raider.HoldGroundAttackGoal(this, 10.0F)); this.goalSelector.addGoal(5, new MeleeAttackGoal(this, 1.0, false)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class).setAlertOthers()); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); diff --git a/net/minecraft/world/entity/monster/Witch.java b/net/minecraft/world/entity/monster/Witch.java index 9f5676b5fa0f369adb8643391738c5ae33911df7..0b3c78e646d68ef57a7cf5d7eb77a07c497bd216 100644 --- a/net/minecraft/world/entity/monster/Witch.java +++ b/net/minecraft/world/entity/monster/Witch.java @@ -56,6 +56,23 @@ public class Witch extends Raider implements RangedAttackMob { super(entityType, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.witchRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witchRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.witchControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { super.registerGoals(); @@ -64,10 +81,12 @@ public class Witch extends Raider implements RangedAttackMob { ); this.attackPlayersGoal = new NearestAttackableWitchTargetGoal<>(this, Player.class, 10, true, false, null); this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0, 60, 10.0F)); this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0)); this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(3, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Raider.class)); this.targetSelector.addGoal(2, this.healRaidersGoal); this.targetSelector.addGoal(3, this.attackPlayersGoal); diff --git a/net/minecraft/world/entity/monster/WitherSkeleton.java b/net/minecraft/world/entity/monster/WitherSkeleton.java index eed8dbefd4d04082dc4e091c858e50309ed5c49b..b0f155564b11ff5fd2430694b937b7826df104ea 100644 --- a/net/minecraft/world/entity/monster/WitherSkeleton.java +++ b/net/minecraft/world/entity/monster/WitherSkeleton.java @@ -34,6 +34,23 @@ public class WitherSkeleton extends AbstractSkeleton { this.setPathfindingMalus(PathType.LAVA, 8.0F); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.witherSkeletonRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.witherSkeletonRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.witherSkeletonControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); diff --git a/net/minecraft/world/entity/monster/Zoglin.java b/net/minecraft/world/entity/monster/Zoglin.java index 9b94e74f6317f835500225b087fe93487a7a0b22..b279e33bb14dfea4813bba770daf950f5343419d 100644 --- a/net/minecraft/world/entity/monster/Zoglin.java +++ b/net/minecraft/world/entity/monster/Zoglin.java @@ -85,6 +85,23 @@ public class Zoglin extends Monster implements HoglinBase { this.xpReward = 5; } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.zoglinRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zoglinRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.zoglinControllable; + } + // Purpur end - Ridables + @Override protected Brain.Provider brainProvider() { return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); @@ -250,6 +267,7 @@ public class Zoglin extends Monster implements HoglinBase { protected void customServerAiStep(ServerLevel level) { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("zoglinBrain"); + if (getRider() == null || !this.isControllable()) // Purpur - only use brain if no rider this.getBrain().tick(level, this); profilerFiller.pop(); this.updateActivity(); diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java index a60c7b828332fc214caea10be9bc1505e2b5d0a9..6c6806fd7204e3610142f0365d158aee33ef8b2c 100644 --- a/net/minecraft/world/entity/monster/Zombie.java +++ b/net/minecraft/world/entity/monster/Zombie.java @@ -100,11 +100,30 @@ public class Zombie extends Monster { this(EntityType.ZOMBIE, level); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.zombieRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.zombieControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0, 3)); // Paper - Add zombie targets turtle egg config this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables this.addBehaviourGoals(); } diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java index 3608fbcd1998ddcdec8ec501dd5f6b80911104ee..33bb29bc03bce90750b3b9376a6ed848208a569d 100644 --- a/net/minecraft/world/entity/monster/ZombieVillager.java +++ b/net/minecraft/world/entity/monster/ZombieVillager.java @@ -78,6 +78,23 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { .ifPresent(profession -> this.setVillagerData(this.getVillagerData().setProfession(profession.value()))); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.zombieVillagerRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombieVillagerRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.zombieVillagerControllable; + } + // Purpur end - Ridables + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { super.defineSynchedData(builder); diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java index f1e25786ef687b4680db1cca96a5ae6068e93946..369f1224ea787ae034d86d0e92696882304cb271 100644 --- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java +++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java @@ -63,6 +63,23 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { this.setPathfindingMalus(PathType.LAVA, 8.0F); } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.zombifiedPiglinRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.zombifiedPiglinRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.zombifiedPiglinControllable; + } + // Purpur end - Ridables + @Override public void setPersistentAngerTarget(@Nullable UUID target) { this.persistentAngerTarget = target; diff --git a/net/minecraft/world/entity/monster/creaking/Creaking.java b/net/minecraft/world/entity/monster/creaking/Creaking.java index eba1e78352f956618b2796ce7cbe5d6f7e6591b6..57ac66c2de97c9b5940c1f0af663a1a26d2c8b73 100644 --- a/net/minecraft/world/entity/monster/creaking/Creaking.java +++ b/net/minecraft/world/entity/monster/creaking/Creaking.java @@ -102,6 +102,29 @@ public class Creaking extends Monster { return this.getHomePos() != null; } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.creakingRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.creakingRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.creakingControllable; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + } + // Purpur end - Ridables + @Override protected BodyRotationControl createBodyControl() { return new Creaking.CreakingBodyRotationControl(this); @@ -580,28 +603,28 @@ public class Creaking extends Monster { } } - class CreakingLookControl extends LookControl { + class CreakingLookControl extends org.purpurmc.purpur.controller.LookControllerWASD { // Purpur - Ridables { public CreakingLookControl(final Creaking mob) { super(mob); } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (Creaking.this.canMove()) { - super.tick(); + super.vanillaTick(); // Purpur - Ridables } } } - class CreakingMoveControl extends MoveControl { + class CreakingMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables public CreakingMoveControl(final Creaking mob) { super(mob); } @Override - public void tick() { + public void vanillaTick() { // Purpur - Ridables if (Creaking.this.canMove()) { - super.tick(); + super.vanillaTick(); // Purpur - Ridables } } } diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java index 0ddc0fe06a1b701f88ed8f8041ecd68f7da6c86d..028e09e1d8a14d989b2c19ca62e6544a93e1f1c4 100644 --- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java +++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java @@ -92,6 +92,23 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { this.xpReward = 5; } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.hoglinRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.hoglinRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.hoglinControllable; + } + // Purpur end - Ridables + @VisibleForTesting public void setTimeInOverworld(int timeInOverworld) { this.timeInOverworld = timeInOverworld; @@ -160,6 +177,7 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { protected void customServerAiStep(ServerLevel level) { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("hoglinBrain"); + //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider this.getBrain().tick(level, this); profilerFiller.pop(); HoglinAi.updateActivity(this); diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java index 0257eada48b35ea024520afe30596beae8a7ef1e..02d748ecb10c3e20aafc0c449b99ca5b6cd80e04 100644 --- a/net/minecraft/world/entity/monster/piglin/Piglin.java +++ b/net/minecraft/world/entity/monster/piglin/Piglin.java @@ -151,6 +151,23 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento this.xpReward = 5; } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.piglinRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.piglinRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.piglinControllable; + } + // Purpur end - Ridables + @Override public void addAdditionalSaveData(CompoundTag compound) { super.addAdditionalSaveData(compound); @@ -346,6 +363,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento protected void customServerAiStep(ServerLevel level) { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("piglinBrain"); + //if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // Purpur - only use brain if no rider this.getBrain().tick(level, this); profilerFiller.pop(); PiglinAi.updateActivity(this); diff --git a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java index 0964b138e87357b7601ddfe937a2b9132afd5478..97241682311797faa93927e0477a7646ce53b2c8 100644 --- a/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +++ b/net/minecraft/world/entity/monster/piglin/PiglinBrute.java @@ -65,6 +65,23 @@ public class PiglinBrute extends AbstractPiglin { this.xpReward = 20; } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.piglinBruteRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.piglinBruteRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.piglinBruteControllable; + } + // Purpur end - Ridables + public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes() .add(Attributes.MAX_HEALTH, 50.0) @@ -117,6 +134,7 @@ public class PiglinBrute extends AbstractPiglin { protected void customServerAiStep(ServerLevel level) { ProfilerFiller profilerFiller = Profiler.get(); profilerFiller.push("piglinBruteBrain"); + if (getRider() == null || this.isControllable()) // Purpur - only use brain if no rider this.getBrain().tick(level, this); profilerFiller.pop(); PiglinBruteAi.updateActivity(this); diff --git a/net/minecraft/world/entity/monster/warden/Warden.java b/net/minecraft/world/entity/monster/warden/Warden.java index 9f476e587d7df797129e49738f101cccca7e10b7..f968e5c99bdb23b268bc34ea1ba5d54ae9ad0ff9 100644 --- a/net/minecraft/world/entity/monster/warden/Warden.java +++ b/net/minecraft/world/entity/monster/warden/Warden.java @@ -129,8 +129,32 @@ public class Warden extends Monster implements VibrationSystem { this.setPathfindingMalus(PathType.LAVA, 8.0F); this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); + this.moveControl = new org.purpurmc.purpur.controller.MoveControllerWASD(this, 0.5F); // Purpur - Ridables } + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.wardenRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.wardenRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.wardenControllable; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + this.targetSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); // Purpur - Ridables + } + // Purpur end - Ridables + @Override public Packet getAddEntityPacket(ServerEntity entity) { return new ClientboundAddEntityPacket(this, entity, this.hasPose(Pose.EMERGING) ? 1 : 0); @@ -394,6 +418,7 @@ public class Warden extends Monster implements VibrationSystem { @Contract("null->false") public boolean canTargetEntity(@Nullable Entity entity) { + if (getRider() != null && isControllable()) return false; // Purpur - Ridables return entity instanceof LivingEntity livingEntity && this.level() == entity.level() && EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity) diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java index 7eb291323dfc71189ac4a160d3cb43506957aa9e..a7424ad414b72d2adaf0863bf1055f3eff5e2989 100644 --- a/net/minecraft/world/entity/npc/Villager.java +++ b/net/minecraft/world/entity/npc/Villager.java @@ -246,6 +246,28 @@ public class Villager extends AbstractVillager implements ReputationEventHandler } // Purpur end - Lobotomize stuck villagers + // Purpur start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.villagerRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.villagerRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.villagerControllable; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new org.purpurmc.purpur.entity.ai.HasRider(this)); + } + // Purpur end - Ridables + @Override public Brain getBrain() { return (Brain)super.getBrain(); @@ -355,7 +377,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler } // Purpur end - Lobotomize stuck villagers // Pufferfish start - if (!inactive /*&& this.behaviorTick++ % this.activatedPriority == 0*/) { + if (!inactive && (getRider() == null || !this.isControllable()) /*&& this.behaviorTick++ % this.activatedPriority == 0*/) { // Purpur - Ridables this.getBrain().tick(level, this); // Paper - EAR 2 } else if (this.isLobotomized && shouldRestock()) restock(); // Purpur - Lobotomize stuck villagers @@ -415,7 +437,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler return super.mobInteract(player, hand); } else if (this.isBaby()) { this.setUnhappy(); - return InteractionResult.SUCCESS; + return tryRide(player, hand, InteractionResult.SUCCESS); // Purpur - Ridables } else { if (!this.level().isClientSide) { boolean isEmpty = this.getOffers().isEmpty(); @@ -428,9 +450,11 @@ public class Villager extends AbstractVillager implements ReputationEventHandler } if (isEmpty) { - return InteractionResult.CONSUME; + return tryRide(player, hand, InteractionResult.CONSUME); // Purpur - Ridables } + if (level().purpurConfig.villagerRidable && itemInHand.isEmpty()) return tryRide(player, hand); // Purpur - Ridables + if (this.level().purpurConfig.villagerAllowTrading) // Purpur - Add config for villager trading this.startTrading(player); } diff --git a/net/minecraft/world/entity/npc/WanderingTrader.java b/net/minecraft/world/entity/npc/WanderingTrader.java index fab309dc34eb88f2b9c844078f167885121675c1..0f8ec3abead11c46205cd21290c65ec2b859efdc 100644 --- a/net/minecraft/world/entity/npc/WanderingTrader.java +++ b/net/minecraft/world/entity/npc/WanderingTrader.java @@ -76,6 +76,23 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill } // Purpur end - Allow leashing villagers + // Purpur - start - Ridables + @Override + public boolean isRidable() { + return level().purpurConfig.wanderingTraderRidable; + } + + @Override + public boolean dismountsUnderwater() { + return level().purpurConfig.useDismountsUnderwaterTag ? super.dismountsUnderwater() : !level().purpurConfig.wanderingTraderRidableInWater; + } + + @Override + public boolean isControllable() { + return level().purpurConfig.wanderingTraderControllable; + } + // Purpur end - Ridables + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); @@ -137,8 +154,9 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill if (!this.level().isClientSide) { if (this.getOffers().isEmpty()) { - return InteractionResult.CONSUME; + return tryRide(player, hand, InteractionResult.CONSUME); // Purpur - Ridables } + if (level().purpurConfig.wanderingTraderRidable && itemInHand.isEmpty()) return tryRide(player, hand); // Purpur - Ridables if (this.level().purpurConfig.wanderingTraderAllowTrading) { // Purpur - Add config for villager trading this.setTradingPlayer(player); diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java index 7ce6d81b1b1dff25e8986d2c7a0c90afd2855f42..d0321875d2a2b612b438cc7973a7e9f172a61778 100644 --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java @@ -220,6 +220,19 @@ public abstract class Player extends LivingEntity { } // CraftBukkit end + // Purpur start - Ridables + public abstract void resetLastActionTime(); + + @Override + public boolean processClick(InteractionHand hand) { + Entity vehicle = getRootVehicle(); + if (vehicle != null && vehicle.getRider() == this) { + return vehicle.onClick(hand); + } + return false; + } + // Purpur end - Ridables + public Player(Level level, BlockPos pos, float yRot, GameProfile gameProfile) { super(EntityType.PLAYER, level); this.setUUID(gameProfile.getId()); diff --git a/net/minecraft/world/entity/projectile/LlamaSpit.java b/net/minecraft/world/entity/projectile/LlamaSpit.java index 4880db97135d54fa72f64c108b2bd4ded096438b..bc102b049047d6e2a1d29e10f92cdf5ae2c140bd 100644 --- a/net/minecraft/world/entity/projectile/LlamaSpit.java +++ b/net/minecraft/world/entity/projectile/LlamaSpit.java @@ -33,6 +33,12 @@ public class LlamaSpit extends Projectile { ); } + // Purpur start - Ridables + public void projectileTick() { + super.tick(); + } + // Purpur end - Ridables + @Override protected double getDefaultGravity() { return 0.06; diff --git a/net/minecraft/world/entity/projectile/WitherSkull.java b/net/minecraft/world/entity/projectile/WitherSkull.java index c7a76d45b5749cf054607808610eb710493f80ea..9af37bd40649f602d700fc7b683c646ae9189eb9 100644 --- a/net/minecraft/world/entity/projectile/WitherSkull.java +++ b/net/minecraft/world/entity/projectile/WitherSkull.java @@ -110,6 +110,14 @@ public class WitherSkull extends AbstractHurtingProjectile { } // Purpur end - Add canSaveToDisk to Entity + // Purpur start - Ridables + @Override + public boolean canHitEntity(Entity target) { + // do not hit rider + return target != this.getRider() && super.canHitEntity(target); + } + // Purpur end - Ridables + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { builder.define(DATA_DANGEROUS, false);