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/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java index b01d7da333bac7820e42b6f645634a15ef88ae4f..30a4b80eacf76ad7f0a48b79bcf01b752c0af48a 100644 --- a/src/main/java/net/minecraft/core/BlockPos.java +++ b/src/main/java/net/minecraft/core/BlockPos.java @@ -41,6 +41,12 @@ public class BlockPos extends Vec3i { private static final int X_OFFSET = 38; // Paper end + // Purpur start + public BlockPos(net.minecraft.world.entity.Entity entity) { + super(entity.getX(), entity.getY(), entity.getZ()); + } + // Purpur end + public BlockPos(int x, int y, int z) { super(x, y, z); } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index be1bc7fda4104d61f91c2815c6ba3c612a019bed..2ede76a55c72840d915ed282609b1ca14f549929 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1592,6 +1592,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper + worldserver.hasRidableMoveEvent = net.pl3x.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper this.profiler.push(() -> { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index f9ed48f5bbde84fd1804e482f2777b516cc3a1ef..29b841462037fa97f72971c490b617d18be53160 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -201,6 +201,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public final UUID uuid; public boolean hasPhysicsEvent = true; // Paper public boolean hasEntityMoveEvent = false; // Paper + public boolean hasRidableMoveEvent = false; // Purpur public static Throwable getAddToWorldStackTrace(Entity entity) { return new Throwable(entity + " Added to world at " + new java.util.Date()); } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 9d759979372d83ddf203a8b6d52202d461136ecd..ac44d1c07ba6922d25592d750af326d34b625cec 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -664,6 +664,15 @@ public class ServerPlayer extends Player { } this.advancements.flushDirty(this); + + // Purpur start + 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 } public void doTick() { @@ -2410,4 +2419,6 @@ public class ServerPlayer extends Player { return (CraftPlayer) super.getBukkitEntity(); } // CraftBukkit end + + } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index b5b1aab39f881c334aa7f5f0d713f78f7265f41b..757c9f9800de18ca8ece3583222c7d3a765f3bde 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -2412,6 +2412,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event); + player.processClick(enumhand); // Purpur + // Fish bucket - SPIGOT-4048 if ((entity instanceof AbstractFish && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) { ServerGamePacketListenerImpl.this.send(new ClientboundAddMobPacket((AbstractFish) entity)); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 28d7e18c9b53b7563b9c4af9afde4e1261d454e4..08efd9b12786077e4f6ae1bfffb912d317f4f418 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -230,7 +230,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n public float yRotO; public float xRotO; private AABB bb; - protected boolean onGround; + public boolean onGround; // Purpur - protected -> public public boolean horizontalCollision; public boolean verticalCollision; public boolean hurtMarked; @@ -291,7 +291,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n private final Set tags; private final double[] pistonDeltas; private long pistonDeltasGameTime; - private EntityDimensions dimensions; + protected EntityDimensions dimensions; // Purpur - private -> protected private float eyeHeight; public boolean isInPowderSnow; public boolean wasInPowderSnow; @@ -2601,6 +2601,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n this.passengers = ImmutableList.copyOf(list); } + // Purpur start + if (isRidable() && this.passengers.get(0) == entity && entity instanceof Player player) { + onMount(player); + this.rider = player; + } + // Purpur end } return true; // CraftBukkit } @@ -2641,6 +2647,14 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n return false; } // Spigot end + + // Purpur start + if (this.rider != null && this.passengers.get(0) == this.rider) { + onDismount(this.rider); + this.rider = null; + } + // Purpur end + if (this.passengers.size() == 1 && this.passengers.get(0) == entity) { this.passengers = ImmutableList.of(); } else { @@ -4213,4 +4227,41 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n return ((ServerChunkCache) level.getChunkSource()).isPositionTicking(this); } // Paper end + + // Purpur start + @Nullable + private Player rider = null; + + @Nullable + public Player getRider() { + return rider; + } + + public boolean isRidable() { + return false; + } + + public void onMount(Player rider) { + if (this instanceof Mob) { + ((Mob) this).setGoalTarget(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 } diff --git a/src/main/java/net/minecraft/world/entity/GlowSquid.java b/src/main/java/net/minecraft/world/entity/GlowSquid.java index d28cecd9bea7c82fa675d333810e2e63a91c615e..8f8bc29d847801938e251904b8334b4b31bd21c5 100644 --- a/src/main/java/net/minecraft/world/entity/GlowSquid.java +++ b/src/main/java/net/minecraft/world/entity/GlowSquid.java @@ -19,6 +19,18 @@ public class GlowSquid extends Squid { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.glowSquidRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + // Purpur end + @Override protected ParticleOptions getInkParticle() { return ParticleTypes.GLOW_SQUID_INK; diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index 24c629d5f26bc5aadebcf39a63930b3448525242..28139fd78e7dfb703e941a46bd18e0236d58fe22 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -220,9 +220,9 @@ public abstract class LivingEntity extends Entity { protected int deathScore; 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; @@ -2570,7 +2570,7 @@ public abstract class LivingEntity extends Entity { return this.hasEffect(MobEffects.JUMP) ? (double) (0.1F * (float) (this.getEffect(MobEffects.JUMP).getAmplifier() + 1)) : 0.0D; } - protected void jumpFromGround() { + public void jumpFromGround() { // Purpur - protected -> public double d0 = (double) this.getJumpPower() + this.getJumpBoostPower(); Vec3 vec3d = this.getDeltaMovement(); @@ -3224,8 +3224,10 @@ public abstract class LivingEntity extends Entity { this.pushEntities(); this.level.getProfiler().pop(); // Paper start - if (((ServerLevel) this.level).hasEntityMoveEvent) { - if (this.xo != getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { + // Purpur start + if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { + if (((ServerLevel) level).hasEntityMoveEvent) { + // Purpur end 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()); @@ -3235,6 +3237,21 @@ public abstract class LivingEntity extends Entity { absMoveTo(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch()); } } + // Purpur start + 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()); + net.pl3x.purpur.event.entity.RidableMoveEvent event = new net.pl3x.purpur.event.entity.RidableMoveEvent((org.bukkit.entity.Mob) getBukkitLivingEntity(), (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 } // Paper end if (!this.level.isClientSide && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java index 5eb93bacd303ebed0a702221f8ae31631d42f45d..c8dee3a9a5cafc9f0fd88becd843823836cd19b3 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -140,6 +140,8 @@ public abstract class Mob extends LivingEntity { this.targetSelector = new GoalSelector(world.getProfilerSupplier()); this.lookControl = new LookControl(this); this.moveControl = new MoveControl(this); + this.lookControl = new net.pl3x.purpur.controller.LookControllerWASD(this); // Purpur + this.moveControl = new net.pl3x.purpur.controller.MoveControllerWASD(this); // Purpur this.jumpControl = new JumpControl(this); this.bodyRotationControl = this.createBodyControl(); this.navigation = this.createNavigation(world); @@ -1283,7 +1285,7 @@ public abstract class Mob extends LivingEntity { protected void onOffspringSpawnedFromEgg(Player player, Mob child) {} protected InteractionResult mobInteract(Player player, InteractionHand hand) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } public boolean isWithinRestriction() { @@ -1644,4 +1646,52 @@ public abstract class Mob extends LivingEntity { return itemmonsteregg == null ? null : new ItemStack(itemmonsteregg); } + + // Purpur start + public double getMaxY() { + return level.getHeight(); + } + + public InteractionResult tryRide(Player player, InteractionHand hand) { + if (!isRidable()) { + return InteractionResult.PASS; + } + 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." + getType().id)) { + player.sendMessage(net.pl3x.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 } diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java b/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java index b1e00093ad2b42a1e0a399d261539e06f2a505b9..53d43442ddc711d39ede5f33c3754e0a2097c2bc 100644 --- a/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java +++ b/src/main/java/net/minecraft/world/entity/ai/attributes/DefaultAttributes.java @@ -74,7 +74,86 @@ import org.apache.logging.log4j.Logger; public class DefaultAttributes { private static final Logger LOGGER = LogManager.getLogger(); - private static final Map, AttributeSupplier> SUPPLIERS = ImmutableMap., AttributeSupplier>builder().put(EntityType.ARMOR_STAND, LivingEntity.createLivingAttributes().build()).put(EntityType.AXOLOTL, Axolotl.createAttributes().build()).put(EntityType.BAT, Bat.createAttributes().build()).put(EntityType.BEE, Bee.createAttributes().build()).put(EntityType.BLAZE, Blaze.createAttributes().build()).put(EntityType.CAT, Cat.createAttributes().build()).put(EntityType.CAVE_SPIDER, CaveSpider.createCaveSpider().build()).put(EntityType.CHICKEN, Chicken.createAttributes().build()).put(EntityType.COD, AbstractFish.createAttributes().build()).put(EntityType.COW, Cow.createAttributes().build()).put(EntityType.CREEPER, Creeper.createAttributes().build()).put(EntityType.DOLPHIN, Dolphin.createAttributes().build()).put(EntityType.DONKEY, AbstractChestedHorse.createBaseChestedHorseAttributes().build()).put(EntityType.DROWNED, Zombie.createAttributes().build()).put(EntityType.ELDER_GUARDIAN, ElderGuardian.createAttributes().build()).put(EntityType.ENDERMAN, EnderMan.createAttributes().build()).put(EntityType.ENDERMITE, Endermite.createAttributes().build()).put(EntityType.ENDER_DRAGON, EnderDragon.createAttributes().build()).put(EntityType.EVOKER, Evoker.createAttributes().build()).put(EntityType.FOX, Fox.createAttributes().build()).put(EntityType.GHAST, Ghast.createAttributes().build()).put(EntityType.GIANT, Giant.createAttributes().build()).put(EntityType.GLOW_SQUID, GlowSquid.createAttributes().build()).put(EntityType.GOAT, Goat.createAttributes().build()).put(EntityType.GUARDIAN, Guardian.createAttributes().build()).put(EntityType.HOGLIN, Hoglin.createAttributes().build()).put(EntityType.HORSE, AbstractHorse.createBaseHorseAttributes().build()).put(EntityType.HUSK, Zombie.createAttributes().build()).put(EntityType.ILLUSIONER, Illusioner.createAttributes().build()).put(EntityType.IRON_GOLEM, IronGolem.createAttributes().build()).put(EntityType.LLAMA, Llama.createAttributes().build()).put(EntityType.MAGMA_CUBE, MagmaCube.createAttributes().build()).put(EntityType.MOOSHROOM, Cow.createAttributes().build()).put(EntityType.MULE, AbstractChestedHorse.createBaseChestedHorseAttributes().build()).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.PIG, Pig.createAttributes().build()).put(EntityType.PIGLIN, Piglin.createAttributes().build()).put(EntityType.PIGLIN_BRUTE, PiglinBrute.createAttributes().build()).put(EntityType.PILLAGER, Pillager.createAttributes().build()).put(EntityType.PLAYER, Player.createAttributes().build()).put(EntityType.POLAR_BEAR, PolarBear.createAttributes().build()).put(EntityType.PUFFERFISH, AbstractFish.createAttributes().build()).put(EntityType.RABBIT, Rabbit.createAttributes().build()).put(EntityType.RAVAGER, Ravager.createAttributes().build()).put(EntityType.SALMON, AbstractFish.createAttributes().build()).put(EntityType.SHEEP, Sheep.createAttributes().build()).put(EntityType.SHULKER, Shulker.createAttributes().build()).put(EntityType.SILVERFISH, Silverfish.createAttributes().build()).put(EntityType.SKELETON, AbstractSkeleton.createAttributes().build()).put(EntityType.SKELETON_HORSE, SkeletonHorse.createAttributes().build()).put(EntityType.SLIME, Monster.createMonsterAttributes().build()).put(EntityType.SNOW_GOLEM, SnowGolem.createAttributes().build()).put(EntityType.SPIDER, Spider.createAttributes().build()).put(EntityType.SQUID, Squid.createAttributes().build()).put(EntityType.STRAY, AbstractSkeleton.createAttributes().build()).put(EntityType.STRIDER, Strider.createAttributes().build()).put(EntityType.TRADER_LLAMA, Llama.createAttributes().build()).put(EntityType.TROPICAL_FISH, AbstractFish.createAttributes().build()).put(EntityType.TURTLE, Turtle.createAttributes().build()).put(EntityType.VEX, Vex.createAttributes().build()).put(EntityType.VILLAGER, Villager.createAttributes().build()).put(EntityType.VINDICATOR, Vindicator.createAttributes().build()).put(EntityType.WANDERING_TRADER, Mob.createMobAttributes().build()).put(EntityType.WITCH, Witch.createAttributes().build()).put(EntityType.WITHER, WitherBoss.createAttributes().build()).put(EntityType.WITHER_SKELETON, AbstractSkeleton.createAttributes().build()).put(EntityType.WOLF, Wolf.createAttributes().build()).put(EntityType.ZOGLIN, Zoglin.createAttributes().build()).put(EntityType.ZOMBIE, Zombie.createAttributes().build()).put(EntityType.ZOMBIE_HORSE, ZombieHorse.createAttributes().build()).put(EntityType.ZOMBIE_VILLAGER, Zombie.createAttributes().build()).put(EntityType.ZOMBIFIED_PIGLIN, ZombifiedPiglin.createAttributes().build()).build(); + + // Purpur start + private static final Map, AttributeSupplier> SUPPLIERS = ImmutableMap., AttributeSupplier>builder() + .put(EntityType.ARMOR_STAND, LivingEntity.createLivingAttributes().build()) + .put(EntityType.AXOLOTL, Axolotl.createAttributes().build()) + .put(EntityType.BAT, Bat.createAttributes().build()) + .put(EntityType.BEE, Bee.createAttributes().build()) + .put(EntityType.BLAZE, Blaze.createAttributes().build()) + .put(EntityType.CAT, Cat.createAttributes().build()) + .put(EntityType.CAVE_SPIDER, CaveSpider.createCaveSpider().build()) + .put(EntityType.CHICKEN, Chicken.createAttributes().build()) + .put(EntityType.COD, AbstractFish.createAttributes().build()) + .put(EntityType.COW, Cow.createAttributes().build()) + .put(EntityType.CREEPER, Creeper.createAttributes().build()) + .put(EntityType.DOLPHIN, Dolphin.createAttributes().build()) + .put(EntityType.DONKEY, AbstractChestedHorse.createBaseChestedHorseAttributes().build()) + .put(EntityType.DROWNED, Zombie.createAttributes().build()) + .put(EntityType.ELDER_GUARDIAN, ElderGuardian.createAttributes().build()) + .put(EntityType.ENDERMAN, EnderMan.createAttributes().build()) + .put(EntityType.ENDERMITE, Endermite.createAttributes().build()) + .put(EntityType.ENDER_DRAGON, EnderDragon.createAttributes().build()) + .put(EntityType.EVOKER, Evoker.createAttributes().build()) + .put(EntityType.FOX, Fox.createAttributes().build()) + .put(EntityType.GHAST, Ghast.createAttributes().build()) + .put(EntityType.GIANT, Giant.createAttributes().build()) + .put(EntityType.GLOW_SQUID, GlowSquid.createAttributes().build()) + .put(EntityType.GOAT, Goat.createAttributes().build()) + .put(EntityType.GUARDIAN, Guardian.createAttributes().build()) + .put(EntityType.HOGLIN, Hoglin.createAttributes().build()) + .put(EntityType.HORSE, AbstractHorse.createBaseHorseAttributes().build()) + .put(EntityType.HUSK, Zombie.createAttributes().build()) + .put(EntityType.ILLUSIONER, Illusioner.createAttributes().build()) + .put(EntityType.IRON_GOLEM, IronGolem.createAttributes().build()) + .put(EntityType.LLAMA, Llama.createAttributes().build()) + .put(EntityType.MAGMA_CUBE, MagmaCube.createAttributes().build()) + .put(EntityType.MOOSHROOM, Cow.createAttributes().build()) + .put(EntityType.MULE, AbstractChestedHorse.createBaseChestedHorseAttributes().build()) + .put(EntityType.OCELOT, Ocelot.createAttributes().build()) + .put(EntityType.PANDA, Panda.createAttributes().build()) + .put(EntityType.PARROT, Parrot.createAttributes().build()) + .put(EntityType.PHANTOM, net.minecraft.world.entity.monster.Phantom.createAttributes().build()) // Purpur + .put(EntityType.PIG, Pig.createAttributes().build()) + .put(EntityType.PIGLIN, Piglin.createAttributes().build()) + .put(EntityType.PIGLIN_BRUTE, PiglinBrute.createAttributes().build()) + .put(EntityType.PILLAGER, Pillager.createAttributes().build()) + .put(EntityType.PLAYER, Player.createAttributes().build()) + .put(EntityType.POLAR_BEAR, PolarBear.createAttributes().build()) + .put(EntityType.PUFFERFISH, AbstractFish.createAttributes().build()) + .put(EntityType.RABBIT, Rabbit.createAttributes().build()) + .put(EntityType.RAVAGER, Ravager.createAttributes().build()) + .put(EntityType.SALMON, AbstractFish.createAttributes().build()) + .put(EntityType.SHEEP, Sheep.createAttributes().build()) + .put(EntityType.SHULKER, Shulker.createAttributes().build()) + .put(EntityType.SILVERFISH, Silverfish.createAttributes().build()) + .put(EntityType.SKELETON, AbstractSkeleton.createAttributes().build()) + .put(EntityType.SKELETON_HORSE, SkeletonHorse.createAttributes().build()) + .put(EntityType.SLIME, Monster.createMonsterAttributes().build()) + .put(EntityType.SNOW_GOLEM, SnowGolem.createAttributes().build()) + .put(EntityType.SPIDER, Spider.createAttributes().build()) + .put(EntityType.SQUID, Squid.createAttributes().build()) + .put(EntityType.STRAY, AbstractSkeleton.createAttributes().build()) + .put(EntityType.STRIDER, Strider.createAttributes().build()) + .put(EntityType.TRADER_LLAMA, Llama.createAttributes().build()) + .put(EntityType.TROPICAL_FISH, AbstractFish.createAttributes().build()) + .put(EntityType.TURTLE, Turtle.createAttributes().build()) + .put(EntityType.VEX, Vex.createAttributes().build()) + .put(EntityType.VILLAGER, Villager.createAttributes().build()) + .put(EntityType.VINDICATOR, Vindicator.createAttributes().build()) + .put(EntityType.WANDERING_TRADER, Mob.createMobAttributes().build()) + .put(EntityType.WITCH, Witch.createAttributes().build()) + .put(EntityType.WITHER, WitherBoss.createAttributes().build()) + .put(EntityType.WITHER_SKELETON, AbstractSkeleton.createAttributes().build()) + .put(EntityType.WOLF, Wolf.createAttributes().build()) + .put(EntityType.ZOGLIN, Zoglin.createAttributes().build()) + .put(EntityType.ZOMBIE, Zombie.createAttributes().build()) + .put(EntityType.ZOMBIE_HORSE, ZombieHorse.createAttributes().build()) + .put(EntityType.ZOMBIE_VILLAGER, Zombie.createAttributes().build()) + .put(EntityType.ZOMBIFIED_PIGLIN, ZombifiedPiglin.createAttributes().build()) + .build(); + // Purpur end public static AttributeSupplier getSupplier(EntityType type) { return SUPPLIERS.get(type); diff --git a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java index fcdebde11f622d0e35d922286b34c8666f9f6861..43e5efd136937fe215db0e88907f3176e06197d1 100644 --- a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java +++ b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java @@ -29,6 +29,20 @@ public class MoveControl implements Control { this.mob = entity; } + // Purpur start + 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 + public boolean hasWanted() { return this.operation == MoveControl.Operation.MOVE_TO; } diff --git a/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java b/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java index ffc87d14cdc7edc22a7e2ac642d0e37037c52487..f2957d7f4c377a67ee486a9d0f7ae173add20aed 100644 --- a/src/main/java/net/minecraft/world/entity/ai/control/SmoothSwimmingLookControl.java +++ b/src/main/java/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 net.pl3x.purpur.controller.LookControllerWASD { // Purpur 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 if (this.hasWanted) { this.hasWanted = false; this.getYRotD().ifPresent((float_) -> { @@ -32,9 +32,9 @@ public class SmoothSwimmingLookControl extends LookControl { } float f = Mth.wrapDegrees(this.mob.yHeadRot - this.mob.yBodyRot); - if (f < (float)(-this.maxYRotFromCenter)) { + if (f < (float) (-this.maxYRotFromCenter)) { this.mob.yBodyRot -= 4.0F; - } else if (f > (float)this.maxYRotFromCenter) { + } else if (f > (float) this.maxYRotFromCenter) { this.mob.yBodyRot += 4.0F; } diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java index 153194d937d210e2e4fd8864e4a3c000f85d7e2e..5708a1f88f3e62856a5ec15dc71d8a169353170d 100644 --- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java +++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java @@ -20,6 +20,7 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.MoverType; import net.minecraft.world.entity.Pose; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; @@ -42,9 +43,48 @@ public class Bat extends AmbientCreature { public Bat(EntityType type, Level world) { super(type, world); + this.moveControl = new net.pl3x.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.075F); // Purpur this.setResting(true); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.batRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.batRidableInWater; + } + + @Override + public double getMaxY() { + return level.purpurConfig.batMaxY; + } + + @Override + public void onMount(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 && !onGround) { + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; + setSpeed(speed); + Vec3 mot = getDeltaMovement(); + move(MoverType.SELF, mot.multiply(speed, 0.25, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } + // Purpur end + @Override public boolean isFlapping() { return !this.isResting() && this.tickCount % Bat.TICKS_PER_FLAP == 0; @@ -94,7 +134,7 @@ public class Bat extends AmbientCreature { protected void pushEntities() {} public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D); + return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur } public boolean isResting() { @@ -126,6 +166,14 @@ public class Bat extends AmbientCreature { @Override protected void customServerAiStep() { + // Purpur start + if (getRider() != null) { + Vec3 mot = getDeltaMovement(); + setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z()); + return; + } + // Purpur end + super.customServerAiStep(); BlockPos blockposition = this.blockPosition(); BlockPos blockposition1 = blockposition.above(); diff --git a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java index fc0cd86397b12e42756273a0317164d79ac51937..4243c4d3479210e392a1246337a3daabee5629d7 100644 --- a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java +++ b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java @@ -108,12 +108,9 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { @Override protected void registerGoals() { super.registerGoals(); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(0, new PanicGoal(this, 1.25D)); - GoalSelector pathfindergoalselector = this.goalSelector; - Predicate predicate = EntitySelector.NO_SPECTATORS; - - Objects.requireNonNull(predicate); - pathfindergoalselector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6D, 1.4D, predicate::test)); + this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 1.6D, 1.4D, EntitySelector.NO_SPECTATORS::test)); // Purpur - decompile fix this.goalSelector.addGoal(4, new AbstractFish.FishSwimGoal(this)); } @@ -125,7 +122,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { @Override public void travel(Vec3 movementInput) { if (this.isEffectiveAi() && this.isInWater()) { - this.moveRelative(0.01F, movementInput); + this.moveRelative(getRider() != null ? getSpeed() : 0.01F, movementInput); // Purpur this.move(MoverType.SELF, this.getDeltaMovement()); this.setDeltaMovement(this.getDeltaMovement().scale(0.9D)); if (this.getTarget() == null) { @@ -183,7 +180,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { @Override protected void playStepSound(BlockPos pos, BlockState state) {} - private static class FishMoveControl extends MoveControl { + private static class FishMoveControl extends net.pl3x.purpur.controller.WaterMoveControllerWASD { // Purpur private final AbstractFish fish; @@ -192,14 +189,22 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable { this.fish = owner; } + // Purpur start + @Override + public void purpurTick(Player rider) { + super.purpurTick(rider); + fish.setDeltaMovement(fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); + } + // Purpur end + @Override - public void tick() { + public void vanillaTick() { // Purpur if (this.fish.isEyeInFluid((Tag) FluidTags.WATER)) { this.fish.setDeltaMovement(this.fish.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); } if (this.operation == MoveControl.Operation.MOVE_TO && !this.fish.getNavigation().isDone()) { - float f = (float) (this.speedModifier * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); + float f = (float) (this.getSpeedModifier() * this.fish.getAttributeValue(Attributes.MOVEMENT_SPEED)); // Purpur this.fish.setSpeed(Mth.lerp(0.125F, this.fish.getSpeed(), f)); double d0 = this.wantedX - this.fish.getX(); diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java index 2639f64f1a50faddc0284fb26b73b563b3e9eba9..8632a4047776723088b9b9fa27c6e8093fb17801 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Bee.java +++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java @@ -44,6 +44,7 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MobType; +import net.minecraft.world.entity.MoverType; import net.minecraft.world.entity.NeutralMob; import net.minecraft.world.entity.PathfinderMob; import net.minecraft.world.entity.Pose; @@ -143,6 +144,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { public Bee(EntityType type, Level world) { super(type, world); this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60); + final net.pl3x.purpur.controller.FlyingMoveControllerWASD flyingController = new net.pl3x.purpur.controller.FlyingMoveControllerWASD(this, 0.25F, false); // Purpur // Paper start - apply gravity to bees when they get stuck in the void, fixes MC-167279 class BeeFlyingMoveControl extends FlyingMoveControl { public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) { @@ -151,11 +153,24 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @Override public void tick() { + // Purpur start + if (mob.getRider() != null) { + flyingController.purpurTick(mob.getRider()); + return; + } + // Purpur end if (this.mob.getY() <= Bee.this.level.getMinBuildHeight()) { this.mob.setNoGravity(false); } super.tick(); } + + // Purpur start + @Override + public boolean hasWanted() { + return mob.getRider() != null || super.hasWanted(); + } + // Purpur end } this.moveControl = new BeeFlyingMoveControl(this, 20, true); // Paper end @@ -167,6 +182,35 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { this.setPathfindingMalus(BlockPathTypes.FENCE, -1.0F); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.beeRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.beeRidableInWater; + } + + @Override + public double getMaxY() { + return level.purpurConfig.beeMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && !onGround) { + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; + setSpeed(speed); + Vec3 mot = getDeltaMovement(); + move(MoverType.SELF, mot.multiply(speed, speed, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } + // Purpur end + @Override protected void defineSynchedData() { super.defineSynchedData(); @@ -181,6 +225,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(0, new Bee.BeeAttackGoal(this, 1.399999976158142D, true)); this.goalSelector.addGoal(1, new Bee.BeeEnterHiveGoal()); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); @@ -196,6 +241,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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur 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)); @@ -871,16 +917,16 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { } } - private class BeeLookControl extends LookControl { + private class BeeLookControl extends net.pl3x.purpur.controller.LookControllerWASD { // Purpur BeeLookControl(Mob entity) { super(entity); } @Override - public void tick() { + public void vanillaTick() { // Purpur if (!Bee.this.isAngry()) { - super.tick(); + super.vanillaTick(); // Purpur } } diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java index 15773d61deb357917e2478f0731f0b470669b8f0..14822b20971b63290a7022f8efe65693c41664d2 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Cat.java +++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java @@ -121,6 +121,26 @@ public class Cat extends TamableAnimal { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.catRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.catRidableInWater; + } + + @Override + public void onMount(Player rider) { + super.onMount(rider); + setInSittingPose(false); + setLying(false); + setRelaxStateOne(false); + } + // Purpur end + public ResourceLocation getResourceLocation() { return (ResourceLocation) Cat.TEXTURE_BY_TYPE.getOrDefault(this.getCatType(), (ResourceLocation) Cat.TEXTURE_BY_TYPE.get(0)); } @@ -129,6 +149,7 @@ public class Cat extends TamableAnimal { protected void registerGoals() { this.temptGoal = new Cat.CatTemptGoal(this, 0.6D, Cat.TEMPT_INGREDIENT, true); this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new SitWhenOrderedToGoal(this)); this.goalSelector.addGoal(2, new Cat.CatRelaxOnOwnerGoal(this)); this.goalSelector.addGoal(3, this.temptGoal); @@ -140,6 +161,7 @@ public class Cat extends TamableAnimal { this.goalSelector.addGoal(10, new BreedGoal(this, 0.8D)); this.goalSelector.addGoal(11, new WaterAvoidingRandomStrollGoal(this, 0.8D, 1.0000001E-5F)); this.goalSelector.addGoal(12, new LookAtPlayerGoal(this, Player.class, 10.0F)); + this.targetSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Rabbit.class, false, (Predicate) null)); this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR)); } @@ -394,6 +416,7 @@ public class Cat extends TamableAnimal { @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { + if (getRider() != null) return InteractionResult.PASS; // Purpur ItemStack itemstack = player.getItemInHand(hand); Item item = itemstack.getItem(); diff --git a/src/main/java/net/minecraft/world/entity/animal/Chicken.java b/src/main/java/net/minecraft/world/entity/animal/Chicken.java index cece07e000a4355e88aef7848fd264191521484e..7a5119e007d69adc9a77fbd167a8d19a9c71c6ff 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Chicken.java +++ b/src/main/java/net/minecraft/world/entity/animal/Chicken.java @@ -52,9 +52,22 @@ public class Chicken extends Animal { this.setPathfindingMalus(BlockPathTypes.WATER, 0.0F); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.chickenRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.chickenRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D)); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, Chicken.FOOD_ITEMS, false)); diff --git a/src/main/java/net/minecraft/world/entity/animal/Cod.java b/src/main/java/net/minecraft/world/entity/animal/Cod.java index ec9c235f00cc1b992340dfe0a0b79803361caac5..5275e4ed3d552d1e164ef580caf6c247ec5fd8c2 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Cod.java +++ b/src/main/java/net/minecraft/world/entity/animal/Cod.java @@ -13,6 +13,18 @@ public class Cod extends AbstractSchoolingFish { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.codRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + // Purpur end + @Override public ItemStack getBucketItemStack() { return new ItemStack(Items.COD_BUCKET); diff --git a/src/main/java/net/minecraft/world/entity/animal/Cow.java b/src/main/java/net/minecraft/world/entity/animal/Cow.java index c9dcbc2dcb2736d0f448496c67121db29b7d4deb..1cb5342d63011605b567a4fe16d07de831f04216 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Cow.java +++ b/src/main/java/net/minecraft/world/entity/animal/Cow.java @@ -40,9 +40,22 @@ public class Cow extends Animal { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.cowRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.cowRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new PanicGoal(this, 2.0D)); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, Ingredient.of(Items.WHEAT), false)); @@ -83,6 +96,7 @@ public class Cow extends Animal { @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { + if (getRider() != null) return InteractionResult.PASS; // Purpur ItemStack itemstack = player.getItemInHand(hand); if (itemstack.is(Items.BUCKET) && !this.isBaby()) { @@ -90,7 +104,7 @@ public class Cow extends Animal { org.bukkit.event.player.PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level, player, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, hand); // Paper - add enumHand if (event.isCancelled()) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } // CraftBukkit end diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java index f3093815066e6881a2bb638ae4643f69374450b3..2300abc4e80449e6b92992f6fb8cfe8e99dea351 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java +++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java @@ -84,14 +84,82 @@ public class Dolphin extends WaterAnimal { public static final Predicate ALLOWED_ITEMS = (entityitem) -> { return !entityitem.hasPickUpDelay() && entityitem.isAlive() && entityitem.isInWater(); }; + private int spitCooldown; // Purpur public Dolphin(EntityType type, Level world) { super(type, world); - this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); + // Purpur start + class DolphinMoveControl extends SmoothSwimmingMoveControl { + private final net.pl3x.purpur.controller.WaterMoveControllerWASD waterMoveControllerWASD; + private final Dolphin dolphin; + + public DolphinMoveControl(Dolphin dolphin, int pitchChange, int yawChange, float speedInWater, float speedInAir, boolean buoyant) { + super(dolphin, pitchChange, yawChange, speedInWater, speedInAir, buoyant); + this.dolphin = dolphin; + this.waterMoveControllerWASD = new net.pl3x.purpur.controller.WaterMoveControllerWASD(dolphin); + } + + @Override + public void tick() { + if (dolphin.getRider() != null) { + purpurTick(dolphin.getRider()); + } else { + super.tick(); + } + } + + public void purpurTick(Player rider) { + if (dolphin.getAirSupply() < 150) { + // if drowning override player WASD controls to find air + tick(); + } else { + waterMoveControllerWASD.purpurTick(rider); + dolphin.setDeltaMovement(dolphin.getDeltaMovement().add(0.0D, 0.005D, 0.0D)); + } + } + }; + this.moveControl = new DolphinMoveControl(this, 85, 10, 0.02F, 0.1F, true); + // Purpur end this.lookControl = new SmoothSwimmingLookControl(this, 10); this.setCanPickUpLoot(true); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.dolphinRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + + @Override + public boolean onSpacebar() { + if (spitCooldown == 0 && getRider() != null) { + spitCooldown = level.purpurConfig.dolphinSpitCooldown; + + org.bukkit.craftbukkit.entity.CraftPlayer player = (org.bukkit.craftbukkit.entity.CraftPlayer) getRider().getBukkitEntity(); + if (!player.hasPermission("allow.special.dolphin")) { + return false; + } + + org.bukkit.Location loc = player.getEyeLocation(); + loc.setPitch(loc.getPitch() - 10); + org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(10).add(loc.toVector()); + + net.pl3x.purpur.entity.DolphinSpit spit = new net.pl3x.purpur.entity.DolphinSpit(level, this); + spit.shoot(target.getX() - getX(), target.getY() - getY(), target.getZ() - getZ(), level.purpurConfig.dolphinSpitSpeed, 5.0F); + + level.addFreshEntity(spit); + playSound(SoundEvents.DOLPHIN_ATTACK, 1.0F, 1.0F + (random.nextFloat() - random.nextFloat()) * 0.2F); + return true; + } + return false; + } + // Purpur end + @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { @@ -166,6 +234,7 @@ public class Dolphin extends WaterAnimal { protected void registerGoals() { this.goalSelector.addGoal(0, new BreathAirGoal(this)); this.goalSelector.addGoal(0, new TryFindWaterGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new Dolphin.DolphinSwimToTreasureGoal(this)); this.goalSelector.addGoal(2, new Dolphin.DolphinSwimWithPlayerGoal(this, 4.0D)); this.goalSelector.addGoal(4, new RandomSwimmingGoal(this, 1.0D, 10)); @@ -176,6 +245,7 @@ public class Dolphin extends WaterAnimal { this.goalSelector.addGoal(8, new Dolphin.PlayWithItemsGoal()); this.goalSelector.addGoal(8, new FollowBoatGoal(this)); this.goalSelector.addGoal(9, new AvoidEntityGoal<>(this, Guardian.class, 8.0F, 1.0D, 1.0D)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Guardian.class})).setAlertOthers(new Class[0])); // CraftBukkit - decompile error } @@ -227,7 +297,7 @@ public class Dolphin extends WaterAnimal { @Override protected boolean canRide(Entity entity) { - return true; + return boardingCooldown <= 0; // Purpur - make dolphin honor ride cooldown like all other non-boss mobs; } @Override @@ -262,6 +332,11 @@ public class Dolphin extends WaterAnimal { @Override public void tick() { super.tick(); + // Purpur start + if (spitCooldown > 0) { + spitCooldown--; + } + // Purpur end if (this.isNoAi()) { this.setAirSupply(this.getMaxAirSupply()); } else { diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java index 21274d2c8c78d8454dbfc19076a52e54876bd78d..ee9dfc609cc9e4a94dca7803e51bb456c1e63389 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Fox.java +++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java @@ -138,6 +138,39 @@ public class Fox extends Animal { this.setCanPickUpLoot(true); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.foxRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.foxRidableInWater; + } + + @Override + public float getJumpPower() { + return getRider() != null ? 0.5F : super.getJumpPower(); + } + + @Override + public void onMount(Player rider) { + super.onMount(rider); + setCanPickUpLoot(false); + clearStates(); + setIsPouncing(false); + spitOutItem(getItemBySlot(EquipmentSlot.MAINHAND)); + setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); + } + + @Override + public void onDismount(Player rider) { + super.onDismount(rider); + setCanPickUpLoot(true); + } + // Purpur end + @Override protected void defineSynchedData() { super.defineSynchedData(); @@ -157,6 +190,7 @@ public class Fox extends Animal { return entityliving instanceof AbstractSchoolingFish; }); this.goalSelector.addGoal(0, new Fox.FoxFloatGoal()); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new Fox.FaceplantGoal()); this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2D)); this.goalSelector.addGoal(3, new Fox.FoxBreedGoal(1.0D)); @@ -182,6 +216,7 @@ public class Fox extends Animal { this.goalSelector.addGoal(11, new Fox.FoxSearchForItemsGoal()); this.goalSelector.addGoal(12, new Fox.FoxLookAtPlayerGoal(this, Player.class, 24.0F)); this.goalSelector.addGoal(13, new Fox.PerchAndSearchGoal()); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(3, new Fox.DefendTrustedTargetGoal(LivingEntity.class, false, false, (entityliving) -> { return Fox.TRUSTED_TARGET_SELECTOR.test(entityliving) && !this.trusts(entityliving.getUUID()); })); @@ -737,16 +772,16 @@ public class Fox extends Animal { return new Vec3(0.0D, (double) (0.55F * this.getEyeHeight()), (double) (this.getBbWidth() * 0.4F)); } - public class FoxLookControl extends LookControl { + public class FoxLookControl extends net.pl3x.purpur.controller.LookControllerWASD { // Purpur public FoxLookControl() { super(Fox.this); } @Override - public void tick() { + public void vanillaTick() { // Purpur if (!Fox.this.isSleeping()) { - super.tick(); + super.vanillaTick(); // Purpur } } @@ -757,16 +792,16 @@ public class Fox extends Animal { } } - private class FoxMoveControl extends MoveControl { + private class FoxMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur public FoxMoveControl() { super(Fox.this); } @Override - public void tick() { + public void vanillaTick() { // Purpur if (Fox.this.canMove()) { - super.tick(); + super.vanillaTick(); // Purpur } } diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java index ec00c2dd8f969eb99ec6a014e3bcd09c7484b237..63b739c86d2ea22aa9a610796ad2f208b0db289e 100644 --- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java +++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java @@ -70,8 +70,22 @@ public class IronGolem extends AbstractGolem implements NeutralMob { this.maxUpStep = 1.0F; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.ironGolemRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.ironGolemRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { + if (level.purpurConfig.ironGolemCanSwim) this.goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0D, true)); this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9D, 32.0F)); this.goalSelector.addGoal(2, new MoveBackToVillageGoal(this, 0.6D, false)); @@ -79,6 +93,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob { this.goalSelector.addGoal(5, new OfferFlowerGoal(this)); this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new DefendVillageTargetGoal(this)); this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); @@ -266,13 +281,13 @@ public class IronGolem extends AbstractGolem implements NeutralMob { ItemStack itemstack = player.getItemInHand(hand); if (!itemstack.is(Items.IRON_INGOT)) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } else { float f = this.getHealth(); this.heal(25.0F); if (this.getHealth() == f) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } else { float f1 = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F; diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java index d9fb3df35de94ae5abbb86ace0328bbe6f5403b3..0e066782ee09bb5626715bcc500bc04f2252bc2e 100644 --- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java +++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java @@ -59,6 +59,18 @@ public class MushroomCow extends Cow implements Shearable { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.mooshroomRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.mooshroomRidableInWater; + } + // Purpur end + @Override public float getWalkTargetValue(BlockPos pos, LevelReader world) { return world.getBlockState(pos.below()).is(Blocks.MYCELIUM) ? 10.0F : world.getBrightness(pos) - 0.5F; @@ -120,7 +132,7 @@ public class MushroomCow extends Cow implements Shearable { } else if (itemstack.is(Items.SHEARS) && this.readyForShearing()) { // CraftBukkit start if (!CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } // CraftBukkit end this.shear(SoundSource.PLAYERS); @@ -141,7 +153,7 @@ public class MushroomCow extends Cow implements Shearable { Optional> optional = this.getEffectFromItemStack(itemstack); if (!optional.isPresent()) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } Pair pair = (Pair) optional.get(); diff --git a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java index 06bf44ceb6f959a99f268fe1e1dca494985fbf4e..2a8f6d920370b4087895e9f0098a0f41d9b1e152 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java +++ b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java @@ -68,6 +68,18 @@ public class Ocelot extends Animal { this.reassessTrustingGoals(); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.ocelotRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.ocelotRidableInWater; + } + // Purpur end + public boolean isTrusting() { return (Boolean) this.entityData.get(Ocelot.DATA_TRUSTING); } @@ -99,12 +111,14 @@ public class Ocelot extends Animal { protected void registerGoals() { this.temptGoal = new Ocelot.OcelotTemptGoal(this, 0.6D, Ocelot.TEMPT_INGREDIENT, true); this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(3, this.temptGoal); this.goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3F)); this.goalSelector.addGoal(8, new OcelotAttackGoal(this)); this.goalSelector.addGoal(9, new BreedGoal(this, 0.8D)); this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 0.8D, 1.0000001E-5F)); this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0F)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Chicken.class, false)); this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR)); } diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java index 12ed864bedf2201fad68e2aeba249c3c18a12444..fa9dbb22dd13c650ef08af6030d60c5fc8ee8044 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Panda.java +++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java @@ -108,6 +108,27 @@ public class Panda extends Animal { } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.pandaRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.pandaRidableInWater; + } + + @Override + public void onMount(Player rider) { + super.onMount(rider); + setForwardMot(0.0F); + sit(false); + eat(false); + setOnBack(false); + } + // Purpur end + @Override public boolean canTakeItem(ItemStack stack) { EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(stack); @@ -263,6 +284,7 @@ public class Panda extends Animal { @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(2, new Panda.PandaPanicGoal(this, 2.0D)); this.goalSelector.addGoal(2, new Panda.PandaBreedGoal(this, 1.0D)); this.goalSelector.addGoal(3, new Panda.PandaAttackGoal(this, 1.2000000476837158D, true)); @@ -278,6 +300,7 @@ public class Panda extends Animal { this.goalSelector.addGoal(12, new Panda.PandaRollGoal(this)); this.goalSelector.addGoal(13, new FollowParentGoal(this, 1.25D)); this.goalSelector.addGoal(14, new WaterAvoidingRandomStrollGoal(this, 1.0D)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, (new Panda.PandaHurtByTargetGoal(this, new Class[0])).setAlertOthers(new Class[0])); } @@ -617,7 +640,7 @@ public class Panda extends Animal { ItemStack itemstack = player.getItemInHand(hand); if (this.isScared()) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } else if (this.isOnBack()) { this.setOnBack(false); return InteractionResult.sidedSuccess(this.level.isClientSide); @@ -636,7 +659,7 @@ public class Panda extends Animal { this.gameEvent(GameEvent.MOB_INTERACT, this.eyeBlockPosition()); } else { if (this.level.isClientSide || this.isSitting() || this.isInWater()) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } this.tryToSit(); @@ -653,7 +676,7 @@ public class Panda extends Animal { return InteractionResult.SUCCESS; } else { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } } @@ -693,7 +716,7 @@ public class Panda extends Animal { return !this.isOnBack() && !this.isScared() && !this.isEating() && !this.isRolling() && !this.isSitting(); } - private static class PandaMoveControl extends MoveControl { + private static class PandaMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur private final Panda panda; @@ -703,9 +726,9 @@ public class Panda extends Animal { } @Override - public void tick() { + public void vanillaTick() { // Purpur if (this.panda.canPerformAction()) { - super.tick(); + super.vanillaTick(); // Purpur } } } diff --git a/src/main/java/net/minecraft/world/entity/animal/Parrot.java b/src/main/java/net/minecraft/world/entity/animal/Parrot.java index 345fe87d5d6c3883c28d2c1b34d1020e18864d97..b881f6e948b21ba851913d9f244d74d886f2cc3a 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Parrot.java +++ b/src/main/java/net/minecraft/world/entity/animal/Parrot.java @@ -121,12 +121,63 @@ public class Parrot extends ShoulderRidingEntity implements FlyingAnimal { public Parrot(EntityType type, Level world) { super(type, world); - this.moveControl = new FlyingMoveControl(this, 10, false); + // Purpur start + final net.pl3x.purpur.controller.FlyingWithSpacebarMoveControllerWASD flyingController = new net.pl3x.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); + class ParrotMoveControl extends FlyingMoveControl { + public ParrotMoveControl(Mob entity, int maxPitchChange, boolean noGravity) { + super(entity, maxPitchChange, noGravity); + } + + @Override + public void tick() { + if (mob.getRider() != null) { + flyingController.purpurTick(mob.getRider()); + } else { + super.tick(); + } + } + + @Override + public boolean hasWanted() { + return mob.getRider() != null ? getForwardMot() != 0 || getStrafeMot() != 0 : super.hasWanted(); + } + } + this.moveControl = new ParrotMoveControl(this, 10, false); + // Purpur end this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F); this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, -1.0F); this.setPathfindingMalus(BlockPathTypes.COCOA, -1.0F); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.parrotRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.parrotRidableInWater; + } + + @Override + public double getMaxY() { + return level.purpurConfig.parrotMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && !onGround) { + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 2; + setSpeed(speed); + Vec3 mot = getDeltaMovement(); + move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.25, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } + // Purpur end + @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { @@ -145,8 +196,10 @@ public class Parrot extends ShoulderRidingEntity implements FlyingAnimal { @Override protected void registerGoals() { - this.goalSelector.addGoal(0, new PanicGoal(this, 1.25D)); + //this.goalSelector.addGoal(0, new PanicGoal(this, 1.25D)); // Purpur - move down this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D)); // Purpur this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); this.goalSelector.addGoal(2, new FollowOwnerGoal(this, 1.0D, 5.0F, 1.0F, true)); diff --git a/src/main/java/net/minecraft/world/entity/animal/Pig.java b/src/main/java/net/minecraft/world/entity/animal/Pig.java index 2c95b6eddfe46e5d2ad495bfc86ccc24ae75e704..80c8ceda47bf8b3ff370f89a61aa01869d606ee6 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Pig.java +++ b/src/main/java/net/minecraft/world/entity/animal/Pig.java @@ -65,9 +65,22 @@ public class Pig extends Animal implements ItemSteerable, Saddleable { this.steering = new ItemBasedSteering(this.entityData, Pig.DATA_BOOST_TIME, Pig.DATA_SADDLE_ID); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.pigRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.pigRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D)); this.goalSelector.addGoal(3, new BreedGoal(this, 1.0D)); this.goalSelector.addGoal(4, new TemptGoal(this, 1.2D, Ingredient.of(Items.CARROT_ON_A_STICK), false)); diff --git a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java index 0694cd0b994ee595adca43c988485e6dc13c7244..dc6bc8f10d147cb1d0e5c69b6f6df63b0e8d4531 100644 --- a/src/main/java/net/minecraft/world/entity/animal/PolarBear.java +++ b/src/main/java/net/minecraft/world/entity/animal/PolarBear.java @@ -61,11 +61,35 @@ public class PolarBear extends Animal implements NeutralMob { private static final UniformInt PERSISTENT_ANGER_TIME = TimeUtil.rangeOfSeconds(20, 39); private int remainingPersistentAngerTime; private UUID persistentAngerTarget; + private int standTimer = 0; // Purpur public PolarBear(EntityType type, Level world) { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.polarBearRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.polarBearRidableInWater; + } + + @Override + public boolean onSpacebar() { + if (!isStanding()) { + if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0) { + setStanding(true); + playSound(SoundEvents.POLAR_BEAR_WARNING, 1.0F, 1.0F); + } + } + return false; + } + // Purpur end + @Override public AgeableMob getBreedOffspring(ServerLevel world, AgeableMob entity) { return EntityType.POLAR_BEAR.create(world); @@ -80,12 +104,14 @@ public class PolarBear extends Animal implements NeutralMob { protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new PolarBear.PolarBearMeleeAttackGoal()); this.goalSelector.addGoal(1, new PolarBear.PolarBearPanicGoal()); this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25D)); this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0D)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new PolarBear.PolarBearHurtByTargetGoal()); this.targetSelector.addGoal(2, new PolarBear.PolarBearAttackPlayersGoal()); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); @@ -201,6 +227,11 @@ public class PolarBear extends Animal implements NeutralMob { this.updatePersistentAnger((ServerLevel)this.level, true); } + // Purpur start + if (isStanding() && --standTimer <= 0) { + setStanding(false); + } + // Purpur end } @Override @@ -230,6 +261,7 @@ public class PolarBear extends Animal implements NeutralMob { public void setStanding(boolean warning) { this.entityData.set(DATA_STANDING_ID, warning); + standTimer = warning ? 20 : -1; // Purpur } public float getStandingAnimationScale(float tickDelta) { diff --git a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java index 1b76e267cd36010a57d31852086dec0585d4bce5..42446fd8ba1d78cd5992bc6c2e5259da361eb716 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java +++ b/src/main/java/net/minecraft/world/entity/animal/Pufferfish.java @@ -45,6 +45,18 @@ public class Pufferfish extends AbstractFish { this.refreshDimensions(); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.pufferfishRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + // Purpur end + @Override protected void defineSynchedData() { super.defineSynchedData(); diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java index 3a9391b512974e812cac0d89119f68ba6728bfc9..29551a3b87f06c5876de5fda80615acf6c1f4764 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java +++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java @@ -81,6 +81,7 @@ public class Rabbit extends Animal { private boolean wasOnGround; private int jumpDelayTicks; int moreCarrotTicks; + private boolean actualJump; // Purpur public Rabbit(EntityType type, Level world) { super(type, world); @@ -89,6 +90,46 @@ public class Rabbit extends Animal { this.initializePathFinderGoals(); // CraftBukkit - moved code } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.rabbitRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.rabbitRidableInWater; + } + + @Override + public boolean onSpacebar() { + if (onGround) { + actualJump = true; + jumpFromGround(); + actualJump = false; + } + return true; + } + + private void handleJumping() { + if (onGround) { + RabbitJumpControl jumpController = (RabbitJumpControl) jumpControl; + if (!wasOnGround) { + setJumping(false); + jumpController.setCanJump(false); + } + if (!jumpController.wantJump()) { + if (moveControl.hasWanted()) { + startJumping(); + } + } else if (!jumpController.canJump()) { + jumpController.setCanJump(true); + } + } + wasOnGround = onGround; + } + // Purpur end + // CraftBukkit start - code from constructor public void initializePathFinderGoals(){ this.setSpeedModifier(0.0D); @@ -98,6 +139,7 @@ public class Rabbit extends Animal { @Override public void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new Rabbit.RabbitPanicGoal(this, 2.2D)); this.goalSelector.addGoal(2, new BreedGoal(this, 0.8D)); this.goalSelector.addGoal(3, new TemptGoal(this, 1.0D, Ingredient.of(Items.CARROT, Items.GOLDEN_CARROT, Blocks.DANDELION), false)); @@ -111,6 +153,13 @@ public class Rabbit extends Animal { @Override protected float getJumpPower() { + if (getRider() != null) { + if (getForwardMot() < 0) { + setSpeed(getForwardMot() * 2F); + } + return actualJump ? 0.5F : 0.3F; + } + // Purpur end if (!this.horizontalCollision && (!this.moveControl.hasWanted() || this.moveControl.getWantedY() <= this.getY() + 0.5D)) { Path pathentity = this.navigation.getPath(); @@ -129,7 +178,7 @@ public class Rabbit extends Animal { } @Override - protected void jumpFromGround() { + public void jumpFromGround() { // Purpur - protected -> public super.jumpFromGround(); double d0 = this.moveControl.getSpeedModifier(); @@ -179,6 +228,13 @@ public class Rabbit extends Animal { @Override public void customServerAiStep() { + // Purpur start + if (getRider() != null) { + handleJumping(); + return; + } + // Purpur end + if (this.jumpDelayTicks > 0) { --this.jumpDelayTicks; } @@ -451,7 +507,7 @@ public class Rabbit extends Animal { } } - private static class RabbitMoveControl extends MoveControl { + private static class RabbitMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur private final Rabbit rabbit; private double nextJumpSpeed; @@ -462,14 +518,14 @@ public class Rabbit extends Animal { } @Override - public void tick() { + public void vanillaTick() { // Purpur if (this.rabbit.onGround && !this.rabbit.jumping && !((Rabbit.RabbitJumpControl) this.rabbit.jumpControl).wantJump()) { this.rabbit.setSpeedModifier(0.0D); } else if (this.hasWanted()) { this.rabbit.setSpeedModifier(this.nextJumpSpeed); } - super.tick(); + super.vanillaTick(); // Purpur } @Override diff --git a/src/main/java/net/minecraft/world/entity/animal/Salmon.java b/src/main/java/net/minecraft/world/entity/animal/Salmon.java index 574f91414ecacd18fadef5a56a4142d9cfdb6713..02a9ce0b98bab47d57b51cdfb2194f0e72a9f705 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Salmon.java +++ b/src/main/java/net/minecraft/world/entity/animal/Salmon.java @@ -13,6 +13,18 @@ public class Salmon extends AbstractSchoolingFish { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.salmonRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + // Purpur end + @Override public int getMaxSchoolSize() { return 5; diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java index 9315c34e61aa0432175385736de51f1bfdafbf85..5890bf8aa714dc219059bca4950a1b5b1882dd3a 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java +++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java @@ -116,10 +116,23 @@ public class Sheep extends Animal implements Shearable { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.sheepRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.sheepRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.eatBlockGoal = new EatBlockGoal(this); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new PanicGoal(this, 1.25D)); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); this.goalSelector.addGoal(3, new TemptGoal(this, 1.1D, Ingredient.of(Items.WHEAT), false)); diff --git a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java index 8c2f447d0d307df35d84b4907000023eb82ac6c2..229b3cc63d2ec0bc5e5797d45efd9ca45f3ea82a 100644 --- a/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java +++ b/src/main/java/net/minecraft/world/entity/animal/SnowGolem.java @@ -53,12 +53,26 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.snowGolemRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.snowGolemRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new RangedAttackGoal(this, 1.25D, 20, 10.0F)); this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D, 1.0000001E-5F)); this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, (entityliving) -> { return entityliving instanceof Enemy; })); @@ -110,6 +124,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM return; } + if (getRider() != null && !level.purpurConfig.snowGolemLeaveTrailWhenRidden) return; // Purpur - don't leave snow trail when being ridden BlockState iblockdata = Blocks.SNOW.defaultBlockState(); for (int l = 0; l < 4; ++l) { @@ -152,7 +167,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM if (itemstack.is(Items.SHEARS) && this.readyForShearing()) { // CraftBukkit start if (!CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand)) { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } // CraftBukkit end this.shear(SoundSource.PLAYERS); @@ -165,7 +180,7 @@ public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackM return InteractionResult.sidedSuccess(this.level.isClientSide); } else { - return InteractionResult.PASS; + return tryRide(player, hand); // Purpur } } diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java index 56838c9f214c0f75041e75c45ad1a0c72fcacc66..151bb142c553d733367a92b39b430b536e569480 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Squid.java +++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java @@ -54,9 +54,32 @@ public class Squid extends WaterAnimal { this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.squidRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + + protected void rotateVectorAroundY(org.bukkit.util.Vector vector, double degrees) { + double rad = Math.toRadians(degrees); + double cos = Math.cos(rad); + double sine = Math.sin(rad); + double x = vector.getX(); + double z = vector.getZ(); + vector.setX(cos * x - sine * z); + vector.setZ(sine * x + cos * z); + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new Squid.SquidRandomMovementGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new Squid.SquidFleeGoal()); } @@ -250,6 +273,38 @@ public class Squid extends WaterAnimal { @Override public void tick() { + // Purpur start + Player rider = squid.getRider(); + if (rider != null) { + if (rider.jumping) { + squid.onSpacebar(); + } + float forward = rider.getForwardMot(); + float strafe = rider.getStrafeMot(); + float speed = (float) squid.getAttributeValue(Attributes.MOVEMENT_SPEED) * 10F; + if (forward < 0.0F) { + speed *= -0.5; + } + org.bukkit.util.Vector dir = rider.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(speed / 20.0F); + if (strafe != 0.0F) { + if (forward == 0.0F) { + dir.setY(0); + rotateVectorAroundY(dir, strafe > 0.0F ? -90 : 90); + } else if (forward < 0.0F) { + rotateVectorAroundY(dir, strafe > 0.0F ? 45 : -45); + } else { + rotateVectorAroundY(dir, strafe > 0.0F ? -45 : 45); + } + } + if (forward != 0.0F || strafe != 0.0F) { + squid.setMovementVector((float) dir.getX(), (float) dir.getY(), (float) dir.getZ()); + } else { + squid.setMovementVector(0.0F, 0.0F, 0.0F); + } + return; + } + // Purpur end + int i = this.squid.getNoActionTime(); if (i > 100) { diff --git a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java index 84015b5bf4b9a11670ad4d984844a431876efb63..5f61fcffebf4d853711a38d1f315f3def25e31a7 100644 --- a/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java +++ b/src/main/java/net/minecraft/world/entity/animal/TropicalFish.java @@ -43,6 +43,18 @@ public class TropicalFish extends AbstractSchoolingFish { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.tropicalFishRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + // Purpur end + public static String getPredefinedName(int variant) { return "entity.minecraft.tropical_fish.predefined." + variant; } diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java index 01d8af06f19427354cac95d691e65d31253fef94..631539a752a038926355c23aeb160af64f363a61 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java +++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java @@ -90,6 +90,18 @@ public class Turtle extends Animal { this.maxUpStep = 1.0F; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.turtleRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.turtleRidableInWater; + } + // Purpur end + public void setHomePos(BlockPos pos) { this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos... } @@ -192,6 +204,7 @@ public class Turtle extends Animal { @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(0, new Turtle.TurtlePanicGoal(this, 1.2D)); this.goalSelector.addGoal(1, new Turtle.TurtleBreedGoal(this, 1.0D)); this.goalSelector.addGoal(1, new Turtle.TurtleLayEggGoal(this, 1.0D)); @@ -349,13 +362,15 @@ public class Turtle extends Animal { org.bukkit.craftbukkit.event.CraftEventFactory.entityDamage = null; // CraftBukkit } - private static class TurtleMoveControl extends MoveControl { + private static class TurtleMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur private final Turtle turtle; + private final net.pl3x.purpur.controller.WaterMoveControllerWASD waterController; // Purpur TurtleMoveControl(Turtle turtle) { super(turtle); this.turtle = turtle; + waterController = new net.pl3x.purpur.controller.WaterMoveControllerWASD(turtle, 0.25D); // Purpur } private void updateSpeed() { @@ -374,8 +389,18 @@ public class Turtle extends Animal { } + // Purpur start + public void purpurTick(Player rider) { + if (turtle.isInWater()) { + waterController.purpurTick(rider); + } else { + super.purpurTick(rider); + } + } + // Purpur end + @Override - public void tick() { + public void vanillaTick() { // Purpur this.updateSpeed(); if (this.operation == MoveControl.Operation.MOVE_TO && !this.turtle.getNavigation().isDone()) { double d0 = this.wantedX - this.turtle.getX(); @@ -388,7 +413,7 @@ public class Turtle extends Animal { 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)); this.turtle.setSpeed(Mth.lerp(0.125F, this.turtle.getSpeed(), f1)); this.turtle.setDeltaMovement(this.turtle.getDeltaMovement().add(0.0D, (double) this.turtle.getSpeed() * d1 * 0.1D, 0.0D)); diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java index 80caabee4d2100208f117a1c3e35247b65e318ad..bca3300e06d6eb0c6acdfb11d715a1e8447c9198 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java +++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java @@ -93,9 +93,27 @@ public class Wolf extends TamableAnimal implements NeutralMob { this.setTame(false); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.wolfRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.wolfRidableInWater; + } + + public void onMount(Player rider) { + super.onMount(rider); + setInSittingPose(false); + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); this.goalSelector.addGoal(3, new Wolf.WolfAvoidEntityGoal<>(this, Llama.class, 24.0F, 1.5D, 1.5D)); this.goalSelector.addGoal(4, new LeapAtTargetGoal(this, 0.4F)); @@ -106,6 +124,7 @@ public class Wolf extends TamableAnimal implements NeutralMob { this.goalSelector.addGoal(9, new BegGoal(this, 8.0F)); this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(10, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this)); this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this)); this.targetSelector.addGoal(3, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers(new Class[0])); // CraftBukkit - decompile error diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java index fa365420a4593bc7d652b0d92f4750602fcb334b..0c2dbff44ec7238c051850976a5f1fd565f35258 100644 --- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java +++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java @@ -90,6 +90,23 @@ public class Axolotl extends Animal implements LerpingModel, Bucketable { this.maxUpStep = 1.0F; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.axolotlRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur + } + // Purpur end + @Override public Map getModelRotationValues() { return this.modelRotationValues; @@ -509,14 +526,22 @@ public class Axolotl extends Animal implements LerpingModel, Bucketable { private static class AxolotlMoveControl extends SmoothSwimmingMoveControl { private final Axolotl axolotl; + private final net.pl3x.purpur.controller.WaterMoveControllerWASD waterController; // Purpur public AxolotlMoveControl(Axolotl axolotl) { super(axolotl, 85, 10, 0.1F, 0.5F, false); this.axolotl = axolotl; + waterController = new net.pl3x.purpur.controller.WaterMoveControllerWASD(axolotl, 0.5D); // Purpur } @Override public void tick() { + // Purpur start + if (axolotl.getRider() != null) { + waterController.purpurTick(axolotl.getRider()); + return; + } + // Purpur end if (!this.axolotl.isPlayingDead()) { super.tick(); } @@ -531,9 +556,9 @@ public class Axolotl extends Animal implements LerpingModel, Bucketable { } @Override - public void tick() { + public void vanillaTick() { // Purpur if (!Axolotl.this.isPlayingDead()) { - super.tick(); + super.vanillaTick(); // Purpur } } diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java index 15787afad42f9299638a1c9e57d26678805f18ee..69a8578f86c42bde4c1df0c5ead033dae248d3ab 100644 --- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java +++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java @@ -72,6 +72,18 @@ public class Goat extends Animal { this.getNavigation().setCanFloat(true); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.goatRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.goatRidableInWater; + } + // Purpur end + @Override protected Brain.Provider brainProvider() { return Brain.provider((Collection) Goat.MEMORY_TYPES, (Collection) Goat.SENSOR_TYPES); @@ -147,6 +159,7 @@ public class Goat extends Animal { @Override protected void customServerAiStep() { this.level.getProfiler().push("goatBrain"); + if (getRider() == null) // Purpur - only use brain if no rider this.getBrain().tick((ServerLevel) this.level, this); // CraftBukkit - decompile error this.level.getProfiler().pop(); this.level.getProfiler().push("goatActivityUpdate"); diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java index 5c104bf219e5e4acb8acfb160bd92f0a0621d864..fbd96e516ac34f874b0cca2da9076120e29254fb 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java @@ -113,12 +113,22 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, protected AbstractHorse(EntityType type, Level world) { super(type, world); + this.moveControl = new net.minecraft.world.entity.ai.control.MoveControl(this); // Purpur - use vanilla controller + this.lookControl = new net.minecraft.world.entity.ai.control.LookControl(this); // Purpur - use vanilla controller this.maxUpStep = 1.0F; this.createInventory(); } + // Purpur start + @Override + public boolean isRidable() { + return false; // vanilla handles + } + // Purpur end + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HorseHasRider(this)); // Purpur this.goalSelector.addGoal(1, new PanicGoal(this, 1.2D)); this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D)); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D, AbstractHorse.class)); @@ -126,6 +136,7 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 0.7D)); this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HorseHasRider(this)); // Purpur this.addBehaviourGoals(); } diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java index ab588b990c15ff809a1937321d11a03aab826f61..e5b13558f45966bf70593931922ca73f4a66c66a 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/Donkey.java @@ -15,6 +15,13 @@ public class Donkey extends AbstractChestedHorse { super(type, world); } + // Purpur start + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.donkeyRidableInWater; + } + // Purpur end + @Override protected SoundEvent getAmbientSound() { super.getAmbientSound(); diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java index 6326471fe48133bef94e98fd028e60a951bccf2b..c7b0d6a987644e0b589c143b0b6b68053be04f37 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/Horse.java @@ -39,6 +39,13 @@ public class Horse extends AbstractHorse { super(type, world); } + // Purpur start + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.horseRidableInWater; + } + // Purpur end + @Override protected void randomizeAttributes() { this.getAttribute(Attributes.MAX_HEALTH).setBaseValue((double)this.generateRandomMaxHealth()); diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java index 5c31519193126b715105e1e83bb54f6a1681d19e..d336e2c63b39b22f9f3a7a84ee059c2d9d71239c 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/Llama.java @@ -68,7 +68,46 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { public Llama(EntityType type, Level world) { super(type, world); + // Purpur start + this.moveControl = new net.pl3x.purpur.controller.MoveControllerWASD(this) { + @Override + public void tick() { + if (entity.getRider() != null && isSaddled()) { + purpurTick(entity.getRider()); + } else { + vanillaTick(); + } + } + }; + this.lookControl = new net.pl3x.purpur.controller.LookControllerWASD(this) { + @Override + public void tick() { + if (entity.getRider() != null && isSaddled()) { + purpurTick(entity.getRider()); + } else { + vanillaTick(); + } + } + }; + // Purpur end + } + + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.llamaRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.llamaRidableInWater; + } + + @Override + public boolean isSaddled() { + return super.isSaddled() || (isTamed() && getSwag() != null); } + // Purpur end public boolean isTraderLlama() { return false; @@ -113,6 +152,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HorseHasRider(this)); // Purpur this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D)); this.goalSelector.addGoal(2, new LlamaFollowCaravanGoal(this, (double)2.1F)); this.goalSelector.addGoal(3, new RangedAttackGoal(this, 1.25D, 40, 20.0F)); @@ -122,6 +162,7 @@ public class Llama extends AbstractChestedHorse implements RangedAttackMob { this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 0.7D)); this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HorseHasRider(this)); // Purpur this.targetSelector.addGoal(1, new Llama.LlamaHurtByTargetGoal(this)); this.targetSelector.addGoal(2, new Llama.LlamaAttackWolfGoal(this)); } diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java b/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java index 6b10aeab9d671327f6e85a31b0c85ef310a1d0b2..40cc7e20913938d6e30e6bca9f4ad70fb5e9435b 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/Mule.java @@ -14,6 +14,13 @@ public class Mule extends AbstractChestedHorse { super(type, world); } + // Purpur start + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.muleRidableInWater; + } + // Purpur end + @Override protected SoundEvent getAmbientSound() { super.getAmbientSound(); diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java index 1d0a2296bab0140d3209c0749710d5fb952c79b4..d4057c300d39eca4ff2e11791ce5ba7993d9b66e 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonHorse.java @@ -29,6 +29,13 @@ public class SkeletonHorse extends AbstractHorse { super(type, world); } + // Purpur start + @Override + public boolean isTamed() { + return true; + } + // Purpur end + public static AttributeSupplier.Builder createAttributes() { return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0D).add(Attributes.MOVEMENT_SPEED, (double)0.2F); } @@ -40,6 +47,7 @@ public class SkeletonHorse extends AbstractHorse { @Override protected void addBehaviourGoals() { + if (level.purpurConfig.skeletonHorseCanSwim) goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur } @Override @@ -135,7 +143,7 @@ public class SkeletonHorse extends AbstractHorse { @Override public boolean rideableUnderWater() { - return true; + return level.purpurConfig.skeletonHorseRidableInWater; // Purpur } @Override diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java index 885937d7001259d9a8ee8d5bc16629a196a13fe8..ff252d9ca75b90ab7606f63aa5f89b6230e33a36 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java @@ -27,6 +27,23 @@ public class TraderLlama extends Llama { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.traderLlamaRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.traderLlamaRidableInWater; + } + + @Override + public boolean isSaddled() { + return super.isSaddled() || isTamed(); + } + // Purpur end + @Override public boolean isTraderLlama() { return true; diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java index c6c7096ec476d91ef91b164e32c5a9cd112f3dd7..d328e36015b6b7d6a9e093fbe232eb5ecda46d96 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/ZombieHorse.java @@ -22,6 +22,18 @@ public class ZombieHorse extends AbstractHorse { super(type, world); } + // Purpur start + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.zombieHorseRidableInWater; + } + + @Override + public boolean isTamed() { + return true; + } + // Purpur end + public static AttributeSupplier.Builder createAttributes() { return createBaseHorseAttributes().add(Attributes.MAX_HEALTH, 15.0D).add(Attributes.MOVEMENT_SPEED, (double)0.2F); } @@ -92,5 +104,6 @@ public class ZombieHorse extends AbstractHorse { @Override protected void addBehaviourGoals() { + if (level.purpurConfig.zombieHorseCanSwim) goalSelector.addGoal(0, new net.minecraft.world.entity.ai.goal.FloatGoal(this)); // Purpur } } diff --git a/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java b/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java index 305a891e4b51d1031d9e9238ff00e2ea7de8d954..84625d09df800fcfd477fc493fb5f8246567b7e8 100644 --- a/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java +++ b/src/main/java/net/minecraft/world/entity/boss/EnderDragonPart.java @@ -21,6 +21,13 @@ public class EnderDragonPart extends Entity { this.name = name; } + // Purpur start + @Override + public net.minecraft.world.InteractionResult interact(net.minecraft.world.entity.player.Player player, net.minecraft.world.InteractionHand hand) { + return parentMob.isAlive() ? parentMob.tryRide(player, hand) : net.minecraft.world.InteractionResult.PASS; + } + // Purpur end + @Override protected void defineSynchedData() { } diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java index 29aa428e019681af8d6b0020c12b18660ff6af6c..5df112f87fba042f13f615a22a5c6f850b779bf7 100644 --- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java @@ -102,6 +102,7 @@ public class EnderDragon extends Mob implements Enemy { private final int[] nodeAdjacency = new int[24]; private final BinaryHeap openSet = new BinaryHeap(); private Explosion explosionSource = new Explosion(null, this, null, null, Double.NaN, Double.NaN, Double.NaN, Float.NaN, true, Explosion.BlockInteraction.DESTROY); // CraftBukkit - reusable source for CraftTNTPrimed.getSource() + private boolean hadRider; // Purpur public EnderDragon(EntityType entitytypes, Level world) { super(EntityType.ENDER_DRAGON, world); @@ -116,8 +117,45 @@ public class EnderDragon extends Mob implements Enemy { } this.phaseManager = new EnderDragonPhaseManager(this); + + // Purpur start + this.moveControl = new net.pl3x.purpur.controller.FlyingMoveControllerWASD(this) { + @Override + public void vanillaTick() { + // dragon doesn't use the controller. do nothing + } + }; + this.lookControl = new net.pl3x.purpur.controller.LookControllerWASD(this) { + @Override + public void vanillaTick() { + // dragon doesn't use the controller. do nothing + } + + @Override + public void purpurTick(Player rider) { + setYawPitch(rider.yRot - 180F, rider.xRotO * 0.5F); + } + }; + // Purpur end + } + + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.enderDragonRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.enderDragonRidableInWater; } + @Override + public double getMaxY() { + return level.purpurConfig.enderDragonMaxY; + } + // Purpur end + public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0D); } @@ -166,6 +204,37 @@ public class EnderDragon extends Mob implements Enemy { @Override public void aiStep() { + // Purpur start + boolean hasRider = getRider() != null; + if (hasRider) { + if (!hadRider) { + hadRider = true; + noPhysics = false; + this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(4.0F, 2.0F); + } + + // dragon doesn't use controllers, so must tick manually + moveControl.tick(); + lookControl.tick(); + + moveRelative((float) getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.1F, new Vec3(-getStrafeMot(), getVerticalMot(), -getForwardMot())); + Vec3 mot = getDeltaMovement(); + setDeltaMovement(mot); + move(MoverType.PLAYER, mot); + + mot = mot.multiply(0.9F, 0.9F, 0.9F); + setDeltaMovement(mot); + + // control wing flap speed on client + phaseManager.setPhase(mot.x() * mot.x() + mot.z() * mot.z() < 0.005F ? EnderDragonPhase.HOVERING : EnderDragonPhase.HOLDING_PATTERN); + } else if (hadRider) { + hadRider = false; + noPhysics = true; + this.dimensions = net.minecraft.world.entity.EntityDimensions.scalable(16.0F, 8.0F); + phaseManager.setPhase(EnderDragonPhase.HOLDING_PATTERN); // HoldingPattern + } + // Purpur end + this.processFlappingMovement(); if (this.level.isClientSide) { this.setHealth(this.getHealth()); @@ -179,6 +248,8 @@ public class EnderDragon extends Mob implements Enemy { float f; if (this.isDeadOrDying()) { + if (hasRider) ejectPassengers(); // Purpur + float f1 = (this.random.nextFloat() - 0.5F) * 8.0F; f = (this.random.nextFloat() - 0.5F) * 4.0F; @@ -191,9 +262,9 @@ public class EnderDragon extends Mob implements Enemy { f = 0.2F / ((float) vec3d.horizontalDistance() * 10.0F + 1.0F); f *= (float) Math.pow(2.0D, vec3d.y); - if (this.phaseManager.getCurrentPhase().isSitting()) { + if (!hasRider && this.phaseManager.getCurrentPhase().isSitting()) { // Purpur this.flapTime += 0.1F; - } else if (this.inWall) { + } else if (!hasRider && this.inWall) { // Purpur this.flapTime += f * 0.5F; } else { this.flapTime += f; @@ -238,7 +309,7 @@ public class EnderDragon extends Mob implements Enemy { } this.phaseManager.getCurrentPhase().doClientTick(); - } else { + } else if (!hasRider) { // Purpur DragonPhaseInstance idragoncontroller = this.phaseManager.getCurrentPhase(); idragoncontroller.doServerTick(); @@ -308,7 +379,7 @@ public class EnderDragon extends Mob implements Enemy { this.tickPart(this.body, (double) (f11 * 0.5F), 0.0D, (double) (-f12 * 0.5F)); this.tickPart(this.wing1, (double) (f12 * 4.5F), 2.0D, (double) (f11 * 4.5F)); this.tickPart(this.wing2, (double) (f12 * -4.5F), 2.0D, (double) (f11 * -4.5F)); - if (!this.level.isClientSide && this.hurtTime == 0) { + if (!hasRider && !this.level.isClientSide && this.hurtTime == 0) { // Purpur this.knockBack(this.level.getEntities(this, this.wing1.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); this.knockBack(this.level.getEntities(this, this.wing2.getBoundingBox().inflate(4.0D, 2.0D, 4.0D).move(0.0D, -2.0D, 0.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); this.hurt(this.level.getEntities(this, this.head.getBoundingBox().inflate(1.0D), EntitySelector.NO_CREATIVE_OR_SPECTATOR)); @@ -352,7 +423,7 @@ public class EnderDragon extends Mob implements Enemy { } if (!this.level.isClientSide) { - this.inWall = this.checkWalls(this.head.getBoundingBox()) | this.checkWalls(this.neck.getBoundingBox()) | this.checkWalls(this.body.getBoundingBox()); + this.inWall = !hasRider && this.checkWalls(this.head.getBoundingBox()) | this.checkWalls(this.neck.getBoundingBox()) | this.checkWalls(this.body.getBoundingBox()); // Purpur if (this.dragonFight != null) { this.dragonFight.updateDragon(this); } diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java index bb329e9c1a2295e6433d3728692a1e716c89dcc0..fdc9068de403e98e18af11d4d6c5b708d2cc3c52 100644 --- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java @@ -83,6 +83,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob return entityliving.getMobType() != MobType.UNDEAD && entityliving.attackable(); }; private static final TargetingConditions TARGETING_CONDITIONS = TargetingConditions.forCombat().range(20.0D).selector(WitherBoss.LIVING_ENTITY_SELECTOR); + private int shootCooldown = 0; // Purpur // Paper start private boolean canPortal = false; @@ -95,15 +96,117 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob this.setHealth(this.getMaxHealth()); this.getNavigation().setCanFloat(true); this.xpReward = 50; + this.moveControl = new net.pl3x.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.1F); // Purpur } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.witherRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.witherRidableInWater; + } + + @Override + public double getMaxY() { + return level.purpurConfig.witherMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && !onGround) { + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED) * 5F; + setSpeed(speed); + Vec3 mot = getDeltaMovement(); + move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 0.5, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } + + @Override + public void onMount(Player rider) { + super.onMount(rider); + this.entityData.set(DATA_TARGETS.get(0), 0); + this.entityData.set(DATA_TARGETS.get(1), 0); + this.entityData.set(DATA_TARGETS.get(2), 0); + getNavigation().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); + WitherSkull skull = new WitherSkull(level, this, x - headX, y - headY, z - headZ) { + @Override + public boolean canHitEntity(Entity target) { + // do not hit rider + return target != rider && super.canHitEntity(target); + } + }; + skull.setPosRaw(headX, headY, headZ); + level.addFreshEntity(skull); + } + // Purpur end + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(0, new WitherBoss.WitherDoNothingGoal()); this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0D, 40, 20.0F)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0])); if(this.level.paperConfig.fixWitherTargetingBug) this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 0, false, false, null)); // Paper - Fix MC-29274 this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Mob.class, 0, false, false, WitherBoss.LIVING_ENTITY_SELECTOR)); @@ -246,6 +349,16 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob @Override protected void customServerAiStep() { + // Purpur start + if (getRider() != null) { + Vec3 mot = getDeltaMovement(); + setDeltaMovement(mot.x(), mot.y() + (getVerticalMot() > 0 ? 0.07D : 0.0D), mot.z()); + } + if (shootCooldown > 0) { + shootCooldown--; + } + // Purpur end + int i; if (this.getInvulnerableTicks() > 0) { @@ -553,7 +666,7 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob } public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 300.0D).add(Attributes.MOVEMENT_SPEED, 0.6000000238418579D).add(Attributes.FOLLOW_RANGE, 40.0D).add(Attributes.ARMOR, 4.0D); + return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 300.0D).add(Attributes.MOVEMENT_SPEED, 0.6000000238418579D).add(Attributes.FOLLOW_RANGE, 40.0D).add(Attributes.ARMOR, 4.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur } public float getHeadYRot(int headIndex) { @@ -573,11 +686,11 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob } public int getAlternativeTarget(int headIndex) { - return (Integer) this.entityData.get((EntityDataAccessor) WitherBoss.DATA_TARGETS.get(headIndex)); + return getRider() != null ? 0 : this.entityData.get(WitherBoss.DATA_TARGETS.get(headIndex)); // Purpur } public void setAlternativeTarget(int headIndex, int id) { - this.entityData.set((EntityDataAccessor) WitherBoss.DATA_TARGETS.get(headIndex), id); + if (getRider() == null) this.entityData.set(WitherBoss.DATA_TARGETS.get(headIndex), id); // Purpur } @Override diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java index cd75f895b6818fbb7ed4b0ef3df873f264bb2d1b..74f4f8e1c9faef3b50fa817ca3dfbb6b19b1622d 100644 --- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java +++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java @@ -69,12 +69,14 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(2, new RestrictSunGoal(this)); this.goalSelector.addGoal(3, new FleeSunGoal(this, 1.0D)); this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Wolf.class, 6.0F, 1.0D, 1.2D)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1.0D)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0])); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); diff --git a/src/main/java/net/minecraft/world/entity/monster/Blaze.java b/src/main/java/net/minecraft/world/entity/monster/Blaze.java index a1bbe0c34bd5693f041dca9028a5a52b2ca71bc5..a5294012d432d5d1fce570a1eb1b1716a24522de 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Blaze.java +++ b/src/main/java/net/minecraft/world/entity/monster/Blaze.java @@ -32,6 +32,7 @@ public class Blaze extends Monster { public Blaze(EntityType type, Level world) { super(type, world); + this.moveControl = new net.pl3x.purpur.controller.FlyingWithSpacebarMoveControllerWASD(this, 0.3F); // Purpur this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F); this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 0.0F); @@ -39,19 +40,50 @@ public class Blaze extends Monster { this.xpReward = 10; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.blazeRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.blazeRidableInWater; + } + + @Override + public double getMaxY() { + return level.purpurConfig.blazeMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && !onGround) { + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); + setSpeed(speed); + Vec3 mot = getDeltaMovement(); + move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } + // Purpur end + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(4, new Blaze.BlazeAttackGoal(this)); this.goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 1.0D)); this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D, 0.0F)); this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)).setAlertOthers()); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); } public static AttributeSupplier.Builder createAttributes() { - return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0D).add(Attributes.MOVEMENT_SPEED, (double)0.23F).add(Attributes.FOLLOW_RANGE, 48.0D); + return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0D).add(Attributes.MOVEMENT_SPEED, (double)0.23F).add(Attributes.FOLLOW_RANGE, 48.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur } @Override @@ -106,6 +138,14 @@ public class Blaze extends Monster { @Override protected void customServerAiStep() { + // Purpur start + if (getRider() != null) { + Vec3 mot = getDeltaMovement(); + setDeltaMovement(mot.x(), getVerticalMot() > 0 ? 0.07D : -0.07D, mot.z()); + return; + } + // Purpur end + --this.nextHeightOffsetChangeTick; if (this.nextHeightOffsetChangeTick <= 0) { this.nextHeightOffsetChangeTick = 100; diff --git a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java index d980b906d9206560741576fa4153c57212f307a0..dd05c5f35d78d1385f793f4e34333ff242d136e1 100644 --- a/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java +++ b/src/main/java/net/minecraft/world/entity/monster/CaveSpider.java @@ -28,6 +28,18 @@ public class CaveSpider extends Spider { return Spider.createAttributes().add(Attributes.MAX_HEALTH, 12.0D); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.caveSpiderRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.caveSpiderRidableInWater; + } + // Purpur end + @Override public boolean doHurtTarget(Entity target) { if (super.doHurtTarget(target)) { diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java index e8c36e8541f041a0d72a86f49ced2a3ce1549be0..1bf65519883585569a1acc780554505dc5d6c30b 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java +++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java @@ -60,21 +60,89 @@ public class Creeper extends Monster implements PowerableMob { public int maxSwell = 30; public int explosionRadius = 3; private int droppedSkulls; + // Purpur start + private int spacebarCharge = 0; + private int prevSpacebarCharge = 0; + private int powerToggleDelay = 0; + // Purpur end public Creeper(EntityType type, Level world) { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.creeperRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.creeperRidableInWater; + } + + @Override + protected void customServerAiStep() { + if (powerToggleDelay > 0) { + powerToggleDelay--; + } + if (getRider() != null) { + if (getRider().getForwardMot() != 0 || getRider().getStrafeMot() != 0) { + spacebarCharge = 0; + setIgnited(false); + } + if (spacebarCharge == prevSpacebarCharge) { + spacebarCharge = 0; + } + prevSpacebarCharge = spacebarCharge; + } + super.customServerAiStep(); + } + + @Override + public void onMount(Player rider) { + super.onMount(rider); + setIgnited(false); + } + + @Override + public boolean onSpacebar() { + if (powerToggleDelay > 0) { + return true; // just toggled power, do not jump or ignite + } + spacebarCharge++; + if (spacebarCharge > maxSwell - 2) { + spacebarCharge = 0; + if (getRider() != null && getRider().getBukkitEntity().hasPermission("allow.powered.creeper")) { + powerToggleDelay = 20; + setPowered(!isPowered()); + setIgnited(false); + return true; + } + } + if (!isIgnited()) { + if (getRider() != null && getRider().getForwardMot() == 0 && getRider().getStrafeMot() == 0 && + getRider().getBukkitEntity().hasPermission("allow.special.creeper")) { + setIgnited(true); + return true; + } + } + return getForwardMot() == 0 && getStrafeMot() == 0; // do not jump if standing still + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); this.goalSelector.addGoal(2, new SwellGoal(this)); + this.goalSelector.addGoal(3, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Ocelot.class, 6.0F, 1.0D, 1.2D)); this.goalSelector.addGoal(3, new AvoidEntityGoal<>(this, Cat.class, 6.0F, 1.0D, 1.2D)); this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0D, false)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8D)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); } @@ -318,6 +386,7 @@ public class Creeper extends Monster implements PowerableMob { com.destroystokyo.paper.event.entity.CreeperIgniteEvent event = new com.destroystokyo.paper.event.entity.CreeperIgniteEvent((org.bukkit.entity.Creeper) getBukkitEntity(), ignited); if (event.callEvent()) { this.entityData.set(Creeper.DATA_IS_IGNITED, event.isIgnited()); + if (!event.isIgnited()) setSwellDir(-1); // Purpur } } // Paper end diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java index 50228e59d629e75e97d23bd3ec92088f75480827..ace909fab2334105eabe0593aba47736e3f67451 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java +++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java @@ -69,6 +69,18 @@ public class Drowned extends Zombie implements RangedAttackMob { this.groundNavigation = new GroundPathNavigation(this, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.drownedRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.drownedRidableInWater; + } + // Purpur end + @Override protected void addBehaviourGoals() { this.goalSelector.addGoal(1, new Drowned.DrownedGoToWaterGoal(this, 1.0D)); @@ -378,7 +390,7 @@ public class Drowned extends Zombie implements RangedAttackMob { } } - static class DrownedMoveControl extends MoveControl { + static class DrownedMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur private final Drowned drowned; public DrownedMoveControl(Drowned drowned) { @@ -387,7 +399,7 @@ public class Drowned extends Zombie implements RangedAttackMob { } @Override - public void tick() { + public void vanillaTick() { // Purpur LivingEntity livingEntity = this.drowned.getTarget(); if (this.drowned.wantsToSwim() && this.drowned.isInWater()) { if (livingEntity != null && livingEntity.getY() > this.drowned.getY() || this.drowned.searchingForLand) { @@ -407,7 +419,7 @@ public class Drowned extends Zombie implements RangedAttackMob { float h = (float)(Mth.atan2(f, d) * (double)(180F / (float)Math.PI)) - 90.0F; this.drowned.setYRot(this.rotlerp(this.drowned.getYRot(), h, 90.0F)); this.drowned.yBodyRot = this.drowned.getYRot(); - float i = (float)(this.speedModifier * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); + float i = (float)(this.getSpeedModifier() * this.drowned.getAttributeValue(Attributes.MOVEMENT_SPEED)); float j = Mth.lerp(0.125F, this.drowned.getSpeed(), i); this.drowned.setSpeed(j); this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add((double)j * d * 0.005D, (double)j * e * 0.1D, (double)j * f * 0.005D)); @@ -416,7 +428,7 @@ public class Drowned extends Zombie implements RangedAttackMob { this.drowned.setDeltaMovement(this.drowned.getDeltaMovement().add(0.0D, -0.008D, 0.0D)); } - super.tick(); + super.vanillaTick(); // Purpur } } diff --git a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java index ee2febe92309f277f1607c0ea024d6cd291490bc..5f8233c1be6f92bcf58c5c5db360b2660c9439ad 100644 --- a/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java +++ b/src/main/java/net/minecraft/world/entity/monster/ElderGuardian.java @@ -30,6 +30,18 @@ public class ElderGuardian extends Guardian { } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.elderGuardianRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + // Purpur end + public static AttributeSupplier.Builder createAttributes() { return Guardian.createAttributes().add(Attributes.MOVEMENT_SPEED, 0.30000001192092896D).add(Attributes.ATTACK_DAMAGE, 8.0D).add(Attributes.MAX_HEALTH, 80.0D); } diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java index e1e220b3e4967590a2a77370e2a6ab919ad50eaa..f68c6ec513437b83bf8bc4a5f8b5cdadbc418436 100644 --- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java @@ -83,9 +83,22 @@ public class EnderMan extends Monster implements NeutralMob { this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.endermanRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.endermanRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new EnderMan.EndermanFreezeWhenLookedAt(this)); this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false)); this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D, 0.0F)); @@ -93,6 +106,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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new EnderMan.EndermanLookForPlayerGoal(this, this::isAngryAt)); this.targetSelector.addGoal(2, new HurtByTargetGoal(this, new Class[0])); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Endermite.class, true, false)); @@ -273,7 +287,7 @@ public class EnderMan extends Monster implements NeutralMob { @Override protected void customServerAiStep() { - if (this.level.isDay() && this.tickCount >= this.targetChangeTime + 600) { + if (getRider() == null && this.level.isDay() && this.tickCount >= this.targetChangeTime + 600) { // Purpur - no random teleporting float f = this.getBrightness(); if (f > 0.5F && this.level.canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper @@ -373,6 +387,7 @@ public class EnderMan extends Monster implements NeutralMob { public boolean hurt(DamageSource source, float amount) { if (this.isInvulnerableTo(source)) { return false; + } else if (getRider() != null) { return super.hurt(source, amount); // Purpur - no teleporting on damage } else if (source instanceof IndirectEntityDamageSource) { if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper start for (int i = 0; i < 64; ++i) { diff --git a/src/main/java/net/minecraft/world/entity/monster/Endermite.java b/src/main/java/net/minecraft/world/entity/monster/Endermite.java index 4aecf69a335c2c6b6457f3b15a1420400878b6e6..1f315cc57f6365a782ca4e645b0dcfbe5485138a 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Endermite.java +++ b/src/main/java/net/minecraft/world/entity/monster/Endermite.java @@ -36,13 +36,27 @@ public class Endermite extends Monster { this.xpReward = 3; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.endermiteRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.endermiteRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false)); this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 1.0D)); this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)).setAlertOthers()); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); } diff --git a/src/main/java/net/minecraft/world/entity/monster/Evoker.java b/src/main/java/net/minecraft/world/entity/monster/Evoker.java index 4b812fc118126040d773f87ab50047cbbda79d1c..053374baf3ec7730bcddf072ddf98e3176656435 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Evoker.java +++ b/src/main/java/net/minecraft/world/entity/monster/Evoker.java @@ -46,10 +46,23 @@ public class Evoker extends SpellcasterIllager { this.xpReward = 10; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.evokerRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.evokerRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new Evoker.EvokerCastingSpellGoal()); this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Player.class, 8.0F, 0.6D, 1.0D)); this.goalSelector.addGoal(4, new Evoker.EvokerSummonSpellGoal()); @@ -58,6 +71,7 @@ public class Evoker extends SpellcasterIllager { this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D)); 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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur 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/src/main/java/net/minecraft/world/entity/monster/Ghast.java b/src/main/java/net/minecraft/world/entity/monster/Ghast.java index 886b6eac6c6ae4d97b1b25624504c0f48e20efc4..bb1a6f6847d0e459eb26a029d8a1f5646168a422 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Ghast.java +++ b/src/main/java/net/minecraft/world/entity/monster/Ghast.java @@ -44,11 +44,42 @@ public class Ghast extends FlyingMob implements Enemy { this.moveControl = new Ghast.GhastMoveControl(this); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.ghastRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.ghastRidableInWater; + } + + @Override + public double getMaxY() { + return level.purpurConfig.ghastMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && !onGround) { + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); + setSpeed(speed); + Vec3 mot = getDeltaMovement(); + move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 1.0, speed)); + setDeltaMovement(mot.scale(0.9D)); + } + } + // Purpur end + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entityliving) -> { return Math.abs(entityliving.getY() - this.getY()) <= 4.0D; })); @@ -90,7 +121,7 @@ public class Ghast extends FlyingMob implements Enemy { } public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.FOLLOW_RANGE, 100.0D); + return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.FOLLOW_RANGE, 100.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur } @Override @@ -147,7 +178,7 @@ public class Ghast extends FlyingMob implements Enemy { return 2.6F; } - private static class GhastMoveControl extends MoveControl { + private static class GhastMoveControl extends net.pl3x.purpur.controller.FlyingMoveControllerWASD { // Purpur private final Ghast ghast; private int floatDuration; @@ -158,7 +189,7 @@ public class Ghast extends FlyingMob implements Enemy { } @Override - public void tick() { + public void vanillaTick() { // Purpur if (this.operation == MoveControl.Operation.MOVE_TO) { if (this.floatDuration-- <= 0) { this.floatDuration += this.ghast.getRandom().nextInt(5) + 2; diff --git a/src/main/java/net/minecraft/world/entity/monster/Giant.java b/src/main/java/net/minecraft/world/entity/monster/Giant.java index 0d578ab12c874bd2daccc4322a3fe1abafa4bc18..d95b110a025d48e7ab18f172e455593740e45252 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Giant.java +++ b/src/main/java/net/minecraft/world/entity/monster/Giant.java @@ -14,6 +14,24 @@ public class Giant extends Monster { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.giantRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.giantRidableInWater; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); + } + // Purpur end + @Override protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { return 10.440001F; diff --git a/src/main/java/net/minecraft/world/entity/monster/Guardian.java b/src/main/java/net/minecraft/world/entity/monster/Guardian.java index c5441f2784463b35fefbb567bf4eca579b3769bb..20b7104b7fd38b3c6c05a68a1472c6006814cb81 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Guardian.java +++ b/src/main/java/net/minecraft/world/entity/monster/Guardian.java @@ -65,15 +65,36 @@ public class Guardian extends Monster { this.xpReward = 10; this.setPathfindingMalus(BlockPathTypes.WATER, 0.0F); this.moveControl = new Guardian.GuardianMoveControl(this); + // Purpur start + this.lookControl = new net.pl3x.purpur.controller.LookControllerWASD(this) { + @Override + public void setYawPitch(float yaw, float pitch) { + super.setYawPitch(yaw, pitch * 0.35F); + } + }; + // Purpur end this.clientSideTailAnimation = this.random.nextFloat(); this.clientSideTailAnimationO = this.clientSideTailAnimation; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.guardianRidable; + } + + @Override + public boolean rideableUnderWater() { + return true; + } + // Purpur end + @Override protected void registerGoals() { MoveTowardsRestrictionGoal pathfindergoalmovetowardsrestriction = new MoveTowardsRestrictionGoal(this, 1.0D); this.randomStrollGoal = new RandomStrollGoal(this, 1.0D, 80); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(4, new Guardian.GuardianAttackGoal(this)); this.goalSelector.addGoal(5, pathfindergoalmovetowardsrestriction); 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)); pathfindergoalmovetowardsrestriction.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, LivingEntity.class, 10, true, false, new Guardian.GuardianAttackSelector(this))); } @@ -337,7 +359,7 @@ public class Guardian extends Monster { @Override public void travel(Vec3 movementInput) { if (this.isEffectiveAi() && this.isInWater()) { - this.moveRelative(0.1F, movementInput); + this.moveRelative(getRider() != null ? getSpeed() : 0.1F, movementInput); // Purpur this.move(MoverType.SELF, this.getDeltaMovement()); this.setDeltaMovement(this.getDeltaMovement().scale(0.9D)); if (!this.isMoving() && this.getTarget() == null) { @@ -349,8 +371,7 @@ public class Guardian extends Monster { } - private static class GuardianMoveControl extends MoveControl { - + private static class GuardianMoveControl extends net.pl3x.purpur.controller.WaterMoveControllerWASD { // Purpur private final Guardian guardian; public GuardianMoveControl(Guardian guardian) { @@ -358,8 +379,17 @@ public class Guardian extends Monster { this.guardian = guardian; } + // Purpur start @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 + + @Override + public void vanillaTick() { // Purpur if (this.operation == MoveControl.Operation.MOVE_TO && !this.guardian.getNavigation().isDone()) { Vec3 vec3d = new Vec3(this.wantedX - this.guardian.getX(), this.wantedY - this.guardian.getY(), this.wantedZ - this.guardian.getZ()); double d0 = vec3d.length(); @@ -370,7 +400,7 @@ public class Guardian extends Monster { 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 float f2 = Mth.lerp(0.125F, this.guardian.getSpeed(), f1); this.guardian.setSpeed(f2); diff --git a/src/main/java/net/minecraft/world/entity/monster/Husk.java b/src/main/java/net/minecraft/world/entity/monster/Husk.java index 28fb67c0a5992cbd77c5d3c6efa0f0493466d81c..75397a8e1ae8d48bf07f5c0409536acd54851c48 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Husk.java +++ b/src/main/java/net/minecraft/world/entity/monster/Husk.java @@ -22,6 +22,18 @@ public class Husk extends Zombie { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.huskRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.huskRidableInWater; + } + // Purpur end + public static boolean checkHuskSpawnRules(EntityType type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) { return checkMonsterSpawnRules(type, world, spawnReason, pos, random) && (spawnReason == MobSpawnType.SPAWNER || world.canSeeSky(pos)); } diff --git a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java index c9fa01b910de7ecb494d3000afebea9a2bd1276a..5f57c14a7ba03af9432a839e6caed47286638b2c 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java +++ b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java @@ -59,10 +59,23 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.illusionerRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.illusionerRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new SpellcasterIllager.SpellcasterCastingSpellGoal()); this.goalSelector.addGoal(4, new Illusioner.IllusionerMirrorSpellGoal()); this.goalSelector.addGoal(5, new Illusioner.IllusionerBlindnessSpellGoal()); @@ -70,6 +83,7 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob { this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D)); 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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers(new Class[0])); // CraftBukkit - decompile error 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/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java index 130205f0d101debaa74c1172fb80863e6fa0ebe1..7d39f25734f2c52b11931e141524acd2c244c2c5 100644 --- a/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java +++ b/src/main/java/net/minecraft/world/entity/monster/MagmaCube.java @@ -27,6 +27,23 @@ public class MagmaCube extends Slime { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.magmaCubeRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.magmaCubeRidableInWater; + } + + @Override + public float getJumpPower() { + return 0.42F * this.getBlockJumpFactor(); // from EntityLiving + } + // Purpur end + public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, (double)0.2F); } @@ -57,7 +74,7 @@ public class MagmaCube extends Slime { } @Override - protected ResourceLocation getDefaultLootTable() { + public ResourceLocation getDefaultLootTable() { // Purpur - decompile fix return this.isTiny() ? BuiltInLootTables.EMPTY : this.getType().getDefaultLootTable(); } @@ -77,10 +94,11 @@ public class MagmaCube extends Slime { } @Override - protected void jumpFromGround() { + public void jumpFromGround() { // Purpur - protected -> public Vec3 vec3 = this.getDeltaMovement(); this.setDeltaMovement(vec3.x, (double)(this.getJumpPower() + (float)this.getSize() * 0.1F), vec3.z); this.hasImpulse = true; + this.actualJump = false; // Purpur } @Override diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java index 39291a0cea465613733a905141b584f05e597b4c..61aff98a7b56eab6a43ddc9f07618cbbedb6b77d 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java +++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java @@ -61,6 +61,59 @@ public class Phantom extends FlyingMob implements Enemy { this.lookControl = new Phantom.PhantomLookControl(this); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.phantomRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.phantomRidableInWater; + } + + @Override + public double getMaxY() { + return level.purpurConfig.phantomMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null && !onGround) { + float speed = (float) getAttributeValue(Attributes.FLYING_SPEED); + setSpeed(speed); + Vec3 mot = getDeltaMovement(); + move(net.minecraft.world.entity.MoverType.SELF, mot.multiply(speed, 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()); + + net.pl3x.purpur.entity.PhantomFlames flames = new net.pl3x.purpur.entity.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 + @Override public boolean isFlapping() { return (this.getUniqueFlapTickOffset() + this.tickCount) % Phantom.TICKS_PER_FLAP == 0; @@ -73,9 +126,11 @@ public class Phantom extends FlyingMob implements Enemy { @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur 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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new Phantom.PhantomAttackPlayerTargetGoal()); } @@ -145,7 +200,7 @@ public class Phantom extends FlyingMob implements Enemy { @Override public void aiStep() { - if (this.isAlive() && shouldBurnInDay && this.isSunBurnTick()) { // Paper - Configurable Burning + if (this.isAlive() && getRider() == null && shouldBurnInDay && this.isSunBurnTick()) { // Paper - Configurable Burning // Purpur this.setSecondsOnFire(8); } @@ -265,7 +320,7 @@ public class Phantom extends FlyingMob implements Enemy { private AttackPhase() {} } - private class PhantomMoveControl extends MoveControl { + private class PhantomMoveControl extends net.pl3x.purpur.controller.FlyingMoveControllerWASD { // Purpur private float speed = 0.1F; @@ -273,8 +328,19 @@ public class Phantom extends FlyingMob implements Enemy { super(entity); } + // Purpur start + 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 + @Override - public void tick() { + public void vanillaTick() { // Purpur if (Phantom.this.horizontalCollision) { Phantom.this.setYRot(Phantom.this.getYRot() + 180.0F); this.speed = 0.1F; @@ -320,14 +386,20 @@ public class Phantom extends FlyingMob implements Enemy { } } - private class PhantomLookControl extends LookControl { + private class PhantomLookControl extends net.pl3x.purpur.controller.LookControllerWASD { // Purpur public PhantomLookControl(Mob entity) { super(entity); } + // Purpur start + public void purpurTick(Player rider) { + setYawPitch(rider.yRot, -rider.xRotO * 0.75F); + } + // Purpur end + @Override - public void tick() {} + public void vanillaTick() {} // Purpur } private class PhantomBodyRotationControl extends BodyRotationControl { diff --git a/src/main/java/net/minecraft/world/entity/monster/Pillager.java b/src/main/java/net/minecraft/world/entity/monster/Pillager.java index c0de613024de7b9b55f96be37e4648e83dea9b8f..84bd5e7df663f315fd099742195e85508ea25adf 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Pillager.java +++ b/src/main/java/net/minecraft/world/entity/monster/Pillager.java @@ -66,15 +66,29 @@ public class Pillager extends AbstractIllager implements CrossbowAttackMob, Inve super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.pillagerRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.pillagerRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(2, new Raider.HoldGroundAttackGoal(this, 10.0F)); this.goalSelector.addGoal(3, new RangedCrossbowAttackGoal<>(this, 1.0D, 8.0F)); this.goalSelector.addGoal(8, new RandomStrollGoal(this, 0.6D)); 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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers(new Class[0])); // CraftBukkit - decompile error this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java index 4f51de49757a912ec84ccf5dab087c9a3e11a60e..32ef769b2b3e3ab42c7a50bf4c8ec7ec548d5e7b 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java +++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java @@ -70,14 +70,34 @@ public class Ravager extends Raider { this.xpReward = 20; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.ravagerRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.ravagerRidableInWater; + } + + @Override + public void onMount(Player rider) { + super.onMount(rider); + getNavigation().stop(); + } + // Purpur end + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(4, new Ravager.RavagerMeleeAttackGoal()); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.4D)); 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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(2, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers(new Class[0])); // CraftBukkit - decompile error this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true)); this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); @@ -149,7 +169,7 @@ public class Ravager extends Raider { @Override public void aiStep() { super.aiStep(); - if (this.isAlive()) { + if (this.isAlive() && getRider() == null) { // Purpur if (this.isImmobile()) { this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.0D); } else { diff --git a/src/main/java/net/minecraft/world/entity/monster/Shulker.java b/src/main/java/net/minecraft/world/entity/monster/Shulker.java index ca0d1c059a6ad94590bcbff34b37b9c13ef19474..42635be6183d86978df3f174c74a71691f2bfcdd 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Shulker.java +++ b/src/main/java/net/minecraft/world/entity/monster/Shulker.java @@ -92,12 +92,26 @@ public class Shulker extends AbstractGolem implements Enemy { this.lookControl = new Shulker.ShulkerLookControl(this); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.shulkerRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.shulkerRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 8.0F, 0.02F, true)); this.goalSelector.addGoal(4, new Shulker.ShulkerAttackGoal()); this.goalSelector.addGoal(7, new Shulker.ShulkerPeekGoal()); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{this.getClass()})).setAlertOthers(new Class[0])); // CraftBukkit - decompile error this.targetSelector.addGoal(2, new Shulker.ShulkerNearestAttackGoal(this)); this.targetSelector.addGoal(3, new Shulker.ShulkerDefenseAttackGoal(this)); @@ -597,7 +611,7 @@ public class Shulker extends AbstractGolem implements Enemy { return b0 != 16 && b0 <= 15 ? DyeColor.byId(b0) : null; } - private class ShulkerLookControl extends LookControl { + private class ShulkerLookControl extends net.pl3x.purpur.controller.LookControllerWASD { // Purpur public ShulkerLookControl(Mob entity) { super(entity); diff --git a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java index 2459ae800a5f6b234a4f4bb1cd3738e4e9cac67d..e66cc79dc61721b31ffb743f68f4388cc499a92d 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java +++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java @@ -39,13 +39,27 @@ public class Silverfish extends Monster { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.silverfishRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.silverfishRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.friendsGoal = new Silverfish.SilverfishWakeUpFriendsGoal(this); this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(3, this.friendsGoal); this.goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0D, false)); this.goalSelector.addGoal(5, new Silverfish.SilverfishMergeWithStoneGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers(new Class[0])); // CraftBukkit - decompile error this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); } diff --git a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java index ccf706acafc20e7ba5408d1648b873d6937a030c..059a62da29b7ec11e2ff9baf18dde788bec4923c 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Skeleton.java +++ b/src/main/java/net/minecraft/world/entity/monster/Skeleton.java @@ -25,6 +25,18 @@ public class Skeleton extends AbstractSkeleton { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.skeletonRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.skeletonRidableInWater; + } + // Purpur end + @Override protected void defineSynchedData() { super.defineSynchedData(); diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java index e1a593b464c35f68b22e84a09f99ee72af73da32..25ce1910a03947ce070b318f57379f0da5ac5db8 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Slime.java +++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java @@ -67,18 +67,50 @@ public class Slime extends Mob implements Enemy { public float squish; public float oSquish; private boolean wasOnGround; + protected boolean actualJump; // Purpur public Slime(EntityType type, Level world) { super(type, world); this.moveControl = new Slime.SlimeMoveControl(this); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.slimeRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.slimeRidableInWater; + } + + @Override + public float getJumpPower() { + float height = super.getJumpPower(); + return getRider() != null && actualJump ? height * 1.5F : height; + } + + @Override + public boolean onSpacebar() { + if (onGround && getRider() != null) { + 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 + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur 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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entityliving) -> { return Math.abs(entityliving.getY() - this.getY()) <= 4.0D; })); @@ -360,11 +392,12 @@ public class Slime extends Mob implements Enemy { } @Override - protected void jumpFromGround() { + public void jumpFromGround() { // Purpur - protected -> public Vec3 vec3d = this.getDeltaMovement(); this.setDeltaMovement(vec3d.x, (double) this.getJumpPower(), vec3d.z); this.hasImpulse = true; + this.actualJump = false; // Purpur } @Nullable @@ -397,7 +430,7 @@ public class Slime extends Mob implements Enemy { return super.getDimensions(pose).scale(0.255F * (float) this.getSize()); } - private static class SlimeMoveControl extends MoveControl { + private static class SlimeMoveControl extends net.pl3x.purpur.controller.MoveControllerWASD { // Purpur private float yRot; private int jumpDelay; @@ -416,21 +449,33 @@ public class Slime extends Mob implements Enemy { } public void setWantedMovement(double speed) { - this.speedModifier = speed; + this.setSpeedModifier(speed); // Purpur this.operation = MoveControl.Operation.MOVE_TO; } @Override public void tick() { + // Purpur start + if (slime.getRider() != null) { + purpurTick(slime.getRider()); + if (slime.getForwardMot() != 0 || slime.getStrafeMot() != 0) { + if (jumpDelay > 10) { + jumpDelay = 6; + } + } else { + jumpDelay = 20; + } + } else { + // Purpur end 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 (entity.getRider() == null && this.operation != MoveControl.Operation.MOVE_TO) { // Purpur this.mob.setZza(0.0F); } else { this.operation = MoveControl.Operation.WAIT; if (this.mob.isOnGround()) { - this.mob.setSpeed((float) (this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED))); + this.mob.setSpeed((float) (this.getSpeedModifier() * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED) * (entity.getRider() != null && (entity.getRider().getForwardMot() != 0 || entity.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur if (this.jumpDelay-- <= 0) { this.jumpDelay = this.slime.getJumpDelay(); if (this.isAggressive) { @@ -447,7 +492,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) * (entity.getRider() != null && (entity.getRider().getForwardMot() != 0 || entity.getRider().getStrafeMot() != 0) ? 2.0D : 1.0D))); // Purpur } } diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java index a8162116eb888106e6f48ee836d0cc5d33b72399..5874d86ca34200e9ce7d41cf7a80eb0f1f13410c 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Spider.java +++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java @@ -51,14 +51,28 @@ public class Spider extends Monster { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.spiderRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.spiderRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4F)); this.goalSelector.addGoal(4, new Spider.SpiderAttackGoal(this)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8D)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0])); this.targetSelector.addGoal(2, new Spider.SpiderTargetGoal<>(this, Player.class)); this.targetSelector.addGoal(3, new Spider.SpiderTargetGoal<>(this, IronGolem.class)); diff --git a/src/main/java/net/minecraft/world/entity/monster/Stray.java b/src/main/java/net/minecraft/world/entity/monster/Stray.java index 0cfcd9c69213d75b52dc93392da727208c13150d..6a8a0cd09e0bf17c7ecb6e55342b645f111dac22 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Stray.java +++ b/src/main/java/net/minecraft/world/entity/monster/Stray.java @@ -21,6 +21,18 @@ public class Stray extends AbstractSkeleton { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.strayRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.strayRidableInWater; + } + // Purpur end + public static boolean checkStraySpawnRules(EntityType type, ServerLevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) { BlockPos blockPos = pos; diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java index fc772387713d4313ec8f90a8abcaf7b703fd9f21..6c0af80f47c53e4573efb0c50412d289c0bb5540 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Strider.java +++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java @@ -97,6 +97,18 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, 0.0F); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.striderRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.striderRidableInWater; + } + // Purpur end + public static boolean checkStriderSpawnRules(EntityType type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) { BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); @@ -158,6 +170,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { @Override protected void registerGoals() { this.panicGoal = new PanicGoal(this, 1.65D); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, this.panicGoal); this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D)); this.temptGoal = new TemptGoal(this, 1.4D, Strider.TEMPT_ITEMS, false); @@ -438,7 +451,7 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { if (!enuminteractionresult.consumesAction()) { ItemStack itemstack = player.getItemInHand(hand); - return itemstack.is(Items.SADDLE) ? itemstack.interactLivingEntity(player, (LivingEntity) this, hand) : InteractionResult.PASS; + return itemstack.is(Items.SADDLE) ? itemstack.interactLivingEntity(player, (LivingEntity) this, hand) : tryRide(player, hand); // Purpur } else { if (flag && !this.isSilent()) { this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.STRIDER_EAT, this.getSoundSource(), 1.0F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F); diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java index d4ea25f30ff6b914958da0c7a4914ba9a65327a3..c914cfc75cc0426c0333a6bb30aab7b9e4c52971 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Vex.java +++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java @@ -57,6 +57,45 @@ public class Vex extends Monster { this.xpReward = 3; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.vexRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.vexRidableInWater; + } + + @Override + public double getMaxY() { + return level.purpurConfig.vexMaxY; + } + + @Override + public void travel(Vec3 vec3) { + super.travel(vec3); + if (getRider() != null) { + 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(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 + @Override public boolean isFlapping() { return this.tickCount % Vex.TICKS_PER_FLAP == 0; @@ -70,7 +109,7 @@ public class Vex extends Monster { @Override public void tick() { - this.noPhysics = true; + this.noPhysics = getRider() == null; // Purpur super.tick(); this.noPhysics = false; this.setNoGravity(true); @@ -85,17 +124,19 @@ public class Vex extends Monster { protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(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 net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[]{Raider.class})).setAlertOthers(new Class[0])); // CraftBukkit - decompile error 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.0D).add(Attributes.ATTACK_DAMAGE, 4.0D); + return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 14.0D).add(Attributes.ATTACK_DAMAGE, 4.0D).add(Attributes.FLYING_SPEED, 0.6D); // Purpur; } @Override @@ -215,14 +256,14 @@ public class Vex extends Monster { this.setDropChance(EquipmentSlot.MAINHAND, 0.0F); } - private class VexMoveControl extends MoveControl { + private class VexMoveControl extends net.pl3x.purpur.controller.FlyingMoveControllerWASD { // Purpur public VexMoveControl(Vex entityvex) { super(entityvex); } @Override - public void tick() { + public void vanillaTick() { // Purpur if (this.operation == MoveControl.Operation.MOVE_TO) { Vec3 vec3d = new Vec3(this.wantedX - Vex.this.getX(), this.wantedY - Vex.this.getY(), this.wantedZ - Vex.this.getZ()); double d0 = vec3d.length(); @@ -231,7 +272,7 @@ public class Vex extends Monster { this.operation = MoveControl.Operation.WAIT; Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().scale(0.5D)); } else { - Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3d.scale(this.speedModifier * 0.05D / d0))); + Vex.this.setDeltaMovement(Vex.this.getDeltaMovement().add(vec3d.scale(this.getSpeedModifier() * 0.05D / d0))); // Purpur if (Vex.this.getTarget() == null) { Vec3 vec3d1 = Vex.this.getDeltaMovement(); diff --git a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java index 51082fb81477b96c778796e8daf288b366cecf22..a3b1332a92824255b807adc9a5a1d29569e7073b 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Vindicator.java +++ b/src/main/java/net/minecraft/world/entity/monster/Vindicator.java @@ -57,14 +57,28 @@ public class Vindicator extends AbstractIllager { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.vindicatorRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.vindicatorRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(1, new Vindicator.VindicatorBreakDoorGoal(this)); this.goalSelector.addGoal(2, new AbstractIllager.RaiderOpenDoorGoal(this)); this.goalSelector.addGoal(3, new Raider.HoldGroundAttackGoal(this, 10.0F)); this.goalSelector.addGoal(4, new Vindicator.VindicatorMeleeAttackGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur 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/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java index 8c3e8c12d7405ad388342e304430834a5fad12a9..e70fb661c62add74cdbe9fc9ef1e3143e96333b2 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Witch.java +++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java @@ -60,6 +60,18 @@ public class Witch extends Raider implements RangedAttackMob { super(type, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.witchRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.witchRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { super.registerGoals(); @@ -68,10 +80,12 @@ public class Witch extends Raider implements RangedAttackMob { }); this.attackPlayersGoal = new NearestAttackableWitchTargetGoal<>(this, Player.class, 10, true, false, (Predicate) null); this.goalSelector.addGoal(1, new FloatGoal(this)); + this.goalSelector.addGoal(1, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.goalSelector.addGoal(2, new RangedAttackGoal(this, 1.0D, 60, 10.0F)); this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D)); this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(3, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[]{Raider.class})); this.targetSelector.addGoal(2, this.healRaidersGoal); this.targetSelector.addGoal(3, this.attackPlayersGoal); diff --git a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java index f9bc07be70fae9aced51a69bccb5eda309187a47..4cea4ba127dc036ce5d585323a25bbcf06bd46a6 100644 --- a/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java +++ b/src/main/java/net/minecraft/world/entity/monster/WitherSkeleton.java @@ -34,6 +34,18 @@ public class WitherSkeleton extends AbstractSkeleton { this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.witherSkeletonRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.witherSkeletonRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractPiglin.class, true)); diff --git a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java index 056c0e66d2f90850906c78a25d759f22c20e4d35..8fd4e26ebe0527fd8a69b15095dd4091fcdde206 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Zoglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/Zoglin.java @@ -67,6 +67,18 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { this.xpReward = 5; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.zoglinRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.zoglinRidableInWater; + } + // Purpur end + @Override protected Brain.Provider brainProvider() { return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); @@ -89,11 +101,11 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { } private static void initIdleActivity(Brain brain) { - brain.addActivity(Activity.IDLE, 10, ImmutableList.of(new StartAttacking<>(Zoglin::findNearestValidAttackTarget), new RunSometimes(new SetEntityLookTarget(8.0F), UniformInt.of(30, 60)), new RunOne(ImmutableList.of(Pair.of(new RandomStroll(0.4F), 2), Pair.of(new SetWalkTargetFromLookTarget(0.4F, 3), 2), Pair.of(new DoNothing(30, 60), 1))))); + brain.addActivity(Activity.IDLE, 10, ImmutableList.of(new StartAttacking<>(Zoglin::findNearestValidAttackTarget), new RunSometimes<>(new SetEntityLookTarget(8.0F), UniformInt.of(30, 60)), new RunOne<>(ImmutableList.of(Pair.of(new RandomStroll(0.4F), 2), Pair.of(new SetWalkTargetFromLookTarget(0.4F, 3), 2), Pair.of(new DoNothing(30, 60), 1))))); // Purpur - decompile fix } private static void initFightActivity(Brain brain) { - brain.addActivityAndRemoveMemoryWhenStopped(Activity.FIGHT, 10, ImmutableList.of(new SetWalkTargetFromAttackTargetIfTargetOutOfReach(1.0F), new RunIf<>(Zoglin::isAdult, new MeleeAttack(40)), new RunIf<>(Zoglin::isBaby, new MeleeAttack(15)), new StopAttackingIfTargetInvalid()), MemoryModuleType.ATTACK_TARGET); + brain.addActivityAndRemoveMemoryWhenStopped(Activity.FIGHT, 10, ImmutableList.of(new SetWalkTargetFromAttackTargetIfTargetOutOfReach(1.0F), new RunIf<>(Zoglin::isAdult, new MeleeAttack(40)), new RunIf<>(Zoglin::isBaby, new MeleeAttack(15)), new StopAttackingIfTargetInvalid<>()), MemoryModuleType.ATTACK_TARGET); // Purpur - decompile fix } private Optional findNearestValidAttackTarget() { @@ -182,7 +194,7 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { @Override public Brain getBrain() { - return super.getBrain(); + return (Brain) super.getBrain(); // Purpur - decompile error } protected void updateActivity() { @@ -199,6 +211,7 @@ public class Zoglin extends Monster implements Enemy, HoglinBase { @Override protected void customServerAiStep() { this.level.getProfiler().push("zoglinBrain"); + if (getRider() == null) // Purpur - only use brain if no rider this.getBrain().tick((ServerLevel)this.level, this); this.level.getProfiler().pop(); this.updateActivity(); diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java index 6408e158745c20ab449c44a28420bc9b28e1efac..6dee348b4e1faec208e5144527ca3df0dab4f96e 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java +++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java @@ -107,11 +107,25 @@ public class Zombie extends Monster { this(EntityType.ZOMBIE, world); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.zombieRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.zombieRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur if (level.paperConfig.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); // Paper this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.targetSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); // Purpur this.addBehaviourGoals(); } diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java index 7a2e3d2ec86536c6caa5a0af0013474143566df8..d487b4cb2da18eac12ec3dc71997cdc1217a85f6 100644 --- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java +++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java @@ -74,6 +74,18 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { this.setVillagerData(this.getVillagerData().setProfession((VillagerProfession) Registry.VILLAGER_PROFESSION.getRandom(this.random))); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.zombieVillagerRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.zombieVillagerRidableInWater; + } + // Purpur end + @Override protected void defineSynchedData() { super.defineSynchedData(); diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java index 025d53ab0787d596f4c486b15d286b9547838e16..708ba2c64a0736a30e477017b46dc711948cfc3d 100644 --- a/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/ZombifiedPiglin.java @@ -58,6 +58,18 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob { this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.zombifiedPiglinRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.zombifiedPiglinRidableInWater; + } + // Purpur end + @Override public void setPersistentAngerTarget(@Nullable UUID uuid) { this.persistentAngerTarget = uuid; diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java index c510da19883d1aa79b2fc25e2d9c8f5cd8dd7bfa..ce7f7caa535aab1bf849b7e28c98c177e16d1ea3 100644 --- a/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/Hoglin.java @@ -67,6 +67,18 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { this.xpReward = 5; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.hoglinRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.hoglinRidableInWater; + } + // Purpur end + @Override public boolean canBeLeashed(Player player) { return !this.isLeashed(); @@ -123,12 +135,13 @@ public class Hoglin extends Animal implements Enemy, HoglinBase { @Override public Brain getBrain() { - return super.getBrain(); + return (Brain) super.getBrain(); // Purpur - decompile error } @Override protected void customServerAiStep() { this.level.getProfiler().push("hoglinBrain"); + if (getRider() == null) // Purpur - only use brain if no rider this.getBrain().tick((ServerLevel)this.level, this); this.level.getProfiler().pop(); HoglinAi.updateActivity(this); diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java index c7ad0e317c0c74e5ad3e08278c5e7b31c894413e..588209ab0a8263951bba9f0b7f46f18b8f7cd9e2 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/piglin/Piglin.java @@ -97,6 +97,18 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento this.xpReward = 5; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.piglinRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.piglinRidableInWater; + } + // Purpur end + @Override public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); @@ -292,6 +304,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento @Override protected void customServerAiStep() { this.level.getProfiler().push("piglinBrain"); + if (getRider() == null) // Purpur - only use brain if no rider this.getBrain().tick((ServerLevel) this.level, (Piglin) this); // CraftBukkit - decompile error this.level.getProfiler().pop(); PiglinAi.updateActivity(this); diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java index af579b2b6f6e18da70e67ce74431a57d9a1236dd..d01a8fe6dd5c84ea5b7370a90c0d57130b27e447 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java +++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinBrute.java @@ -40,6 +40,18 @@ public class PiglinBrute extends AbstractPiglin { this.xpReward = 20; } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.piglinBruteRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.piglinBruteRidableInWater; + } + // Purpur end + public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 50.0D).add(Attributes.MOVEMENT_SPEED, (double)0.35F).add(Attributes.ATTACK_DAMAGE, 7.0D); } @@ -69,7 +81,7 @@ public class PiglinBrute extends AbstractPiglin { @Override public Brain getBrain() { - return super.getBrain(); + return (Brain) super.getBrain(); // Purpur - decompile error } @Override @@ -85,6 +97,7 @@ public class PiglinBrute extends AbstractPiglin { @Override protected void customServerAiStep() { this.level.getProfiler().push("piglinBruteBrain"); + if (getRider() == null) // Purpur - only use brain if no rider this.getBrain().tick((ServerLevel)this.level, this); this.level.getProfiler().pop(); PiglinBruteAi.updateActivity(this); diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java index eaefa4f5f86f1c836aa29dd64ea786baced4b34d..f0f1f16971e9a0678afdccf6dcd92d8967c35346 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java @@ -155,6 +155,23 @@ public class Villager extends AbstractVillager implements ReputationEventHandler this.setVillagerData(this.getVillagerData().setType(type).setProfession(VillagerProfession.NONE)); } + // Purpur start + @Override + public boolean isRidable() { + return level.purpurConfig.villagerRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.villagerRidableInWater; + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(0, new net.pl3x.purpur.entity.ai.HasRider(this)); + } + // Purpur end + @Override public Brain getBrain() { return (Brain) super.getBrain(); // CraftBukkit - decompile error @@ -306,7 +323,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler if (!itemstack.is(Items.VILLAGER_SPAWN_EGG) && this.isAlive() && !this.isTrading() && !this.isSleeping()) { if (this.isBaby()) { this.setUnhappy(); - return InteractionResult.sidedSuccess(this.level.isClientSide); + return tryRide(player, hand); // Purpur } else { boolean flag = this.getOffers().isEmpty(); @@ -319,8 +336,9 @@ public class Villager extends AbstractVillager implements ReputationEventHandler } if (flag) { - return InteractionResult.sidedSuccess(this.level.isClientSide); + return tryRide(player, hand); // Purpur } else { + if (level.purpurConfig.villagerRidable && itemstack.isEmpty()) return tryRide(player, hand); // Purpur if (!this.level.isClientSide && !this.offers.isEmpty()) { this.startTrading(player); } diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java index c4f7c94255e4631a3c0355f9260132ba28296f50..d6c31596e21041a124a263054ccb6447829eccdd 100644 --- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java +++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java @@ -67,6 +67,18 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill //this.setDespawnDelay(48000); // CraftBukkit - set default from MobSpawnerTrader // Paper - move back to MobSpawnerTrader - Vanilla behavior is that only traders spawned by it have this value set. } + // Purpur - start + @Override + public boolean isRidable() { + return level.purpurConfig.wanderingTraderRidable; + } + + @Override + public boolean rideableUnderWater() { + return level.purpurConfig.wanderingTraderRidableInWater; + } + // Purpur end + @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); @@ -114,8 +126,9 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill } if (this.getOffers().isEmpty()) { - return InteractionResult.sidedSuccess(this.level.isClientSide); + return tryRide(player, hand); // Purpur } else { + if (level.purpurConfig.wanderingTraderRidable && itemstack.isEmpty()) return tryRide(player, hand); // Purpur if (!this.level.isClientSide) { this.setTradingPlayer(player); this.openTradingScreen(player, this.getDisplayName(), 1); diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java index e7a7de5ad9b64876df77e20465631ca8e5b19a4a..7b4f41d53373a56ad50cf4a9a761d87612600da7 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -193,6 +193,19 @@ public abstract class Player extends LivingEntity { } // CraftBukkit end + // Purpur start + 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 + public Player(Level world, BlockPos pos, float yaw, GameProfile profile) { super(EntityType.PLAYER, world); this.lastItemInMainHand = ItemStack.EMPTY; diff --git a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java index 85a509e4fc0e4b9f182585e17b7deab2fea7e6c0..f1a12b147d55e34d4f8374593640a311598cf1a6 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java +++ b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java @@ -27,6 +27,12 @@ public class LlamaSpit extends Projectile { this.setPos(owner.getX() - (double) (owner.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(owner.yBodyRot * 0.017453292F), owner.getEyeY() - 0.10000000149011612D, owner.getZ() + (double) (owner.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(owner.yBodyRot * 0.017453292F)); } + // Purpur start + public void super_tick() { + super.tick(); + } + // Purpur end + @Override public void tick() { super.tick(); diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java index 37356b36f0ae12d55150f399318581fa77c30cee..4e667be589fd95eb61e57a99448939a945c59e5e 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java @@ -35,7 +35,7 @@ public abstract class Projectile extends Entity { private boolean hasBeenShot; // CraftBukkit start - private boolean hitCancelled = false; + public boolean hitCancelled = false; // Purpur - private -> public // CraftBukkit end Projectile(EntityType type, Level world) { diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java index d0d87fcca78ea5c7853d693bc617c2bd6cfed487..773e42ff93e01b9f2db41dc4e8273525c5c162dc 100644 --- a/src/main/java/net/pl3x/purpur/PurpurConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java @@ -156,4 +156,9 @@ public class PurpurConfig { } return builder.build(); } + + public static String cannotRideMob = "You cannot mount that mob"; + private static void messages() { + cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); + } } diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java index 683ee20f08eac69238bea33021e35b1838c44a8b..3f91e7f49a1f00ff21fd65ea443af02729b7cc10 100644 --- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java @@ -92,4 +92,532 @@ public class PurpurWorldConfig { final Map value = PurpurConfig.getMap("world-settings." + worldName + "." + path, null); return value.isEmpty() ? fallback : value; } + + public boolean babiesAreRidable = true; + public boolean untamedTamablesAreRidable = true; + public boolean useNightVisionWhenRiding = false; + private void ridableSettings() { + babiesAreRidable = getBoolean("ridable-settings.babies-are-ridable", babiesAreRidable); + untamedTamablesAreRidable = getBoolean("ridable-settings.untamed-tamables-are-ridable", untamedTamablesAreRidable); + useNightVisionWhenRiding = getBoolean("ridable-settings.use-night-vision", useNightVisionWhenRiding); + } + + public boolean axolotlRidable = false; + private void axolotlSettings() { + axolotlRidable = getBoolean("mobs.axolotl.ridable", axolotlRidable); + } + + public boolean batRidable = false; + public boolean batRidableInWater = false; + public double batMaxY = 256D; + private void batSettings() { + batRidable = getBoolean("mobs.bat.ridable", batRidable); + batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater); + batMaxY = getDouble("mobs.bat.ridable-max-y", batMaxY); + } + + public boolean beeRidable = false; + public boolean beeRidableInWater = false; + public double beeMaxY = 256D; + private void beeSettings() { + beeRidable = getBoolean("mobs.bee.ridable", beeRidable); + beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); + beeMaxY = getDouble("mobs.bee.ridable-max-y", beeMaxY); + } + + public boolean blazeRidable = false; + public boolean blazeRidableInWater = false; + public double blazeMaxY = 256D; + private void blazeSettings() { + blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable); + blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater); + blazeMaxY = getDouble("mobs.blaze.ridable-max-y", blazeMaxY); + } + + public boolean catRidable = false; + public boolean catRidableInWater = false; + private void catSettings() { + catRidable = getBoolean("mobs.cat.ridable", catRidable); + catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); + } + + public boolean caveSpiderRidable = false; + public boolean caveSpiderRidableInWater = false; + private void caveSpiderSettings() { + caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable); + caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater); + } + + public boolean chickenRidable = false; + public boolean chickenRidableInWater = false; + private void chickenSettings() { + chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); + chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); + } + + public boolean codRidable = false; + private void codSettings() { + codRidable = getBoolean("mobs.cod.ridable", codRidable); + } + + public boolean cowRidable = false; + public boolean cowRidableInWater = false; + private void cowSettings() { + cowRidable = getBoolean("mobs.cow.ridable", cowRidable); + cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); + } + + public boolean creeperRidable = false; + public boolean creeperRidableInWater = false; + private void creeperSettings() { + creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); + creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); + } + + public boolean dolphinRidable = false; + public int dolphinSpitCooldown = 20; + public float dolphinSpitSpeed = 1.0F; + public float dolphinSpitDamage = 2.0F; + private void dolphinSettings() { + dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); + dolphinSpitCooldown = getInt("mobs.dolphin.spit.cooldown", dolphinSpitCooldown); + dolphinSpitSpeed = (float) getDouble("mobs.dolphin.spit.speed", dolphinSpitSpeed); + dolphinSpitDamage = (float) getDouble("mobs.dolphin.spit.damage", dolphinSpitDamage); + } + + public boolean donkeyRidableInWater = false; + private void donkeySettings() { + donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); + } + + public boolean drownedRidable = false; + public boolean drownedRidableInWater = false; + private void drownedSettings() { + drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); + drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); + } + + public boolean elderGuardianRidable = false; + private void elderGuardianSettings() { + elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable); + } + + public boolean enderDragonRidable = false; + public boolean enderDragonRidableInWater = false; + public double enderDragonMaxY = 256D; + private void enderDragonSettings() { + enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); + enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); + enderDragonMaxY = getDouble("mobs.ender_dragon.ridable-max-y", enderDragonMaxY); + } + + public boolean endermanRidable = false; + public boolean endermanRidableInWater = false; + private void endermanSettings() { + endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); + endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); + } + + public boolean endermiteRidable = false; + public boolean endermiteRidableInWater = false; + private void endermiteSettings() { + endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable); + endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater); + } + + public boolean evokerRidable = false; + public boolean evokerRidableInWater = false; + private void evokerSettings() { + evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); + evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); + } + + public boolean foxRidable = false; + public boolean foxRidableInWater = false; + private void foxSettings() { + foxRidable = getBoolean("mobs.fox.ridable", foxRidable); + foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); + } + + public boolean ghastRidable = false; + public boolean ghastRidableInWater = false; + public double ghastMaxY = 256D; + private void ghastSettings() { + ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable); + ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater); + ghastMaxY = getDouble("mobs.ghast.ridable-max-y", ghastMaxY); + } + + public boolean giantRidable = false; + public boolean giantRidableInWater = false; + private void giantSettings() { + giantRidable = getBoolean("mobs.giant.ridable", giantRidable); + giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater); + } + + public boolean glowSquidRidable = false; + private void glowSquidSettings() { + glowSquidRidable = getBoolean("mobs.glow_squid.ridable", glowSquidRidable); + } + + public boolean goatRidable = false; + public boolean goatRidableInWater = false; + private void goatSettings() { + goatRidable = getBoolean("mobs.goat.ridable", goatRidable); + goatRidableInWater = getBoolean("mobs.goat.ridable-in-water", goatRidableInWater); + } + + public boolean guardianRidable = false; + private void guardianSettings() { + guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable); + } + + public boolean hoglinRidable = false; + public boolean hoglinRidableInWater = false; + private void hoglinSettings() { + hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); + hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); + } + + public boolean horseRidableInWater = false; + private void horseSettings() { + horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); + } + + public boolean huskRidable = false; + public boolean huskRidableInWater = false; + private void huskSettings() { + huskRidable = getBoolean("mobs.husk.ridable", huskRidable); + huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater); + } + + public boolean illusionerRidable = false; + public boolean illusionerRidableInWater = false; + private void illusionerSettings() { + illusionerRidable = getBoolean("mobs.illusioner.ridable", illusionerRidable); + illusionerRidableInWater = getBoolean("mobs.illusioner.ridable-in-water", illusionerRidableInWater); + } + + public boolean ironGolemRidable = false; + public boolean ironGolemRidableInWater = false; + public boolean ironGolemCanSwim = false; + private void ironGolemSettings() { + ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); + ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); + ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); + } + + public boolean llamaRidable = false; + public boolean llamaRidableInWater = false; + private void llamaSettings() { + llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); + llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); + } + + public boolean magmaCubeRidable = false; + public boolean magmaCubeRidableInWater = false; + private void magmaCubeSettings() { + magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable); + magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater); + } + + public boolean mooshroomRidable = false; + public boolean mooshroomRidableInWater = false; + private void mooshroomSettings() { + mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); + mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); + } + + public boolean muleRidableInWater = false; + private void muleSettings() { + muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); + } + + public boolean ocelotRidable = false; + public boolean ocelotRidableInWater = false; + private void ocelotSettings() { + ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); + ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); + } + + public boolean pandaRidable = false; + public boolean pandaRidableInWater = false; + private void pandaSettings() { + pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); + pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); + } + + public boolean parrotRidable = false; + public boolean parrotRidableInWater = false; + public double parrotMaxY = 256D; + private void parrotSettings() { + parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable); + parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater); + parrotMaxY = getDouble("mobs.parrot.ridable-max-y", parrotMaxY); + } + + public boolean phantomRidable = false; + public boolean phantomRidableInWater = false; + public double phantomMaxY = 256D; + public float phantomFlameDamage = 1.0F; + public int phantomFlameFireTime = 8; + public boolean phantomAllowGriefing = false; + private void phantomSettings() { + phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); + phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); + phantomMaxY = getDouble("mobs.phantom.ridable-max-y", phantomMaxY); + phantomFlameDamage = (float) getDouble("mobs.phantom.flames.damage", phantomFlameDamage); + phantomFlameFireTime = getInt("mobs.phantom.flames.fire-time", phantomFlameFireTime); + phantomAllowGriefing = getBoolean("mobs.phantom.allow-griefing", phantomAllowGriefing); + } + + public boolean pigRidable = false; + public boolean pigRidableInWater = false; + private void pigSettings() { + pigRidable = getBoolean("mobs.pig.ridable", pigRidable); + pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); + } + + public boolean piglinRidable = false; + public boolean piglinRidableInWater = false; + private void piglinSettings() { + piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); + piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); + } + + public boolean piglinBruteRidable = false; + public boolean piglinBruteRidableInWater = false; + private void piglinBruteSettings() { + piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable); + piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater); + } + + public boolean pillagerRidable = false; + public boolean pillagerRidableInWater = false; + private void pillagerSettings() { + pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); + pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); + } + + public boolean polarBearRidable = false; + public boolean polarBearRidableInWater = false; + private void polarBearSettings() { + polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); + polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); + } + + public boolean pufferfishRidable = false; + private void pufferfishSettings() { + pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable); + } + + public boolean rabbitRidable = false; + public boolean rabbitRidableInWater = false; + private void rabbitSettings() { + rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); + rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); + } + + public boolean ravagerRidable = false; + public boolean ravagerRidableInWater = false; + private void ravagerSettings() { + ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); + ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); + } + + public boolean salmonRidable = false; + private void salmonSettings() { + salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable); + } + + public boolean sheepRidable = false; + public boolean sheepRidableInWater = false; + private void sheepSettings() { + sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); + sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); + } + + public boolean shulkerRidable = false; + public boolean shulkerRidableInWater = false; + private void shulkerSettings() { + shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable); + shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater); + } + + public boolean silverfishRidable = false; + public boolean silverfishRidableInWater = false; + private void silverfishSettings() { + silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); + silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); + } + + public boolean skeletonRidable = false; + public boolean skeletonRidableInWater = false; + private void skeletonSettings() { + skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); + skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); + } + + public boolean skeletonHorseRidableInWater = false; + public boolean skeletonHorseCanSwim = false; + private void skeletonHorseSettings() { + skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater); + skeletonHorseCanSwim = getBoolean("mobs.skeleton_horse.can-swim", skeletonHorseCanSwim); + } + + public boolean slimeRidable = false; + public boolean slimeRidableInWater = false; + private void slimeSettings() { + slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable); + slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater); + } + + public boolean snowGolemRidable = false; + public boolean snowGolemRidableInWater = false; + public boolean snowGolemLeaveTrailWhenRidden = false; + private void snowGolemSettings() { + snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); + snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); + snowGolemLeaveTrailWhenRidden = getBoolean("mobs.snow_golem.leave-trail-when-ridden", snowGolemLeaveTrailWhenRidden); + } + + public boolean squidRidable = false; + private void squidSettings() { + squidRidable = getBoolean("mobs.squid.ridable", squidRidable); + } + + public boolean spiderRidable = false; + public boolean spiderRidableInWater = false; + private void spiderSettings() { + spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable); + spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater); + } + + public boolean strayRidable = false; + public boolean strayRidableInWater = false; + private void straySettings() { + strayRidable = getBoolean("mobs.stray.ridable", strayRidable); + strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater); + } + + public boolean striderRidable = false; + public boolean striderRidableInWater = false; + private void striderSettings() { + striderRidable = getBoolean("mobs.strider.ridable", striderRidable); + striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); + } + + public boolean traderLlamaRidable = false; + public boolean traderLlamaRidableInWater = false; + private void traderLlamaSettings() { + traderLlamaRidable = getBoolean("mobs.trader_llama.ridable", traderLlamaRidable); + traderLlamaRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", traderLlamaRidableInWater); + } + + public boolean tropicalFishRidable = false; + private void tropicalFishSettings() { + tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable); + } + + public boolean turtleRidable = false; + public boolean turtleRidableInWater = false; + private void turtleSettings() { + turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); + turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); + } + + public boolean vexRidable = false; + public boolean vexRidableInWater = false; + public double vexMaxY = 256D; + private void vexSettings() { + vexRidable = getBoolean("mobs.vex.ridable", vexRidable); + vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater); + vexMaxY = getDouble("mobs.vex.ridable-max-y", vexMaxY); + } + + public boolean villagerRidable = false; + public boolean villagerRidableInWater = false; + private void villagerSettings() { + villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); + villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); + } + + public boolean vindicatorRidable = false; + public boolean vindicatorRidableInWater = false; + private void vindicatorSettings() { + vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable); + vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater); + } + + public boolean wanderingTraderRidable = false; + public boolean wanderingTraderRidableInWater = false; + private void wanderingTraderSettings() { + wanderingTraderRidable = getBoolean("mobs.wandering_trader.ridable", wanderingTraderRidable); + wanderingTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", wanderingTraderRidableInWater); + } + + public boolean witchRidable = false; + public boolean witchRidableInWater = false; + private void witchSettings() { + witchRidable = getBoolean("mobs.witch.ridable", witchRidable); + witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater); + } + + public boolean witherRidable = false; + public boolean witherRidableInWater = false; + public double witherMaxY = 256D; + private void witherSettings() { + witherRidable = getBoolean("mobs.wither.ridable", witherRidable); + witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); + witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY); + } + + public boolean witherSkeletonRidable = false; + public boolean witherSkeletonRidableInWater = false; + private void witherSkeletonSettings() { + witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable); + witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater); + } + + public boolean wolfRidable = false; + public boolean wolfRidableInWater = false; + private void wolfSettings() { + wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); + wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); + } + + public boolean zoglinRidable = false; + public boolean zoglinRidableInWater = false; + private void zoglinSettings() { + zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable); + zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater); + } + + public boolean zombieRidable = false; + public boolean zombieRidableInWater = false; + private void zombieSettings() { + zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); + zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); + } + + public boolean zombieHorseRidableInWater = false; + public boolean zombieHorseCanSwim = false; + private void zombieHorseSettings() { + zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater); + zombieHorseCanSwim = getBoolean("mobs.zombie_horse.can-swim", zombieHorseCanSwim); + } + + public boolean zombieVillagerRidable = false; + public boolean zombieVillagerRidableInWater = false; + private void zombieVillagerSettings() { + zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); + zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); + } + + public boolean zombifiedPiglinRidable = false; + public boolean zombifiedPiglinRidableInWater = false; + private void zombifiedPiglinSettings() { + zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); + zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); + } } diff --git a/src/main/java/net/pl3x/purpur/controller/FlyingMoveControllerWASD.java b/src/main/java/net/pl3x/purpur/controller/FlyingMoveControllerWASD.java new file mode 100644 index 0000000000000000000000000000000000000000..d0f6c7d47d158b49fb6a5fe2a7480ffd53f844c5 --- /dev/null +++ b/src/main/java/net/pl3x/purpur/controller/FlyingMoveControllerWASD.java @@ -0,0 +1,61 @@ +package net.pl3x.purpur.controller; + +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; + +public class FlyingMoveControllerWASD extends MoveControllerWASD { + protected final float groundSpeedModifier; + protected int tooHighCooldown = 0; + protected boolean setGravityFlag = true; + + public FlyingMoveControllerWASD(Mob entity) { + this(entity, 1.0F); + } + + public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier) { + this(entity, groundSpeedModifier, true); + } + + public FlyingMoveControllerWASD(Mob entity, float groundSpeedModifier, boolean setGravityFlag) { + super(entity); + this.groundSpeedModifier = groundSpeedModifier; + this.setGravityFlag = setGravityFlag; + } + + @Override + public void purpurTick(Player rider) { + float forward = Math.max(0.0F, rider.getForwardMot()); + float vertical = forward == 0.0F ? 0.0F : -(rider.xRotO / 45.0F); + float strafe = rider.getStrafeMot(); + + if (rider.jumping && spacebarEvent(entity)) { + entity.onSpacebar(); + } + + if (entity.getY() >= entity.getMaxY() || --tooHighCooldown > 0) { + tooHighCooldown = 60; + entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, -0.05D, 0.0D)); + vertical = 0.0F; + } + + setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED)); + float speed = (float) getSpeedModifier(); + + if (entity.onGround) { + speed *= groundSpeedModifier; // TODO = fix this! + } + + if (setGravityFlag) { + entity.setNoGravity(forward > 0); + } + + entity.setSpeed(speed); + entity.setVerticalMot(vertical); + entity.setStrafeMot(strafe); + entity.setForwardMot(forward); + + setForward(entity.getForwardMot()); + setStrafe(entity.getStrafeMot()); + } +} diff --git a/src/main/java/net/pl3x/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java b/src/main/java/net/pl3x/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java new file mode 100644 index 0000000000000000000000000000000000000000..79d23cb66bc825fe78ecc249f12ef8b9851e09f8 --- /dev/null +++ b/src/main/java/net/pl3x/purpur/controller/FlyingWithSpacebarMoveControllerWASD.java @@ -0,0 +1,61 @@ +package net.pl3x.purpur.controller; + +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; + +public class FlyingWithSpacebarMoveControllerWASD extends FlyingMoveControllerWASD { + public FlyingWithSpacebarMoveControllerWASD(Mob entity) { + super(entity); + } + + public FlyingWithSpacebarMoveControllerWASD(Mob entity, float groundSpeedModifier) { + super(entity, groundSpeedModifier); + } + + @Override + public void purpurTick(Player rider) { + float forward = rider.getForwardMot(); + float strafe = rider.getStrafeMot() * 0.5F; + float vertical = 0; + + if (forward < 0.0F) { + forward *= 0.5F; + strafe *= 0.5F; + } + + float speed = (float) entity.getAttributeValue(Attributes.MOVEMENT_SPEED); + + if (entity.onGround) { + speed *= groundSpeedModifier; + } + + if (rider.jumping && spacebarEvent(entity) && !entity.onSpacebar()) { + entity.setNoGravity(true); + vertical = 1.0F; + } else { + entity.setNoGravity(false); + } + + if (entity.getY() >= entity.getMaxY() || --tooHighCooldown > 0) { + tooHighCooldown = 60; + entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, -0.2D, 0.0D)); + vertical = 0.0F; + } + + setSpeedModifier(speed); + entity.setSpeed((float) getSpeedModifier()); + entity.setVerticalMot(vertical); + entity.setStrafeMot(strafe); + entity.setForwardMot(forward); + + setForward(entity.getForwardMot()); + setStrafe(entity.getStrafeMot()); + + Vec3 mot = entity.getDeltaMovement(); + if (mot.y > 0.2D) { + entity.setDeltaMovement(mot.x, 0.2D, mot.z); + } + } +} diff --git a/src/main/java/net/pl3x/purpur/controller/LookControllerWASD.java b/src/main/java/net/pl3x/purpur/controller/LookControllerWASD.java new file mode 100644 index 0000000000000000000000000000000000000000..b93fe26c357930d5c0242da8137443feb216f9dd --- /dev/null +++ b/src/main/java/net/pl3x/purpur/controller/LookControllerWASD.java @@ -0,0 +1,76 @@ +package net.pl3x.purpur.controller; + + +import net.minecraft.network.protocol.game.ClientboundMoveEntityPacket; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.control.LookControl; +import net.minecraft.world.entity.player.Player; + +public class LookControllerWASD extends LookControl { + protected final Mob entity; + private float yOffset = 0; + private float xOffset = 0; + + public LookControllerWASD(Mob entity) { + super(entity); + this.entity = entity; + } + + // tick + @Override + public void tick() { + if (entity.getRider() != null) { + purpurTick(entity.getRider()); + } else { + vanillaTick(); + } + } + + protected void purpurTick(Player rider) { + setYawPitch(rider.getYRot(), rider.getXRot()); + } + + public void vanillaTick() { + super.tick(); + } + + public void setYawPitch(float yRot, float xRot) { + entity.setXRot(normalizePitch(xRot + xOffset)); + entity.setYRot(normalizeYaw(yRot + yOffset)); + entity.setYHeadRot(entity.getYRot()); + entity.xRotO = entity.getXRot(); + entity.yRotO = entity.getYRot(); + + entity.tracker.broadcast(new ClientboundMoveEntityPacket + .PosRot(entity.getId(), + (short) 0, (short) 0, (short) 0, + (byte) Mth.floor(entity.getYRot() * 256.0F / 360.0F), + (byte) Mth.floor(entity.getXRot() * 256.0F / 360.0F), + entity.onGround)); + } + + public void setOffsets(float yaw, float pitch) { + yOffset = yaw; + xOffset = pitch; + } + + public float normalizeYaw(float yaw) { + yaw %= 360.0f; + if (yaw >= 180.0f) { + yaw -= 360.0f; + } else if (yaw < -180.0f) { + yaw += 360.0f; + } + return yaw; + } + + public float normalizePitch(float pitch) { + if (pitch > 90.0f) { + pitch = 90.0f; + } else if (pitch < -90.0f) { + pitch = -90.0f; + } + return pitch; + } +} diff --git a/src/main/java/net/pl3x/purpur/controller/MoveControllerWASD.java b/src/main/java/net/pl3x/purpur/controller/MoveControllerWASD.java new file mode 100644 index 0000000000000000000000000000000000000000..4a3a1eca04a58682d5aeb720832bad5cc8ba2d9c --- /dev/null +++ b/src/main/java/net/pl3x/purpur/controller/MoveControllerWASD.java @@ -0,0 +1,89 @@ +package net.pl3x.purpur.controller; + +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.ai.control.MoveControl; +import net.minecraft.world.entity.player.Player; +import net.pl3x.purpur.event.entity.RidableSpacebarEvent; + +public class MoveControllerWASD extends MoveControl { + protected final Mob entity; + private final double speedModifier; + + public MoveControllerWASD(Mob entity) { + this(entity, 1.0D); + } + + public MoveControllerWASD(Mob entity, double speedModifier) { + super(entity); + this.entity = entity; + this.speedModifier = speedModifier; + } + + @Override + public boolean hasWanted() { + return entity.getRider() != null ? strafeForwards != 0 || strafeRight != 0 : super.hasWanted(); + } + + @Override + public void tick() { + if (entity.getRider() != null) { + purpurTick(entity.getRider()); + } else { + vanillaTick(); + } + } + + public void vanillaTick() { + super.tick(); + } + + public void purpurTick(Player rider) { + float forward = rider.getForwardMot() * 0.5F; + float strafe = rider.getStrafeMot() * 0.25F; + + if (forward <= 0.0F) { + forward *= 0.5F; + } + + float yawOffset = 0; + if (strafe != 0) { + if (forward == 0) { + yawOffset += strafe > 0 ? -90 : 90; + forward = Math.abs(strafe * 2); + } else { + yawOffset += strafe > 0 ? -30 : 30; + strafe /= 2; + if (forward < 0) { + yawOffset += strafe > 0 ? -110 : 110; + forward *= -1; + } + } + } else if (forward < 0) { + yawOffset -= 180; + forward *= -1; + } + + ((LookControllerWASD) entity.getLookControl()).setOffsets(yawOffset, 0); + + if (rider.jumping && spacebarEvent(entity) && !entity.onSpacebar() && entity.onGround) { + entity.jumpFromGround(); + } + + setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED) * speedModifier); + + entity.setSpeed((float) getSpeedModifier()); + entity.setForwardMot(forward); + + setForward(entity.getForwardMot()); + setStrafe(entity.getStrafeMot()); + } + + public static boolean spacebarEvent(Mob entity) { + if (RidableSpacebarEvent.getHandlerList().getRegisteredListeners().length > 0) { + return new RidableSpacebarEvent(entity.getBukkitEntity()).callEvent(); + } else { + return true; + } + } +} diff --git a/src/main/java/net/pl3x/purpur/controller/WaterMoveControllerWASD.java b/src/main/java/net/pl3x/purpur/controller/WaterMoveControllerWASD.java new file mode 100644 index 0000000000000000000000000000000000000000..c9b24eeaa4221c56dc5030ad4574499e1a03727d --- /dev/null +++ b/src/main/java/net/pl3x/purpur/controller/WaterMoveControllerWASD.java @@ -0,0 +1,50 @@ +package net.pl3x.purpur.controller; + +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; + +public class WaterMoveControllerWASD extends MoveControllerWASD { + private final double speedModifier; + + public WaterMoveControllerWASD(Mob entity) { + this(entity, 1.0D); + } + + public WaterMoveControllerWASD(Mob entity, double speedModifier) { + super(entity); + this.speedModifier = speedModifier; + } + + @Override + public void purpurTick(Player rider) { + float forward = rider.getForwardMot(); + float strafe = rider.getStrafeMot() * 0.5F; // strafe slower by default + float vertical = -(rider.xRotO / 90); + + if (forward == 0.0F) { + // strafe slower if not moving forward + strafe *= 0.5F; + // do not move vertically if not moving forward + vertical = 0.0F; + } else if (forward < 0.0F) { + // water animals can't swim backwards + forward = 0.0F; + vertical = 0.0F; + } + + if (rider.jumping && spacebarEvent(entity)) { + entity.onSpacebar(); + } + + setSpeedModifier(entity.getAttributeValue(Attributes.MOVEMENT_SPEED) * speedModifier); + entity.setSpeed((float) getSpeedModifier() * 0.1F); + + entity.setForwardMot(forward * (float) speedModifier); + entity.setStrafeMot(strafe * (float) speedModifier); + entity.setVerticalMot(vertical * (float) speedModifier); + + setForward(entity.getForwardMot()); + setStrafe(entity.getStrafeMot()); + } +} diff --git a/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java b/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java new file mode 100644 index 0000000000000000000000000000000000000000..fda24d4ecff91cc28d2a7a45fbb55ea734261153 --- /dev/null +++ b/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java @@ -0,0 +1,99 @@ +package net.pl3x.purpur.entity; + +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.animal.Dolphin; +import net.minecraft.world.entity.projectile.LlamaSpit; +import net.minecraft.world.entity.projectile.ProjectileUtil; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class DolphinSpit extends LlamaSpit { + public LivingEntity dolphin; + public int ticksLived; + + public DolphinSpit(EntityType type, Level world) { + super(type, world); + } + + public DolphinSpit(Level world, Dolphin dolphin) { + this(EntityType.LLAMA_SPIT, world); + setOwner(dolphin.getRider() != null ? dolphin.getRider() : dolphin); + this.dolphin = dolphin; + this.setPos( + dolphin.getX() - (double) (dolphin.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(dolphin.yBodyRot * 0.017453292F), + dolphin.getEyeY() - 0.10000000149011612D, + dolphin.getZ() + (double) (dolphin.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(dolphin.yBodyRot * 0.017453292F)); + } + + public void tick() { + super_tick(); + + Vec3 mot = this.getDeltaMovement(); + HitResult hitResult = ProjectileUtil.getHitResult(this, this::canHitEntity); + + this.preOnHit(hitResult); + + double x = this.getX() + mot.x; + double y = this.getY() + mot.y; + double z = this.getZ() + mot.z; + + this.updateRotation(); + + Vec3 motDouble = mot.scale(2.0); + for (int i = 0; i < 5; i++) { + ((ServerLevel) level).sendParticles(null, ParticleTypes.BUBBLE, + getX() + random.nextFloat() / 2 - 0.25F, + getY() + random.nextFloat() / 2 - 0.25F, + getZ() + random.nextFloat() / 2 - 0.25F, + 0, motDouble.x(), motDouble.y(), motDouble.z(), 0.1D, true); + } + + if (++ticksLived > 20) { + this.discard(); + } else { + this.setDeltaMovement(mot.scale(0.99D)); + if (!this.isNoGravity()) { + this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.06D, 0.0D)); + } + + this.setPos(x, y, z); + } + } + + @Override + public void shoot(double x, double y, double z, float speed, float inaccuracy) { + setDeltaMovement(new Vec3(x, y, z).normalize().add( + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy) + .scale(speed)); + } + + @Override + protected void onHitEntity(EntityHitResult entityHitResult) { + Entity shooter = this.getOwner(); + if (shooter instanceof LivingEntity) { + entityHitResult.getEntity().hurt(DamageSource.indirectMobAttack(this, (LivingEntity) shooter).setProjectile(), level.purpurConfig.dolphinSpitDamage); + } + } + + @Override + protected void onHitBlock(BlockHitResult blockHitResult) { + if (this.hitCancelled) { + return; + } + BlockState state = this.level.getBlockState(blockHitResult.getBlockPos()); + state.onProjectileHit(this.level, state, blockHitResult, this); + this.discard(); + } +} diff --git a/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java b/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java new file mode 100644 index 0000000000000000000000000000000000000000..57b59a12f609fda0787d49575724762362ce12af --- /dev/null +++ b/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java @@ -0,0 +1,114 @@ +package net.pl3x.purpur.entity; + +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.monster.Phantom; +import net.minecraft.world.entity.projectile.LlamaSpit; +import net.minecraft.world.entity.projectile.ProjectileUtil; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class PhantomFlames extends LlamaSpit { + public Phantom phantom; + public int ticksLived; + public boolean canGrief = false; + + public PhantomFlames(EntityType type, Level world) { + super(type, world); + } + + public PhantomFlames(Level world, Phantom phantom) { + this(EntityType.LLAMA_SPIT, world); + setOwner(phantom.getRider() != null ? phantom.getRider() : phantom); + this.phantom = phantom; + this.setPos( + phantom.getX() - (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.sin(phantom.yBodyRot * 0.017453292F), + phantom.getEyeY() - 0.10000000149011612D, + phantom.getZ() + (double) (phantom.getBbWidth() + 1.0F) * 0.5D * (double) Mth.cos(phantom.yBodyRot * 0.017453292F)); + } + + public void tick() { + super_tick(); + + Vec3 mot = this.getDeltaMovement(); + HitResult hitResult = ProjectileUtil.getHitResult(this, this::canHitEntity); + + this.preOnHit(hitResult); + + double x = this.getX() + mot.x; + double y = this.getY() + mot.y; + double z = this.getZ() + mot.z; + + this.updateRotation(); + + Vec3 motDouble = mot.scale(2.0); + for (int i = 0; i < 5; i++) { + ((ServerLevel) level).sendParticles(null, ParticleTypes.FLAME, + getX() + random.nextFloat() / 2 - 0.25F, + getY() + random.nextFloat() / 2 - 0.25F, + getZ() + random.nextFloat() / 2 - 0.25F, + 0, motDouble.x(), motDouble.y(), motDouble.z(), 0.1D, true); + } + + if (++ticksLived > 20) { + this.discard(); + } else if (this.level.getBlockStates(this.getBoundingBox()).noneMatch(BlockBehaviour.BlockStateBase::isAir)) { + this.discard(); + } else if (this.isInWaterOrBubble()) { + this.discard(); + } else { + this.setDeltaMovement(mot.scale(0.99D)); + if (!this.isNoGravity()) { + this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.06D, 0.0D)); + } + + this.setPos(x, y, z); + } + } + + @Override + public void shoot(double x, double y, double z, float speed, float inaccuracy) { + setDeltaMovement(new Vec3(x, y, z).normalize().add( + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, + random.nextGaussian() * (double) 0.0075F * (double) inaccuracy) + .scale(speed)); + } + + @Override + protected void onHitEntity(EntityHitResult entityHitResult) { + Entity shooter = this.getOwner(); + if (shooter instanceof LivingEntity) { + Entity target = entityHitResult.getEntity(); + if (canGrief || (target instanceof LivingEntity && !(target instanceof ArmorStand))) { + target.hurt(DamageSource.indirectMobAttack(this, (LivingEntity) shooter).setProjectile(), level.purpurConfig.phantomFlameDamage); + if (level.purpurConfig.phantomFlameFireTime > 0) { + target.setSecondsOnFire(level.purpurConfig.phantomFlameFireTime); + } + } + } + } + + @Override + protected void onHitBlock(BlockHitResult blockHitResult) { + if (this.hitCancelled) { + return; + } + if (this.canGrief) { + BlockState state = this.level.getBlockState(blockHitResult.getBlockPos()); + state.onProjectileHit(this.level, state, blockHitResult, this); + } + this.discard(); + } +} diff --git a/src/main/java/net/pl3x/purpur/entity/ai/HasRider.java b/src/main/java/net/pl3x/purpur/entity/ai/HasRider.java new file mode 100644 index 0000000000000000000000000000000000000000..bd48d16bbe3d9b10541a5e65c037926b3a58af22 --- /dev/null +++ b/src/main/java/net/pl3x/purpur/entity/ai/HasRider.java @@ -0,0 +1,20 @@ +package net.pl3x.purpur.entity.ai; + +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.ai.goal.Goal; + +import java.util.EnumSet; + +public class HasRider extends Goal { + public final Mob entity; + + public HasRider(Mob entity) { + this.entity = entity; + setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK, Flag.TARGET, Flag.UNKNOWN_BEHAVIOR)); + } + + @Override + public boolean canUse() { + return entity.getRider() != null; + } +} diff --git a/src/main/java/net/pl3x/purpur/entity/ai/HorseHasRider.java b/src/main/java/net/pl3x/purpur/entity/ai/HorseHasRider.java new file mode 100644 index 0000000000000000000000000000000000000000..8eefb7b7eb33aecf48ac206d3f0139e0cf342e35 --- /dev/null +++ b/src/main/java/net/pl3x/purpur/entity/ai/HorseHasRider.java @@ -0,0 +1,17 @@ +package net.pl3x.purpur.entity.ai; + +import net.minecraft.world.entity.animal.horse.AbstractHorse; + +public class HorseHasRider extends HasRider { + public final AbstractHorse horse; + + public HorseHasRider(AbstractHorse entity) { + super(entity); + this.horse = entity; + } + + @Override + public boolean canUse() { + return super.canUse() && horse.isSaddled(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 8ce49478441e77cedf5148ecb81d78b32660329e..fb5cd6fe7903f3f96af1abb55832bafb7ca7f4a8 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -1234,4 +1234,27 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { return getHandle().isTicking(); } // Paper end + + // Purpur start + @Override + public org.bukkit.entity.Player getRider() { + Player rider = getHandle().getRider(); + return rider != null ? (org.bukkit.entity.Player) rider.getBukkitEntity() : null; + } + + @Override + public boolean hasRider() { + return getHandle().getRider() != null; + } + + @Override + public boolean isRidable() { + return getHandle().isRidable(); + } + + @Override + public boolean isRidableInWater() { + return getHandle().rideableUnderWater(); + } + // Purpur end } diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index ec00da61e422384276442fa23e496dc078f49d1a..0238bea72b9d4d6b92a03ec59c8697cbe88dbf5a 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -537,6 +537,15 @@ public class CraftEventFactory { } craftServer.getPluginManager().callEvent(event); + // Purpur start + if (who != null) { + switch (action) { + case LEFT_CLICK_BLOCK, LEFT_CLICK_AIR -> who.processClick(InteractionHand.MAIN_HAND); + case RIGHT_CLICK_BLOCK, RIGHT_CLICK_AIR -> who.processClick(InteractionHand.OFF_HAND); + } + } + // Purpur end + return event; } @@ -959,6 +968,7 @@ public class CraftEventFactory { damageCause = DamageCause.ENTITY_EXPLOSION; } event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), entity.getBukkitEntity(), damageCause, modifiers, modifierFunctions); + damager.processClick(InteractionHand.MAIN_HAND); // Purpur } event.setCancelled(cancelled); @@ -1042,6 +1052,7 @@ public class CraftEventFactory { if (!event.isCancelled()) { event.getEntity().setLastDamageCause(event); } + damager.getHandle().processClick(InteractionHand.MAIN_HAND); // Purpur return event; } @@ -1093,6 +1104,7 @@ public class CraftEventFactory { EntityDamageEvent event; if (damager != null) { event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, modifiers, modifierFunctions); + damager.processClick(InteractionHand.MAIN_HAND); // Purpur } else { event = new EntityDamageEvent(damagee.getBukkitEntity(), cause, modifiers, modifierFunctions); } diff --git a/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java b/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java index b2d510459bcf90a3611f3d91dae4ccc3d29b4079..2ddf338f40092f8ef1db3ea5c175300471566d51 100644 --- a/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java +++ b/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java @@ -37,7 +37,7 @@ public class VanillaMobGoalTest { } List> classes; - try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft").scan()) { + try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft", "net.pl3x.purpur.entity.ai").scan()) { // Purpur classes = scanResult.getSubclasses(net.minecraft.world.entity.ai.goal.Goal.class.getName()).loadClasses(); }