Move patches to unapplied

This commit is contained in:
Nassim Jahnke
2024-12-12 12:22:12 +01:00
parent ff75689b08
commit 45ddf764d9
821 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
--- a/net/minecraft/world/entity/AgeableMob.java
+++ b/net/minecraft/world/entity/AgeableMob.java
@@ -21,12 +21,38 @@
protected int age;
protected int forcedAge;
protected int forcedAgeTimer;
+ public boolean ageLocked; // CraftBukkit
protected AgeableMob(EntityType<? extends AgeableMob> type, Level world) {
super(type, world);
}
+ // Spigot start
@Override
+ public void inactiveTick()
+ {
+ super.inactiveTick();
+ if ( this.level().isClientSide || this.ageLocked )
+ { // CraftBukkit
+ this.refreshDimensions();
+ } else
+ {
+ int i = this.getAge();
+
+ if ( i < 0 )
+ {
+ ++i;
+ this.setAge( i );
+ } else if ( i > 0 )
+ {
+ --i;
+ this.setAge( i );
+ }
+ }
+ }
+ // Spigot end
+
+ @Override
public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) {
if (entityData == null) {
entityData = new AgeableMob.AgeableMobGroupData(true);
@@ -60,6 +86,7 @@
}
public void ageUp(int age, boolean overGrow) {
+ if (this.ageLocked) return; // Paper - Honor ageLock
int j = this.getAge();
int k = j;
@@ -104,6 +131,7 @@
super.addAdditionalSaveData(nbt);
nbt.putInt("Age", this.getAge());
nbt.putInt("ForcedAge", this.forcedAge);
+ nbt.putBoolean("AgeLocked", this.ageLocked); // CraftBukkit
}
@Override
@@ -111,6 +139,7 @@
super.readAdditionalSaveData(nbt);
this.setAge(nbt.getInt("Age"));
this.forcedAge = nbt.getInt("ForcedAge");
+ this.ageLocked = nbt.getBoolean("AgeLocked"); // CraftBukkit
}
@Override
@@ -125,7 +154,7 @@
@Override
public void aiStep() {
super.aiStep();
- if (this.level().isClientSide) {
+ if (this.level().isClientSide || this.ageLocked) { // CraftBukkit
if (this.forcedAgeTimer > 0) {
if (this.forcedAgeTimer % 4 == 0) {
this.level().addParticle(ParticleTypes.HAPPY_VILLAGER, this.getRandomX(1.0D), this.getRandomY() + 0.5D, this.getRandomZ(1.0D), 0.0D, 0.0D, 0.0D);

View File

@@ -0,0 +1,160 @@
--- a/net/minecraft/world/entity/AreaEffectCloud.java
+++ b/net/minecraft/world/entity/AreaEffectCloud.java
@@ -33,6 +33,12 @@
import net.minecraft.world.level.material.PushReaction;
import org.slf4j.Logger;
+// CraftBukkit start
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
+
public class AreaEffectCloud extends Entity implements TraceableEntity {
private static final Logger LOGGER = LogUtils.getLogger();
@@ -54,7 +60,7 @@
public float radiusOnUse;
public float radiusPerTick;
@Nullable
- private LivingEntity owner;
+ private net.minecraft.world.entity.LivingEntity owner;
@Nullable
public UUID ownerUUID;
@@ -145,7 +151,19 @@
this.duration = duration;
}
+ // Spigot start - copied from below
@Override
+ public void inactiveTick() {
+ super.inactiveTick();
+
+ if (this.tickCount >= this.waitTime + this.duration) {
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
+ return;
+ }
+ }
+ // Spigot end
+
+ @Override
public void tick() {
super.tick();
Level world = this.level();
@@ -200,7 +218,7 @@
private void serverTick(ServerLevel world) {
if (this.tickCount >= this.waitTime + this.duration) {
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
} else {
boolean flag = this.isWaiting();
boolean flag1 = this.tickCount < this.waitTime;
@@ -215,7 +233,7 @@
if (this.radiusPerTick != 0.0F) {
f += this.radiusPerTick;
if (f < 0.5F) {
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
return;
}
@@ -244,16 +262,17 @@
}
list.addAll(this.potionContents.customEffects());
- List<LivingEntity> list1 = this.level().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox());
+ List<net.minecraft.world.entity.LivingEntity> list1 = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, this.getBoundingBox());
if (!list1.isEmpty()) {
Iterator iterator1 = list1.iterator();
+ List<LivingEntity> entities = new java.util.ArrayList<LivingEntity>(); // CraftBukkit
while (iterator1.hasNext()) {
- LivingEntity entityliving = (LivingEntity) iterator1.next();
+ net.minecraft.world.entity.LivingEntity entityliving = (net.minecraft.world.entity.LivingEntity) iterator1.next();
if (!this.victims.containsKey(entityliving) && entityliving.isAffectedByPotions()) {
- Stream stream = list.stream();
+ Stream<MobEffectInstance> stream = list.stream(); // CraftBukkit - decompile error
Objects.requireNonNull(entityliving);
if (!stream.noneMatch(entityliving::canBeAffected)) {
@@ -262,6 +281,19 @@
double d2 = d0 * d0 + d1 * d1;
if (d2 <= (double) (f * f)) {
+ // CraftBukkit start
+ entities.add((LivingEntity) entityliving.getBukkitEntity());
+ }
+ }
+ }
+ }
+ {
+ org.bukkit.event.entity.AreaEffectCloudApplyEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callAreaEffectCloudApplyEvent(this, entities);
+ if (!event.isCancelled()) {
+ for (LivingEntity entity : event.getAffectedEntities()) {
+ if (entity instanceof CraftLivingEntity) {
+ net.minecraft.world.entity.LivingEntity entityliving = ((CraftLivingEntity) entity).getHandle();
+ // CraftBukkit end
this.victims.put(entityliving, this.tickCount + this.reapplicationDelay);
Iterator iterator2 = list.iterator();
@@ -271,14 +303,14 @@
if (((MobEffect) mobeffect1.getEffect().value()).isInstantenous()) {
((MobEffect) mobeffect1.getEffect().value()).applyInstantenousEffect(world, this, this.getOwner(), entityliving, mobeffect1.getAmplifier(), 0.5D);
} else {
- entityliving.addEffect(new MobEffectInstance(mobeffect1), this);
+ entityliving.addEffect(new MobEffectInstance(mobeffect1), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AREA_EFFECT_CLOUD); // CraftBukkit
}
}
if (this.radiusOnUse != 0.0F) {
f += this.radiusOnUse;
if (f < 0.5F) {
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
return;
}
@@ -288,7 +320,7 @@
if (this.durationOnUse != 0) {
this.duration += this.durationOnUse;
if (this.duration <= 0) {
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
return;
}
}
@@ -336,14 +368,14 @@
this.waitTime = waitTime;
}
- public void setOwner(@Nullable LivingEntity owner) {
+ public void setOwner(@Nullable net.minecraft.world.entity.LivingEntity owner) {
this.owner = owner;
this.ownerUUID = owner == null ? null : owner.getUUID();
}
@Nullable
@Override
- public LivingEntity getOwner() {
+ public net.minecraft.world.entity.LivingEntity getOwner() {
if (this.owner != null && !this.owner.isRemoved()) {
return this.owner;
} else {
@@ -353,10 +385,10 @@
if (world instanceof ServerLevel) {
ServerLevel worldserver = (ServerLevel) world;
Entity entity = worldserver.getEntity(this.ownerUUID);
- LivingEntity entityliving;
+ net.minecraft.world.entity.LivingEntity entityliving;
- if (entity instanceof LivingEntity) {
- LivingEntity entityliving1 = (LivingEntity) entity;
+ if (entity instanceof net.minecraft.world.entity.LivingEntity) {
+ net.minecraft.world.entity.LivingEntity entityliving1 = (net.minecraft.world.entity.LivingEntity) entity;
entityliving = entityliving1;
} else {

View File

@@ -0,0 +1,14 @@
--- a/net/minecraft/world/entity/ConversionParams.java
+++ b/net/minecraft/world/entity/ConversionParams.java
@@ -12,4 +12,11 @@
public interface AfterConversion<T extends Mob> {
void finalizeConversion(T convertedEntity);
}
+
+ // Paper start - entity zap event - allow conversion to be cancelled during finalization
+ @FunctionalInterface
+ public interface CancellingAfterConversion<T extends Mob> {
+ boolean finalizeConversionOrCancel(final T convertedEntity);
+ }
+ // Paper start - entity zap event - allow conversion to be cancelled during finalization
}

View File

@@ -0,0 +1,46 @@
--- a/net/minecraft/world/entity/ConversionType.java
+++ b/net/minecraft/world/entity/ConversionType.java
@@ -4,6 +4,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import net.minecraft.core.BlockPos;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.ai.Brain;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
@@ -11,6 +12,8 @@
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.scores.Scoreboard;
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
public enum ConversionType {
@@ -31,7 +34,7 @@
while (iterator.hasNext()) {
entity1 = (Entity) iterator.next();
entity1.stopRiding();
- entity1.remove(Entity.RemovalReason.DISCARDED);
+ entity1.remove(Entity.RemovalReason.DISCARDED, EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause
}
entity.startRiding(newEntity);
@@ -64,7 +67,7 @@
newEntity.hurtTime = oldEntity.hurtTime;
newEntity.yBodyRot = oldEntity.yBodyRot;
newEntity.setOnGround(oldEntity.onGround());
- Optional optional = oldEntity.getSleepingPos();
+ Optional<BlockPos> optional = oldEntity.getSleepingPos(); // CraftBukkit - decompile error
Objects.requireNonNull(newEntity);
optional.ifPresent(newEntity::setSleepingPos);
@@ -156,7 +159,7 @@
newEntity.setNoGravity(oldEntity.isNoGravity());
newEntity.setPortalCooldown(oldEntity.getPortalCooldown());
newEntity.setSilent(oldEntity.isSilent());
- Set set = oldEntity.getTags();
+ Set<String> set = oldEntity.getTags(); // CraftBukkit - decompile error
Objects.requireNonNull(newEntity);
set.forEach(newEntity::addTag);

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/Display.java
+++ b/net/minecraft/world/entity/Display.java
@@ -903,7 +903,7 @@
b = loadFlag(b, nbt, "default_background", (byte)4);
Optional<Display.TextDisplay.Align> optional = Display.TextDisplay.Align.CODEC
.decode(NbtOps.INSTANCE, nbt.get("alignment"))
- .resultOrPartial(Util.prefix("Display entity", Display.LOGGER::error))
+ .result() // Paper - Hide text display error on spawn
.map(Pair::getFirst);
if (optional.isPresent()) {
b = switch ((Display.TextDisplay.Align)optional.get()) {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
--- a/net/minecraft/world/entity/EntitySelector.java
+++ b/net/minecraft/world/entity/EntitySelector.java
@@ -27,8 +27,25 @@
};
public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith);
public static final Predicate<Entity> CAN_BE_PICKED = EntitySelector.NO_SPECTATORS.and(Entity::isPickable);
+ // Paper start - Ability to control player's insomnia and phantoms
+ public static Predicate<Player> IS_INSOMNIAC = (player) -> {
+ net.minecraft.server.level.ServerPlayer serverPlayer = (net.minecraft.server.level.ServerPlayer) player;
+ int playerInsomniaTicks = serverPlayer.level().paperConfig().entities.behavior.playerInsomniaStartTicks;
+ if (playerInsomniaTicks <= 0) {
+ return false;
+ }
+
+ return net.minecraft.util.Mth.clamp(serverPlayer.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= playerInsomniaTicks;
+ };
+ // Paper end - Ability to control player's insomnia and phantoms
+
private EntitySelector() {}
+ // Paper start - Affects Spawning API
+ public static final Predicate<Entity> PLAYER_AFFECTS_SPAWNING = (entity) -> {
+ return !entity.isSpectator() && entity.isAlive() && entity instanceof Player player && player.affectsSpawning;
+ };
+ // Paper end - Affects Spawning API
public static Predicate<Entity> withinDistance(double x, double y, double z, double max) {
double d4 = max * max;
@@ -39,13 +56,18 @@
}
public static Predicate<Entity> pushableBy(Entity entity) {
+ // Paper start - Climbing should not bypass cramming gamerule
+ return pushable(entity, false);
+ }
+ public static Predicate<Entity> pushable(Entity entity, boolean ignoreClimbing) {
+ // Paper end - Climbing should not bypass cramming gamerule
PlayerTeam scoreboardteam = entity.getTeam();
Team.CollisionRule scoreboardteambase_enumteampush = scoreboardteam == null ? Team.CollisionRule.ALWAYS : scoreboardteam.getCollisionRule();
return (Predicate) (scoreboardteambase_enumteampush == Team.CollisionRule.NEVER ? Predicates.alwaysFalse() : EntitySelector.NO_SPECTATORS.and((entity1) -> {
- if (!entity1.isPushable()) {
+ if (!entity1.isCollidable(ignoreClimbing) || !entity1.canCollideWithBukkit(entity) || !entity.canCollideWithBukkit(entity1)) { // CraftBukkit - collidable API // Paper - Climbing should not bypass cramming gamerule
return false;
- } else if (entity.level().isClientSide && (!(entity1 instanceof Player) || !((Player) entity1).isLocalPlayer())) {
+ } else if (entity1 instanceof Player && entity instanceof Player && !io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions) { // Paper - Configurable player collision
return false;
} else {
PlayerTeam scoreboardteam1 = entity1.getTeam();

View File

@@ -0,0 +1,179 @@
--- a/net/minecraft/world/entity/EntityType.java
+++ b/net/minecraft/world/entity/EntityType.java
@@ -176,6 +176,7 @@
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
+import org.bukkit.event.entity.CreatureSpawnEvent;
import org.slf4j.Logger;
public class EntityType<T extends Entity> implements FeatureElement, EntityTypeTest<Entity, T> {
@@ -191,7 +192,7 @@
return Items.ACACIA_CHEST_BOAT;
}), MobCategory.MISC).noLootTable().sized(1.375F, 0.5625F).eyeHeight(0.5625F).clientTrackingRange(10));
public static final EntityType<Allay> ALLAY = EntityType.register("allay", EntityType.Builder.of(Allay::new, MobCategory.CREATURE).sized(0.35F, 0.6F).eyeHeight(0.36F).ridingOffset(0.04F).clientTrackingRange(8).updateInterval(2));
- public static final EntityType<AreaEffectCloud> AREA_EFFECT_CLOUD = EntityType.register("area_effect_cloud", EntityType.Builder.of(AreaEffectCloud::new, MobCategory.MISC).noLootTable().fireImmune().sized(6.0F, 0.5F).clientTrackingRange(10).updateInterval(Integer.MAX_VALUE));
+ public static final EntityType<AreaEffectCloud> AREA_EFFECT_CLOUD = EntityType.register("area_effect_cloud", EntityType.Builder.of(AreaEffectCloud::new, MobCategory.MISC).noLootTable().fireImmune().sized(6.0F, 0.5F).clientTrackingRange(10).updateInterval(10)); // CraftBukkit - SPIGOT-3729: track area effect clouds
public static final EntityType<Armadillo> ARMADILLO = EntityType.register("armadillo", EntityType.Builder.of(Armadillo::new, MobCategory.CREATURE).sized(0.7F, 0.65F).eyeHeight(0.26F).clientTrackingRange(10));
public static final EntityType<ArmorStand> ARMOR_STAND = EntityType.register("armor_stand", EntityType.Builder.of(ArmorStand::new, MobCategory.MISC).sized(0.5F, 1.975F).eyeHeight(1.7775F).clientTrackingRange(10));
public static final EntityType<Arrow> ARROW = EntityType.register("arrow", EntityType.Builder.of(Arrow::new, MobCategory.MISC).noLootTable().sized(0.5F, 0.5F).eyeHeight(0.13F).clientTrackingRange(4).updateInterval(20));
@@ -399,7 +400,7 @@
return ResourceKey.create(Registries.ENTITY_TYPE, ResourceLocation.withDefaultNamespace(id));
}
- private static <T extends Entity> EntityType<T> register(String id, EntityType.Builder<T> type) {
+ private static <T extends Entity> EntityType<T> register(String id, EntityType.Builder type) { // CraftBukkit - decompile error
return EntityType.register(EntityType.vanillaEntityId(id), type);
}
@@ -431,16 +432,23 @@
@Nullable
public T spawn(ServerLevel world, @Nullable ItemStack stack, @Nullable Player player, BlockPos pos, EntitySpawnReason spawnReason, boolean alignPosition, boolean invertY) {
- Consumer consumer;
+ // CraftBukkit start
+ return this.spawn(world, stack, player, pos, spawnReason, alignPosition, invertY, spawnReason == EntitySpawnReason.DISPENSER ? org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DISPENSE_EGG : org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // Paper - use correct spawn reason for dispenser spawn eggs
+ }
- if (stack != null) {
- consumer = EntityType.createDefaultStackConfig(world, stack, player);
+ @Nullable
+ public T spawn(ServerLevel worldserver, @Nullable ItemStack itemstack, @Nullable Player entityhuman, BlockPos blockposition, EntitySpawnReason entityspawnreason, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
+ // CraftBukkit end
+ Consumer<T> consumer; // CraftBukkit - decompile error
+
+ if (itemstack != null) {
+ consumer = EntityType.createDefaultStackConfig(worldserver, itemstack, entityhuman);
} else {
consumer = (entity) -> {
};
}
- return this.spawn(world, consumer, pos, spawnReason, alignPosition, invertY);
+ return this.spawn(worldserver, consumer, blockposition, entityspawnreason, flag, flag1, spawnReason); // CraftBukkit
}
public static <T extends Entity> Consumer<T> createDefaultStackConfig(Level world, ItemStack stack, @Nullable Player player) {
@@ -464,21 +472,50 @@
CustomData customdata = (CustomData) stack.getOrDefault(DataComponents.ENTITY_DATA, CustomData.EMPTY);
return !customdata.isEmpty() ? chained.andThen((entity) -> {
- EntityType.updateCustomEntityTag(world, player, entity, customdata);
+ try { EntityType.updateCustomEntityTag(world, player, entity, customdata); } catch (Throwable t) { EntityType.LOGGER.warn("Error loading spawn egg NBT", t); } // CraftBukkit - SPIGOT-5665
}) : chained;
}
@Nullable
public T spawn(ServerLevel world, BlockPos pos, EntitySpawnReason reason) {
- return this.spawn(world, (Consumer) null, pos, reason, false, false);
+ // CraftBukkit start
+ return this.spawn(world, pos, reason, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
}
@Nullable
+ public T spawn(ServerLevel worldserver, BlockPos blockposition, EntitySpawnReason entityspawnreason, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
+ return this.spawn(worldserver, (Consumer<T>) null, blockposition, entityspawnreason, false, false, spawnReason); // CraftBukkit - decompile error
+ // CraftBukkit end
+ }
+
+ @Nullable
public T spawn(ServerLevel world, @Nullable Consumer<T> afterConsumer, BlockPos pos, EntitySpawnReason reason, boolean alignPosition, boolean invertY) {
- T t0 = this.create(world, afterConsumer, pos, reason, alignPosition, invertY);
+ // CraftBukkit start
+ return this.spawn(world, afterConsumer, pos, reason, alignPosition, invertY, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
+ }
+
+ @Nullable
+ public T spawn(ServerLevel worldserver, @Nullable Consumer<T> consumer, BlockPos blockposition, EntitySpawnReason entityspawnreason, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
+ // CraftBukkit end
+ // Paper start - PreCreatureSpawnEvent
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
+ io.papermc.paper.util.MCUtil.toLocation(worldserver, blockposition),
+ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(this),
+ spawnReason
+ );
+ if (!event.callEvent()) {
+ return null;
+ }
+ // Paper end - PreCreatureSpawnEvent
+ T t0 = this.create(worldserver, consumer, blockposition, entityspawnreason, flag, flag1);
if (t0 != null) {
- world.addFreshEntityWithPassengers(t0);
+ // CraftBukkit start
+ worldserver.addFreshEntityWithPassengers(t0, spawnReason);
+ if (t0.isRemoved()) {
+ return null; // Don't return an entity when CreatureSpawnEvent is canceled
+ }
+ // CraftBukkit end
if (t0 instanceof Mob) {
Mob entityinsentient = (Mob) t0;
@@ -542,6 +579,15 @@
if (entity.getType() == entitytypes) {
if (world.isClientSide || !entity.getType().onlyOpCanSetNbt() || player != null && minecraftserver.getPlayerList().isOp(player.getGameProfile())) {
+ // Paper start - filter out protected tags
+ if (player == null || !player.getBukkitEntity().hasPermission("minecraft.nbt.place")) {
+ nbt = nbt.update((compound) -> {
+ for (net.minecraft.commands.arguments.NbtPathArgument.NbtPath tag : world.paperConfig().entities.spawning.filteredEntityTagNbtPaths) {
+ tag.remove(compound);
+ }
+ });
+ }
+ // Paper end - filter out protected tags
nbt.loadInto(entity);
}
}
@@ -613,9 +659,15 @@
}
public static Optional<Entity> create(CompoundTag nbt, Level world, EntitySpawnReason reason) {
+ // Paper start - Don't fire sync event during generation
+ return create(nbt, world, reason, false);
+ }
+ public static Optional<Entity> create(CompoundTag nbt, Level world, EntitySpawnReason reason, boolean generation) {
+ // Paper end - Don't fire sync event during generation
return Util.ifElse(EntityType.by(nbt).map((entitytypes) -> {
return entitytypes.create(world, reason);
}), (entity) -> {
+ if (generation) entity.generation = true; // Paper - Don't fire sync event during generation
entity.load(nbt);
}, () -> {
EntityType.LOGGER.warn("Skipping Entity with id {}", nbt.getString("id"));
@@ -638,7 +690,7 @@
}
public static Optional<EntityType<?>> by(CompoundTag nbt) {
- return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.parse(nbt.getString("id")));
+ return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.tryParse(nbt.getString("id"))); // Paper - Validate ResourceLocation
}
@Nullable
@@ -657,7 +709,7 @@
}
return entity;
- }).orElse((Object) null);
+ }).orElse(null); // CraftBukkit - decompile error
}
public static Stream<Entity> loadEntitiesRecursive(final List<? extends Tag> entityNbtList, final Level world, final EntitySpawnReason reason) {
@@ -718,7 +770,7 @@
@Nullable
public T tryCast(Entity obj) {
- return obj.getType() == this ? obj : null;
+ return obj.getType() == this ? (T) obj : null; // CraftBukkit - decompile error
}
@Override
@@ -791,7 +843,7 @@
this.canSpawnFarFromPlayer = spawnGroup == MobCategory.CREATURE || spawnGroup == MobCategory.MISC;
}
- public static <T extends Entity> EntityType.Builder<T> of(EntityType.EntityFactory<T> factory, MobCategory spawnGroup) {
+ public static <T extends Entity> EntityType.Builder<T> of(EntityType.EntityFactory factory, MobCategory spawnGroup) { // CraftBukkit - decompile error
return new EntityType.Builder<>(factory, spawnGroup);
}

View File

@@ -0,0 +1,267 @@
--- a/net/minecraft/world/entity/ExperienceOrb.java
+++ b/net/minecraft/world/entity/ExperienceOrb.java
@@ -24,6 +24,13 @@
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityRemoveEvent;
+import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
+import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.event.player.PlayerExpCooldownChangeEvent;
+// CraftBukkit end
public class ExperienceOrb extends Entity {
@@ -37,9 +44,63 @@
public int value;
public int count;
private Player followingPlayer;
+ // Paper start
+ @javax.annotation.Nullable
+ public java.util.UUID sourceEntityId;
+ @javax.annotation.Nullable
+ public java.util.UUID triggerEntityId;
+ public org.bukkit.entity.ExperienceOrb.SpawnReason spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN;
+ private void loadPaperNBT(CompoundTag tag) {
+ if (!tag.contains("Paper.ExpData", net.minecraft.nbt.Tag.TAG_COMPOUND)) {
+ return;
+ }
+ CompoundTag comp = tag.getCompound("Paper.ExpData");
+ if (comp.hasUUID("source")) {
+ this.sourceEntityId = comp.getUUID("source");
+ }
+ if (comp.hasUUID("trigger")) {
+ this.triggerEntityId = comp.getUUID("trigger");
+ }
+ if (comp.contains("reason")) {
+ String reason = comp.getString("reason");
+ try {
+ this.spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.valueOf(reason);
+ } catch (Exception e) {
+ this.level().getCraftServer().getLogger().warning("Invalid spawnReason set for experience orb: " + e.getMessage() + " - " + reason);
+ }
+ }
+ }
+ private void savePaperNBT(CompoundTag tag) {
+ CompoundTag comp = new CompoundTag();
+ if (this.sourceEntityId != null) {
+ comp.putUUID("source", this.sourceEntityId);
+ }
+ if (this.triggerEntityId != null) {
+ comp.putUUID("trigger", triggerEntityId);
+ }
+ if (this.spawnReason != null && this.spawnReason != org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN) {
+ comp.putString("reason", this.spawnReason.name());
+ }
+ tag.put("Paper.ExpData", comp);
+ }
+
+ @io.papermc.paper.annotation.DoNotUse
+ @Deprecated
public ExperienceOrb(Level world, double x, double y, double z, int amount) {
+ this(world, x, y, z, amount, null, null);
+ }
+
+ public ExperienceOrb(Level world, double x, double y, double z, int amount, @javax.annotation.Nullable org.bukkit.entity.ExperienceOrb.SpawnReason reason, @javax.annotation.Nullable Entity triggerId) {
+ this(world, x, y, z, amount, reason, triggerId, null);
+ }
+
+ public ExperienceOrb(Level world, double x, double y, double z, int amount, @javax.annotation.Nullable org.bukkit.entity.ExperienceOrb.SpawnReason reason, @javax.annotation.Nullable Entity triggerId, @javax.annotation.Nullable Entity sourceId) {
this(EntityType.EXPERIENCE_ORB, world);
+ this.sourceEntityId = sourceId != null ? sourceId.getUUID() : null;
+ this.triggerEntityId = triggerId != null ? triggerId.getUUID() : null;
+ this.spawnReason = reason != null ? reason : org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN;
+ // Paper end
this.setPos(x, y, z);
this.setYRot((float) (this.random.nextDouble() * 360.0D));
this.setDeltaMovement((this.random.nextDouble() * 0.20000000298023224D - 0.10000000149011612D) * 2.0D, this.random.nextDouble() * 0.2D * 2.0D, (this.random.nextDouble() * 0.20000000298023224D - 0.10000000149011612D) * 2.0D);
@@ -68,6 +129,7 @@
@Override
public void tick() {
super.tick();
+ Player prevTarget = this.followingPlayer;// CraftBukkit - store old target
this.xo = this.getX();
this.yo = this.getY();
this.zo = this.getZ();
@@ -93,7 +155,22 @@
this.followingPlayer = null;
}
- if (this.followingPlayer != null) {
+ // CraftBukkit start
+ boolean cancelled = false;
+ if (this.followingPlayer != prevTarget) {
+ EntityTargetLivingEntityEvent event = CraftEventFactory.callEntityTargetLivingEvent(this, this.followingPlayer, (this.followingPlayer != null) ? EntityTargetEvent.TargetReason.CLOSEST_PLAYER : EntityTargetEvent.TargetReason.FORGOT_TARGET);
+ LivingEntity target = (event.getTarget() == null) ? null : ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle();
+ cancelled = event.isCancelled();
+
+ if (cancelled) {
+ this.followingPlayer = prevTarget;
+ } else {
+ this.followingPlayer = (target instanceof Player) ? (Player) target : null;
+ }
+ }
+
+ if (this.followingPlayer != null && !cancelled) {
+ // CraftBukkit end
Vec3 vec3d = new Vec3(this.followingPlayer.getX() - this.getX(), this.followingPlayer.getY() + (double) this.followingPlayer.getEyeHeight() / 2.0D - this.getY(), this.followingPlayer.getZ() - this.getZ());
double d0 = vec3d.lengthSqr();
@@ -121,7 +198,7 @@
++this.age;
if (this.age >= 6000) {
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
}
}
@@ -150,18 +227,27 @@
}
public static void award(ServerLevel world, Vec3 pos, int amount) {
+ // Paper start - add reasons for orbs
+ award(world, pos, amount, null, null, null);
+ }
+ public static void award(ServerLevel world, Vec3 pos, int amount, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId) {
+ award(world, pos, amount, reason, triggerId, null);
+ }
+ public static void award(ServerLevel world, Vec3 pos, int amount, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId, Entity sourceId) {
+ // Paper end - add reasons for orbs
while (amount > 0) {
int j = ExperienceOrb.getExperienceValue(amount);
amount -= j;
if (!ExperienceOrb.tryMergeToExisting(world, pos, j)) {
- world.addFreshEntity(new ExperienceOrb(world, pos.x(), pos.y(), pos.z(), j));
+ world.addFreshEntity(new ExperienceOrb(world, pos.x(), pos.y(), pos.z(), j, reason, triggerId, sourceId)); // Paper - add reason
}
}
}
private static boolean tryMergeToExisting(ServerLevel world, Vec3 pos, int amount) {
+ // Paper - TODO some other event for this kind of merge
AABB axisalignedbb = AABB.ofSize(pos, 1.0D, 1.0D, 1.0D);
int j = world.getRandom().nextInt(40);
List<ExperienceOrb> list = world.getEntities(EntityTypeTest.forClass(ExperienceOrb.class), axisalignedbb, (entityexperienceorb) -> {
@@ -188,9 +274,14 @@
}
private void merge(ExperienceOrb other) {
+ // Paper start - call orb merge event
+ if (!new com.destroystokyo.paper.event.entity.ExperienceOrbMergeEvent((org.bukkit.entity.ExperienceOrb) this.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) other.getBukkitEntity()).callEvent()) {
+ return;
+ }
+ // Paper end - call orb merge event
this.count += other.count;
this.age = Math.min(this.age, other.age);
- other.discard();
+ other.discard(EntityRemoveEvent.Cause.MERGE); // CraftBukkit - add Bukkit remove cause
}
private void setUnderwaterMovement() {
@@ -215,7 +306,7 @@
this.markHurt();
this.health = (int) ((float) this.health - amount);
if (this.health <= 0) {
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause
}
return true;
@@ -226,33 +317,35 @@
public void addAdditionalSaveData(CompoundTag nbt) {
nbt.putShort("Health", (short) this.health);
nbt.putShort("Age", (short) this.age);
- nbt.putShort("Value", (short) this.value);
+ nbt.putInt("Value", this.value); // Paper - save as Integer
nbt.putInt("Count", this.count);
+ this.savePaperNBT(nbt); // Paper
}
@Override
public void readAdditionalSaveData(CompoundTag nbt) {
this.health = nbt.getShort("Health");
this.age = nbt.getShort("Age");
- this.value = nbt.getShort("Value");
+ this.value = nbt.getInt("Value"); // Paper - load as Integer
this.count = Math.max(nbt.getInt("Count"), 1);
+ this.loadPaperNBT(nbt); // Paper
}
@Override
public void playerTouch(Player player) {
if (player instanceof ServerPlayer entityplayer) {
- if (player.takeXpDelay == 0) {
- player.takeXpDelay = 2;
+ if (player.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(entityplayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent
+ player.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(player, 2, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2;
player.take(this, 1);
int i = this.repairPlayerItems(entityplayer, this.value);
if (i > 0) {
- player.giveExperiencePoints(i);
+ player.giveExperiencePoints(CraftEventFactory.callPlayerExpChangeEvent(player, this).getAmount()); // CraftBukkit - this.value -> event.getAmount() // Paper - supply experience orb object
}
--this.count;
if (this.count == 0) {
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
}
}
@@ -266,12 +359,23 @@
ItemStack itemstack = ((EnchantedItemInUse) optional.get()).itemStack();
int j = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.serverLevel(), itemstack, amount);
int k = Math.min(j, itemstack.getDamageValue());
+ // CraftBukkit start
+ // Paper start - mending event
+ final int consumedExperience = k > 0 ? k * amount / j : 0;
+ org.bukkit.event.player.PlayerItemMendEvent event = CraftEventFactory.callPlayerItemMendEvent(player, this, itemstack, optional.get().inSlot(), k, consumedExperience);
+ // Paper end - mending event
+ k = event.getRepairAmount();
+ if (event.isCancelled()) {
+ return amount;
+ }
+ // CraftBukkit end
itemstack.setDamageValue(itemstack.getDamageValue() - k);
if (k > 0) {
- int l = amount - k * amount / j;
+ int l = amount - k * amount / j; // Paper - diff on change - expand PlayerMendEvents
if (l > 0) {
+ // this.value = l; // CraftBukkit - update exp value of orb for PlayerItemMendEvent calls // Paper - the value field should not be mutated here because it doesn't take "count" into account
return this.repairPlayerItems(player, l);
}
}
@@ -291,6 +395,24 @@
}
public static int getExperienceValue(int value) {
+ // CraftBukkit start
+ if (value > 162670129) return value - 100000;
+ if (value > 81335063) return 81335063;
+ if (value > 40667527) return 40667527;
+ if (value > 20333759) return 20333759;
+ if (value > 10166857) return 10166857;
+ if (value > 5083423) return 5083423;
+ if (value > 2541701) return 2541701;
+ if (value > 1270849) return 1270849;
+ if (value > 635413) return 635413;
+ if (value > 317701) return 317701;
+ if (value > 158849) return 158849;
+ if (value > 79423) return 79423;
+ if (value > 39709) return 39709;
+ if (value > 19853) return 19853;
+ if (value > 9923) return 9923;
+ if (value > 4957) return 4957;
+ // CraftBukkit end
return value >= 2477 ? 2477 : (value >= 1237 ? 1237 : (value >= 617 ? 617 : (value >= 307 ? 307 : (value >= 149 ? 149 : (value >= 73 ? 73 : (value >= 37 ? 37 : (value >= 17 ? 17 : (value >= 7 ? 7 : (value >= 3 ? 3 : 1)))))))));
}

View File

@@ -0,0 +1,42 @@
--- a/net/minecraft/world/entity/Interaction.java
+++ b/net/minecraft/world/entity/Interaction.java
@@ -27,6 +27,12 @@
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;
+// CraftBukkit start
+import net.minecraft.world.damagesource.DamageSource;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityDamageEvent;
+// CraftBukkit end
+
public class Interaction extends Entity implements Attackable, Targeting {
private static final Logger LOGGER = LogUtils.getLogger();
@@ -65,7 +71,7 @@
this.setHeight(nbt.getFloat("height"));
}
- DataResult dataresult;
+ DataResult<com.mojang.datafixers.util.Pair<Interaction.PlayerAction, net.minecraft.nbt.Tag>> dataresult; // CraftBukkit - decompile error
Logger logger;
if (nbt.contains("attack")) {
@@ -145,9 +151,16 @@
@Override
public boolean skipAttackInteraction(Entity attacker) {
if (attacker instanceof Player entityhuman) {
+ // CraftBukkit start
+ DamageSource source = entityhuman.damageSources().playerAttack(entityhuman);
+ EntityDamageEvent event = CraftEventFactory.callNonLivingEntityDamageEvent(this, source, 1.0F, false);
+ if (event.isCancelled()) {
+ return true;
+ }
+ // CraftBukkit end
this.attack = new Interaction.PlayerAction(entityhuman.getUUID(), this.level().getGameTime());
if (entityhuman instanceof ServerPlayer entityplayer) {
- CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(entityplayer, this, entityhuman.damageSources().generic(), 1.0F, 1.0F, false);
+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(entityplayer, this, entityhuman.damageSources().generic(), 1.0F, (float) event.getFinalDamage(), false); // CraftBukkit // Paper - use correct source and fix taken/dealt param order
}
return !this.getResponse();

View File

@@ -0,0 +1,17 @@
--- a/net/minecraft/world/entity/ItemBasedSteering.java
+++ b/net/minecraft/world/entity/ItemBasedSteering.java
@@ -53,6 +53,14 @@
return (Integer) this.entityData.get(this.boostTimeAccessor);
}
+ // CraftBukkit add setBoostTicks(int)
+ public void setBoostTicks(int ticks) {
+ this.boosting = true;
+ this.boostTime = 0;
+ this.entityData.set(this.boostTimeAccessor, ticks);
+ }
+ // CraftBukkit end
+
public void addAdditionalSaveData(CompoundTag nbt) {
nbt.putBoolean("Saddle", this.hasSaddle());
}

View File

@@ -0,0 +1,157 @@
--- a/net/minecraft/world/entity/Leashable.java
+++ b/net/minecraft/world/entity/Leashable.java
@@ -15,6 +15,10 @@
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.Level;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityUnleashEvent;
+import org.bukkit.event.entity.EntityUnleashEvent.UnleashReason;
+// CraftBukkit end
public interface Leashable {
@@ -45,7 +49,7 @@
default void setDelayedLeashHolderId(int unresolvedLeashHolderId) {
this.setLeashData(new Leashable.LeashData(unresolvedLeashHolderId));
- Leashable.dropLeash((Entity) this, false, false);
+ Leashable.dropLeash((Entity & Leashable) this, false, false); // CraftBukkit - decompile error
}
default void readLeashData(CompoundTag nbt) {
@@ -61,10 +65,16 @@
@Nullable
private static Leashable.LeashData readLeashDataInternal(CompoundTag nbt) {
if (nbt.contains("leash", 10)) {
- return new Leashable.LeashData(Either.left(nbt.getCompound("leash").getUUID("UUID")));
+ // Paper start
+ final CompoundTag leashTag = nbt.getCompound("leash");
+ if (!leashTag.hasUUID("UUID")) {
+ return null;
+ }
+ return new Leashable.LeashData(Either.left(leashTag.getUUID("UUID")));
+ // Paper end
} else {
if (nbt.contains("leash", 11)) {
- Either<UUID, BlockPos> either = (Either) NbtUtils.readBlockPos(nbt, "leash").map(Either::right).orElse((Object) null);
+ Either<UUID, BlockPos> either = (Either) NbtUtils.readBlockPos(nbt, "leash").map(Either::right).orElse(null); // CraftBukkit - decompile error
if (either != null) {
return new Leashable.LeashData(either);
@@ -79,6 +89,11 @@
if (leashData != null) {
Either<UUID, BlockPos> either = leashData.delayedLeashInfo;
Entity entity = leashData.leashHolder;
+ // CraftBukkit start - SPIGOT-7487: Don't save (and possible drop) leash, when the holder was removed by a plugin
+ if (entity != null && entity.pluginRemoved) {
+ return;
+ }
+ // CraftBukkit end
if (entity instanceof LeashFenceKnotEntity) {
LeashFenceKnotEntity entityleash = (LeashFenceKnotEntity) entity;
@@ -121,7 +136,9 @@
}
if (entity.tickCount > 100) {
+ entity.forceDrops = true; // CraftBukkit
entity.spawnAtLocation(worldserver, (ItemLike) Items.LEAD);
+ entity.forceDrops = false; // CraftBukkit
((Leashable) entity).setLeashData((Leashable.LeashData) null);
}
}
@@ -130,11 +147,11 @@
}
default void dropLeash() {
- Leashable.dropLeash((Entity) this, true, true);
+ Leashable.dropLeash((Entity & Leashable) this, true, true); // CraftBukkit - decompile error
}
default void removeLeash() {
- Leashable.dropLeash((Entity) this, true, false);
+ Leashable.dropLeash((Entity & Leashable) this, true, false); // CraftBukkit - decompile error
}
default void onLeashRemoved() {}
@@ -151,7 +168,9 @@
ServerLevel worldserver = (ServerLevel) world;
if (dropItem) {
+ entity.forceDrops = true; // CraftBukkit
entity.spawnAtLocation(worldserver, (ItemLike) Items.LEAD);
+ entity.forceDrops = false; // CraftBukkit
}
if (sendPacket) {
@@ -171,7 +190,11 @@
if (leashable_a != null && leashable_a.leashHolder != null) {
if (!entity.isAlive() || !leashable_a.leashHolder.isAlive()) {
- if (world.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
+ // Paper start - Expand EntityUnleashEvent
+ final EntityUnleashEvent event = new EntityUnleashEvent(entity.getBukkitEntity(), (!entity.isAlive()) ? UnleashReason.PLAYER_UNLEASH : UnleashReason.HOLDER_GONE, world.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS) && !entity.pluginRemoved);
+ event.callEvent();
+ if (event.isDropLeash()) { // CraftBukkit - SPIGOT-7487: Don't drop leash, when the holder was removed by a plugin
+ // Paper end - Expand EntityUnleashEvent
((Leashable) entity).dropLeash();
} else {
((Leashable) entity).removeLeash();
@@ -187,7 +210,7 @@
return;
}
- if ((double) f > 10.0D) {
+ if ((double) f > entity.level().paperConfig().misc.maxLeashDistance.or(LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance
((Leashable) entity).leashTooFarBehaviour();
} else if ((double) f > 6.0D) {
((Leashable) entity).elasticRangeLeashBehaviour(entity1, f);
@@ -205,13 +228,27 @@
}
default void leashTooFarBehaviour() {
- this.dropLeash();
+ // CraftBukkit start
+ boolean dropLeash = true; // Paper
+ if (this instanceof Entity entity) {
+ // Paper start - Expand EntityUnleashEvent
+ final EntityUnleashEvent event = new EntityUnleashEvent(entity.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE, true);
+ if (!event.callEvent()) return;
+ dropLeash = event.isDropLeash();
+ }
+ // CraftBukkit end
+ if (dropLeash) {
+ this.dropLeash();
+ } else {
+ this.removeLeash();
+ }
+ // Paper end - Expand EntityUnleashEvent
}
default void closeRangeLeashBehaviour(Entity entity) {}
default void elasticRangeLeashBehaviour(Entity leashHolder, float distance) {
- Leashable.legacyElasticRangeLeashBehaviour((Entity) this, leashHolder, distance);
+ Leashable.legacyElasticRangeLeashBehaviour((Entity & Leashable) this, leashHolder, distance); // CraftBukkit - decompile error
}
private static <E extends Entity & Leashable> void legacyElasticRangeLeashBehaviour(E entity, Entity leashHolder, float distance) {
@@ -223,7 +260,7 @@
}
default void setLeashedTo(Entity leashHolder, boolean sendPacket) {
- this.setLeashedTo((Entity) this, leashHolder, sendPacket);
+ Leashable.setLeashedTo((Entity & Leashable) this, leashHolder, sendPacket); // CraftBukkit - decompile error
}
private static <E extends Entity & Leashable> void setLeashedTo(E entity, Entity leashHolder, boolean sendPacket) {
@@ -254,7 +291,7 @@
@Nullable
default Entity getLeashHolder() {
- return Leashable.getLeashHolder((Entity) this);
+ return Leashable.getLeashHolder((Entity & Leashable) this); // CraftBukkit - decompile error
}
@Nullable

View File

@@ -0,0 +1,160 @@
--- a/net/minecraft/world/entity/LightningBolt.java
+++ b/net/minecraft/world/entity/LightningBolt.java
@@ -30,6 +30,10 @@
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
public class LightningBolt extends Entity {
@@ -44,6 +48,7 @@
private ServerPlayer cause;
private final Set<Entity> hitEntities = Sets.newHashSet();
private int blocksSetOnFire;
+ public boolean isEffect; // Paper - Properly handle lightning effects api
public LightningBolt(EntityType<? extends LightningBolt> type, Level world) {
super(type, world);
@@ -82,7 +87,7 @@
@Override
public void tick() {
super.tick();
- if (this.life == 2) {
+ if (!this.isEffect && this.life == 2) { // Paper - Properly handle lightning effects api
if (this.level().isClientSide()) {
this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_THUNDER, SoundSource.WEATHER, 10000.0F, 0.8F + this.random.nextFloat() * 0.2F, false);
this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_IMPACT, SoundSource.WEATHER, 2.0F, 0.5F + this.random.nextFloat() * 0.2F, false);
@@ -94,7 +99,7 @@
}
this.powerLightningRod();
- LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition());
+ LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition(), this); // Paper - Call EntityChangeBlockEvent
this.gameEvent(GameEvent.LIGHTNING_STRIKE);
}
}
@@ -120,7 +125,7 @@
}
}
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
} else if (this.life < -this.random.nextInt(10)) {
--this.flashes;
this.life = 1;
@@ -129,7 +134,7 @@
}
}
- if (this.life >= 0) {
+ if (this.life >= 0 && !this.isEffect) { // CraftBukkit - add !this.visualOnly // Paper - Properly handle lightning effects api
if (!(this.level() instanceof ServerLevel)) {
this.level().setSkyFlashTime(2);
} else if (!this.visualOnly) {
@@ -158,7 +163,7 @@
}
private void spawnFire(int spreadAttempts) {
- if (!this.visualOnly) {
+ if (!this.visualOnly && !this.isEffect) { // Paper - Properly handle lightning effects api
Level world = this.level();
if (world instanceof ServerLevel) {
@@ -169,8 +174,12 @@
BlockState iblockdata = BaseFireBlock.getState(this.level(), blockposition);
if (this.level().getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level(), blockposition)) {
- this.level().setBlockAndUpdate(blockposition, iblockdata);
- ++this.blocksSetOnFire;
+ // CraftBukkit start - add "!visualOnly"
+ if (!this.visualOnly && !CraftEventFactory.callBlockIgniteEvent(this.level(), blockposition, this).isCancelled()) {
+ this.level().setBlockAndUpdate(blockposition, iblockdata);
+ ++this.blocksSetOnFire;
+ }
+ // CraftBukkit end
}
for (int j = 0; j < spreadAttempts; ++j) {
@@ -178,8 +187,12 @@
iblockdata = BaseFireBlock.getState(this.level(), blockposition1);
if (this.level().getBlockState(blockposition1).isAir() && iblockdata.canSurvive(this.level(), blockposition1)) {
- this.level().setBlockAndUpdate(blockposition1, iblockdata);
- ++this.blocksSetOnFire;
+ // CraftBukkit start - add "!visualOnly"
+ if (!this.visualOnly && !CraftEventFactory.callBlockIgniteEvent(this.level(), blockposition1, this).isCancelled()) {
+ this.level().setBlockAndUpdate(blockposition1, iblockdata);
+ ++this.blocksSetOnFire;
+ }
+ // CraftBukkit end
}
}
@@ -190,7 +203,7 @@
}
- private static void clearCopperOnLightningStrike(Level world, BlockPos pos) {
+ private static void clearCopperOnLightningStrike(Level world, BlockPos pos, Entity lightning) { // Paper - Call EntityChangeBlockEvent
BlockState iblockdata = world.getBlockState(pos);
BlockPos blockposition1;
BlockState iblockdata1;
@@ -204,24 +217,29 @@
}
if (iblockdata1.getBlock() instanceof WeatheringCopper) {
- world.setBlockAndUpdate(blockposition1, WeatheringCopper.getFirst(world.getBlockState(blockposition1)));
+ // Paper start - Call EntityChangeBlockEvent
+ BlockState newBlock = WeatheringCopper.getFirst(world.getBlockState(blockposition1));
+ if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1, newBlock)) {
+ world.setBlockAndUpdate(blockposition1, newBlock);
+ }
+ // Paper end - Call EntityChangeBlockEvent
BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable();
int i = world.random.nextInt(3) + 3;
for (int j = 0; j < i; ++j) {
int k = world.random.nextInt(8) + 1;
- LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k);
+ LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
}
}
}
- private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count) {
+ private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
mutablePos.set(pos);
for (int j = 0; j < count; ++j) {
- Optional<BlockPos> optional = LightningBolt.randomStepCleaningCopper(world, mutablePos);
+ Optional<BlockPos> optional = LightningBolt.randomStepCleaningCopper(world, mutablePos, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
if (optional.isEmpty()) {
break;
@@ -232,7 +250,7 @@
}
- private static Optional<BlockPos> randomStepCleaningCopper(Level world, BlockPos pos) {
+ private static Optional<BlockPos> randomStepCleaningCopper(Level world, BlockPos pos, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
Iterator iterator = BlockPos.randomInCube(world.random, 10, pos, 1).iterator();
BlockPos blockposition1;
@@ -247,8 +265,10 @@
iblockdata = world.getBlockState(blockposition1);
} while (!(iblockdata.getBlock() instanceof WeatheringCopper));
+ BlockPos blockposition1Final = blockposition1; // CraftBukkit - decompile error
WeatheringCopper.getPrevious(iblockdata).ifPresent((iblockdata1) -> {
- world.setBlockAndUpdate(blockposition1, iblockdata1);
+ if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1Final, iblockdata1)) // Paper - call EntityChangeBlockEvent
+ world.setBlockAndUpdate(blockposition1Final, iblockdata1); // CraftBukkit - decompile error
});
world.levelEvent(3002, blockposition1, -1);
return Optional.of(blockposition1);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,472 @@
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -84,6 +84,17 @@
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.AABB;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.entity.EntityRemoveEvent;
+import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
+import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.event.entity.EntityTransformEvent;
+import org.bukkit.event.entity.EntityUnleashEvent;
+import org.bukkit.event.entity.EntityUnleashEvent.UnleashReason;
+// CraftBukkit end
public abstract class Mob extends LivingEntity implements EquipmentUser, Leashable, Targeting {
@@ -112,6 +123,7 @@
private final BodyRotationControl bodyRotationControl;
protected PathNavigation navigation;
public GoalSelector goalSelector;
+ @Nullable public net.minecraft.world.entity.ai.goal.FloatGoal goalFloat; // Paper - Allow nerfed mobs to jump and float
public GoalSelector targetSelector;
@Nullable
private LivingEntity target;
@@ -132,6 +144,8 @@
private BlockPos restrictCenter;
private float restrictRadius;
+ public boolean aware = true; // CraftBukkit
+
protected Mob(EntityType<? extends Mob> type, Level world) {
super(type, world);
this.handItems = NonNullList.withSize(2, ItemStack.EMPTY);
@@ -157,8 +171,14 @@
if (world instanceof ServerLevel) {
this.registerGoals();
}
+
+ }
+ // CraftBukkit start
+ public void setPersistenceRequired(boolean persistenceRequired) {
+ this.persistenceRequired = persistenceRequired;
}
+ // CraftBukkit end
protected void registerGoals() {}
@@ -264,13 +284,44 @@
@Nullable
protected final LivingEntity getTargetFromBrain() {
- return (LivingEntity) this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse((Object) null);
+ return (LivingEntity) this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null); // CraftBukkit - decompile error
}
public void setTarget(@Nullable LivingEntity target) {
- this.target = target;
+ // CraftBukkit start - fire event
+ this.setTarget(target, EntityTargetEvent.TargetReason.UNKNOWN, true);
}
+ public boolean setTarget(LivingEntity entityliving, EntityTargetEvent.TargetReason reason, boolean fireEvent) {
+ if (this.getTarget() == entityliving) return false;
+ if (fireEvent) {
+ if (reason == EntityTargetEvent.TargetReason.UNKNOWN && this.getTarget() != null && entityliving == null) {
+ reason = this.getTarget().isAlive() ? EntityTargetEvent.TargetReason.FORGOT_TARGET : EntityTargetEvent.TargetReason.TARGET_DIED;
+ }
+ if (reason == EntityTargetEvent.TargetReason.UNKNOWN) {
+ this.level().getCraftServer().getLogger().log(java.util.logging.Level.WARNING, "Unknown target reason, please report on the issue tracker", new Exception());
+ }
+ CraftLivingEntity ctarget = null;
+ if (entityliving != null) {
+ ctarget = (CraftLivingEntity) entityliving.getBukkitEntity();
+ }
+ EntityTargetLivingEntityEvent event = new EntityTargetLivingEntityEvent(this.getBukkitEntity(), ctarget, reason);
+ this.level().getCraftServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return false;
+ }
+
+ if (event.getTarget() != null) {
+ entityliving = ((CraftLivingEntity) event.getTarget()).getHandle();
+ } else {
+ entityliving = null;
+ }
+ }
+ this.target = entityliving;
+ return true;
+ // CraftBukkit end
+ }
+
@Override
public boolean canAttackType(EntityType<?> type) {
return type != EntityType.GHAST;
@@ -399,6 +450,12 @@
return null;
}
+ // CraftBukkit start - Add delegate method
+ public SoundEvent getAmbientSound0() {
+ return this.getAmbientSound();
+ }
+ // CraftBukkit end
+
@Override
public void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
@@ -473,13 +530,25 @@
nbt.putBoolean("NoAI", this.isNoAi());
}
+ nbt.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit
}
@Override
public void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
- this.setCanPickUpLoot(nbt.getBoolean("CanPickUpLoot"));
- this.persistenceRequired = nbt.getBoolean("PersistenceRequired");
+ // CraftBukkit start - If looting or persistence is false only use it if it was set after we started using it
+ if (nbt.contains("CanPickUpLoot", 99)) {
+ boolean data = nbt.getBoolean("CanPickUpLoot");
+ if (isLevelAtLeast(nbt, 1) || data) {
+ this.setCanPickUpLoot(data);
+ }
+ }
+
+ boolean data = nbt.getBoolean("PersistenceRequired");
+ if (isLevelAtLeast(nbt, 1) || data) {
+ this.persistenceRequired = data;
+ }
+ // CraftBukkit end
ListTag nbttaglist;
CompoundTag nbttagcompound1;
int i;
@@ -540,13 +609,18 @@
this.readLeashData(nbt);
this.setLeftHanded(nbt.getBoolean("LeftHanded"));
if (nbt.contains("DeathLootTable", 8)) {
- this.lootTable = Optional.of(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("DeathLootTable"))));
+ this.lootTable = Optional.ofNullable(ResourceLocation.tryParse(nbt.getString("DeathLootTable"))).map((rs) -> ResourceKey.create(Registries.LOOT_TABLE, rs)); // Paper - Validate ResourceLocation
} else {
this.lootTable = Optional.empty();
}
this.lootTableSeed = nbt.getLong("DeathLootTableSeed");
this.setNoAi(nbt.getBoolean("NoAI"));
+ // CraftBukkit start
+ if (nbt.contains("Bukkit.Aware")) {
+ this.aware = nbt.getBoolean("Bukkit.Aware");
+ }
+ // CraftBukkit end
}
@Override
@@ -608,6 +682,11 @@
ItemEntity entityitem = (ItemEntity) iterator.next();
if (!entityitem.isRemoved() && !entityitem.getItem().isEmpty() && !entityitem.hasPickUpDelay() && this.wantsToPickUp(worldserver, entityitem.getItem())) {
+ // Paper start - Item#canEntityPickup
+ if (!entityitem.canMobPickup) {
+ continue;
+ }
+ // Paper end - Item#canEntityPickup
this.pickUpItem(worldserver, entityitem);
}
}
@@ -623,23 +702,29 @@
protected void pickUpItem(ServerLevel world, ItemEntity itemEntity) {
ItemStack itemstack = itemEntity.getItem();
- ItemStack itemstack1 = this.equipItemIfPossible(world, itemstack.copy());
+ ItemStack itemstack1 = this.equipItemIfPossible(world, itemstack.copy(), itemEntity); // CraftBukkit - add item
if (!itemstack1.isEmpty()) {
this.onItemPickup(itemEntity);
this.take(itemEntity, itemstack1.getCount());
itemstack.shrink(itemstack1.getCount());
if (itemstack.isEmpty()) {
- itemEntity.discard();
+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
}
}
}
public ItemStack equipItemIfPossible(ServerLevel world, ItemStack stack) {
- EquipmentSlot enumitemslot = this.getEquipmentSlotForItem(stack);
+ // CraftBukkit start - add item
+ return this.equipItemIfPossible(world, stack, null);
+ }
+
+ public ItemStack equipItemIfPossible(ServerLevel worldserver, ItemStack itemstack, ItemEntity entityitem) {
+ // CraftBukkit end
+ EquipmentSlot enumitemslot = this.getEquipmentSlotForItem(itemstack);
ItemStack itemstack1 = this.getItemBySlot(enumitemslot);
- boolean flag = this.canReplaceCurrentItem(stack, itemstack1, enumitemslot);
+ boolean flag = this.canReplaceCurrentItem(itemstack, itemstack1, enumitemslot);
if (enumitemslot.isArmor() && !flag) {
enumitemslot = EquipmentSlot.MAINHAND;
@@ -647,14 +732,22 @@
flag = itemstack1.isEmpty();
}
- if (flag && this.canHoldItem(stack)) {
+ // CraftBukkit start
+ boolean canPickup = flag && this.canHoldItem(itemstack);
+ if (entityitem != null) {
+ canPickup = !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entityitem, 0, !canPickup).isCancelled();
+ }
+ if (canPickup) {
+ // CraftBukkit end
double d0 = (double) this.getEquipmentDropChance(enumitemslot);
if (!itemstack1.isEmpty() && (double) Math.max(this.random.nextFloat() - 0.1F, 0.0F) < d0) {
- this.spawnAtLocation(world, itemstack1);
+ this.forceDrops = true; // CraftBukkit
+ this.spawnAtLocation(worldserver, itemstack1);
+ this.forceDrops = false; // CraftBukkit
}
- ItemStack itemstack2 = enumitemslot.limit(stack);
+ ItemStack itemstack2 = enumitemslot.limit(itemstack);
this.setItemSlotAndDropWhenKilled(enumitemslot, itemstack2);
return itemstack2;
@@ -768,25 +861,29 @@
@Override
public void checkDespawn() {
if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
} else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
- Player entityhuman = this.level().getNearestPlayer(this, -1.0D);
+ Player entityhuman = this.level().findNearbyPlayer(this, -1.0D, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper - Affects Spawning API
if (entityhuman != null) {
- double d0 = entityhuman.distanceToSqr((Entity) this);
- int i = this.getType().getCategory().getDespawnDistance();
- int j = i * i;
-
- if (d0 > (double) j && this.removeWhenFarAway(d0)) {
- this.discard();
+ // Paper start - Configurable despawn distances
+ final io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DespawnRangePair despawnRangePair = this.level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory());
+ final io.papermc.paper.configuration.type.DespawnRange.Shape shape = this.level().paperConfig().entities.spawning.despawnRangeShape;
+ final double dy = Math.abs(entityhuman.getY() - this.getY());
+ final double dySqr = Math.pow(dy, 2);
+ final double dxSqr = Math.pow(entityhuman.getX() - this.getX(), 2);
+ final double dzSqr = Math.pow(entityhuman.getZ() - this.getZ(), 2);
+ final double distanceSquared = dxSqr + dzSqr + dySqr;
+ // Despawn if hard/soft limit is exceeded
+ if (despawnRangePair.hard().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy) && this.removeWhenFarAway(distanceSquared)) {
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
}
-
- int k = this.getType().getCategory().getNoDespawnDistance();
- int l = k * k;
-
- if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > (double) l && this.removeWhenFarAway(d0)) {
- this.discard();
- } else if (d0 < (double) l) {
+ if (despawnRangePair.soft().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy)) {
+ if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && this.removeWhenFarAway(distanceSquared)) {
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
+ }
+ } else {
+ // Paper end - Configurable despawn distances
this.noActionTime = 0;
}
}
@@ -799,6 +896,15 @@
@Override
protected final void serverAiStep() {
++this.noActionTime;
+ // Paper start - Allow nerfed mobs to jump and float
+ if (!this.aware) {
+ if (goalFloat != null) {
+ if (goalFloat.canUse()) goalFloat.tick();
+ this.getJumpControl().tick();
+ }
+ return;
+ }
+ // Paper end - Allow nerfed mobs to jump and float
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push("sensing");
@@ -994,23 +1100,36 @@
@Override
public void setItemSlot(EquipmentSlot slot, ItemStack stack) {
+ // Paper start - Fix silent equipment change
+ setItemSlot(slot, stack, false);
+ }
+
+ @Override
+ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) {
+ // Paper end - Fix silent equipment change
this.verifyEquippedItem(stack);
switch (slot.getType()) {
case HAND:
- this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack);
+ this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change
break;
case HUMANOID_ARMOR:
- this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack);
+ this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change
break;
case ANIMAL_ARMOR:
ItemStack itemstack1 = this.bodyArmorItem;
this.bodyArmorItem = stack;
- this.onEquipItem(slot, itemstack1, stack);
+ this.onEquipItem(slot, itemstack1, stack, silent); // Paper - Fix silent equipment change
}
}
+ // Paper start
+ protected boolean shouldSkipLoot(EquipmentSlot slot) { // method to avoid to fallback into the global mob loot logic (i.e fox)
+ return false;
+ }
+ // Paper end
+
@Override
protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {
super.dropCustomDeathLoot(world, source, causedByPlayer);
@@ -1018,6 +1137,7 @@
while (iterator.hasNext()) {
EquipmentSlot enumitemslot = (EquipmentSlot) iterator.next();
+ if (this.shouldSkipLoot(enumitemslot)) continue; // Paper
ItemStack itemstack = this.getItemBySlot(enumitemslot);
float f = this.getEquipmentDropChance(enumitemslot);
@@ -1042,7 +1162,13 @@
}
this.spawnAtLocation(world, itemstack);
+ if (this.clearEquipmentSlots) { // Paper
this.setItemSlot(enumitemslot, ItemStack.EMPTY);
+ // Paper start
+ } else {
+ this.clearedEquipmentSlots.add(enumitemslot);
+ }
+ // Paper end
}
}
}
@@ -1338,7 +1464,7 @@
if (itemstack.getItem() instanceof SpawnEggItem) {
if (this.level() instanceof ServerLevel) {
SpawnEggItem itemmonsteregg = (SpawnEggItem) itemstack.getItem();
- Optional<Mob> optional = itemmonsteregg.spawnOffspringFromSpawnEgg(player, this, this.getType(), (ServerLevel) this.level(), this.position(), itemstack);
+ Optional<Mob> optional = itemmonsteregg.spawnOffspringFromSpawnEgg(player, this, (EntityType<? extends Mob>) this.getType(), (ServerLevel) this.level(), this.position(), itemstack); // CraftBukkit - decompile error
optional.ifPresent((entityinsentient) -> {
this.onOffspringSpawnedFromEgg(player, entityinsentient);
@@ -1389,28 +1515,51 @@
return this.restrictRadius != -1.0F;
}
+ // CraftBukkit start
@Nullable
public <T extends Mob> T convertTo(EntityType<T> entityType, ConversionParams context, EntitySpawnReason reason, ConversionParams.AfterConversion<T> finalizer) {
+ return this.convertTo(entityType, context, reason, finalizer, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT);
+ }
+
+ @Nullable
+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, EntitySpawnReason entityspawnreason, ConversionParams.AfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) {
+ // Paper start - entity zap event - allow cancellation of conversion post creation
+ return this.convertTo(entitytypes, conversionparams, entityspawnreason, e -> { conversionparams_a.finalizeConversion(e); return true; }, transformReason, spawnReason);
+ }
+ @Nullable
+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, EntitySpawnReason entityspawnreason, ConversionParams.CancellingAfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) {
+ // Paper end - entity zap event - allow cancellation of conversion post creation
+ // CraftBukkit end
if (this.isRemoved()) {
return null;
} else {
- T t0 = (Mob) entityType.create(this.level(), reason);
+ T t0 = entitytypes.create(this.level(), EntitySpawnReason.CONVERSION); // CraftBukkit - decompile error
if (t0 == null) {
return null;
} else {
- context.type().convert(this, t0, context);
- finalizer.finalizeConversion(t0);
+ conversionparams.type().convert(this, t0, conversionparams);
+ if (!conversionparams_a.finalizeConversionOrCancel(t0)) return null; // Paper - entity zap event - return null if conversion was cancelled
Level world = this.level();
+ // CraftBukkit start
+ if (transformReason == null) {
+ // Special handling for slime split and pig lightning
+ return t0;
+ }
+
+ if (CraftEventFactory.callEntityTransformEvent(this, t0, transformReason).isCancelled()) {
+ return null;
+ }
+ // CraftBukkit end
if (world instanceof ServerLevel) {
ServerLevel worldserver = (ServerLevel) world;
- worldserver.addFreshEntity(t0);
+ worldserver.addFreshEntity(t0, spawnReason); // CraftBukkit
}
- if (context.type().shouldDiscardAfterConversion()) {
- this.discard();
+ if (conversionparams.type().shouldDiscardAfterConversion()) {
+ this.discard(EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause
}
return t0;
@@ -1420,10 +1569,22 @@
@Nullable
public <T extends Mob> T convertTo(EntityType<T> entityType, ConversionParams context, ConversionParams.AfterConversion<T> finalizer) {
- return this.convertTo(entityType, context, EntitySpawnReason.CONVERSION, finalizer);
+ // CraftBukkit start
+ return this.convertTo(entityType, context, finalizer, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT);
}
@Nullable
+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, ConversionParams.AfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) {
+ // Paper start - entity zap event - allow cancellation of conversion post creation
+ return this.convertTo(entitytypes, conversionparams, e -> { conversionparams_a.finalizeConversion(e); return true; }, transformReason, spawnReason);
+ }
+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, ConversionParams.CancellingAfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) {
+ // Paper start - entity zap event - allow cancellation of conversion post creation
+ return this.convertTo(entitytypes, conversionparams, EntitySpawnReason.CONVERSION, conversionparams_a, transformReason, spawnReason);
+ // CraftBukkit end
+ }
+
+ @Nullable
@Override
public Leashable.LeashData getLeashData() {
return this.leashData;
@@ -1458,7 +1619,15 @@
boolean flag1 = super.startRiding(entity, force);
if (flag1 && this.isLeashed()) {
- this.dropLeash();
+ // Paper start - Expand EntityUnleashEvent
+ EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.UNKNOWN, true);
+ if (!event.callEvent()) { return flag1; }
+ if (event.isDropLeash()) {
+ this.dropLeash();
+ } else {
+ this.removeLeash();
+ }
+ // Paper end - Expand EntityUnleashEvent
}
return flag1;
@@ -1542,7 +1711,7 @@
if (f1 > 0.0F && target instanceof LivingEntity) {
entityliving = (LivingEntity) target;
- entityliving.knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)));
+ entityliving.knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events
this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D));
}

View File

@@ -0,0 +1,86 @@
--- a/net/minecraft/world/entity/NeutralMob.java
+++ b/net/minecraft/world/entity/NeutralMob.java
@@ -8,6 +8,9 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityTargetEvent;
+// CraftBukkit end
public interface NeutralMob {
@@ -42,24 +45,11 @@
UUID uuid = nbt.getUUID("AngryAt");
this.setPersistentAngerTarget(uuid);
- Entity entity = ((ServerLevel) world).getEntity(uuid);
-
- if (entity != null) {
- if (entity instanceof Mob) {
- Mob entityinsentient = (Mob) entity;
-
- this.setTarget(entityinsentient);
- this.setLastHurtByMob(entityinsentient);
- }
-
- if (entity instanceof Player) {
- Player entityhuman = (Player) entity;
-
- this.setTarget(entityhuman);
- this.setLastHurtByPlayer(entityhuman);
- }
-
- }
+ // Paper - Prevent entity loading causing async lookups; Moved diff to separate method
+ // If this entity already survived its first tick, e.g. is loaded and ticked in sync, actively
+ // tick the initial persistent anger.
+ // If not, let the first tick on the baseTick call the method later down the line.
+ if (this instanceof Entity entity && !entity.firstTick) this.tickInitialPersistentAnger(world);
}
}
}
@@ -114,7 +104,7 @@
default void stopBeingAngry() {
this.setLastHurtByMob((LivingEntity) null);
this.setPersistentAngerTarget((UUID) null);
- this.setTarget((LivingEntity) null);
+ this.setTarget((LivingEntity) null, org.bukkit.event.entity.EntityTargetEvent.TargetReason.FORGOT_TARGET, true); // CraftBukkit
this.setRemainingPersistentAngerTime(0);
}
@@ -127,8 +117,34 @@
void setTarget(@Nullable LivingEntity target);
+ boolean setTarget(@Nullable LivingEntity entityliving, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent); // CraftBukkit
+
boolean canAttack(LivingEntity target);
@Nullable
LivingEntity getTarget();
+
+ // Paper start - Prevent entity loading causing async lookups
+ // Update last hurt when ticking
+ default void tickInitialPersistentAnger(Level level) {
+ UUID target = getPersistentAngerTarget();
+ if (target == null) {
+ return;
+ }
+
+ Entity entity = ((ServerLevel) level).getEntity(target);
+
+ if (entity != null) {
+ if (entity instanceof Mob mob) {
+ this.setTarget(mob, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit
+ this.setLastHurtByMob(mob);
+ }
+
+ if (entity instanceof Player player) {
+ this.setTarget(player, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit
+ this.setLastHurtByPlayer(player);
+ }
+ }
+ }
+ // Paper end - Prevent entity loading causing async lookups
}

View File

@@ -0,0 +1,29 @@
--- a/net/minecraft/world/entity/OminousItemSpawner.java
+++ b/net/minecraft/world/entity/OminousItemSpawner.java
@@ -76,7 +76,7 @@
entity = this.spawnProjectile(serverLevel, projectileItem, itemStack);
} else {
entity = new ItemEntity(serverLevel, this.getX(), this.getY(), this.getZ(), itemStack);
- serverLevel.addFreshEntity(entity);
+ serverLevel.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OMINOUS_ITEM_SPAWNER); // Paper - fixes and addition to spawn reason API
}
serverLevel.levelEvent(3021, this.blockPosition(), 1);
@@ -90,7 +90,7 @@
ProjectileItem.DispenseConfig dispenseConfig = item.createDispenseConfig();
dispenseConfig.overrideDispenseEvent().ifPresent(dispenseEvent -> world.levelEvent(dispenseEvent, this.blockPosition(), 0));
Direction direction = Direction.DOWN;
- Projectile projectile = Projectile.spawnProjectileUsingShoot(
+ Projectile projectile = Projectile.spawnProjectileUsingShootDelayed( // Paper - fixes and addition to spawn reason API
item.asProjectile(world, this.position(), stack, direction),
world,
stack,
@@ -99,7 +99,7 @@
(double)direction.getStepZ(),
dispenseConfig.power(),
dispenseConfig.uncertainty()
- );
+ ).spawn(org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OMINOUS_ITEM_SPAWNER); // Paper - fixes and addition to spawn reason API
projectile.setOwner(this);
return projectile;
}

View File

@@ -0,0 +1,12 @@
--- a/net/minecraft/world/entity/PathfinderMob.java
+++ b/net/minecraft/world/entity/PathfinderMob.java
@@ -10,6 +10,9 @@
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityUnleashEvent;
+// CraftBukkit end
public abstract class PathfinderMob extends Mob {

View File

@@ -0,0 +1,18 @@
--- a/net/minecraft/world/entity/Shearable.java
+++ b/net/minecraft/world/entity/Shearable.java
@@ -5,7 +5,15 @@
import net.minecraft.world.item.ItemStack;
public interface Shearable {
+ default void shear(ServerLevel world, SoundSource soundCategory, ItemStack shears, java.util.List<net.minecraft.world.item.ItemStack> drops) { this.shear(world, soundCategory, shears); } // Paper - Add drops to shear events
void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears);
boolean readyForShearing();
+ net.minecraft.world.level.Level level(); // Shearable API - expose default level needed for shearing.
+
+ // Paper start - custom shear drops; ensure all implementing entities override this
+ default java.util.List<net.minecraft.world.item.ItemStack> generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) {
+ return java.util.Collections.emptyList();
+ }
+ // Paper end - custom shear drops
}

View File

@@ -0,0 +1,85 @@
--- a/net/minecraft/world/entity/TamableAnimal.java
+++ b/net/minecraft/world/entity/TamableAnimal.java
@@ -27,6 +27,11 @@
import net.minecraft.world.level.pathfinder.PathType;
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator;
import net.minecraft.world.scores.PlayerTeam;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityTeleportEvent;
+// CraftBukkit end
public abstract class TamableAnimal extends Animal implements OwnableEntity {
@@ -85,7 +90,7 @@
}
this.orderedToSit = nbt.getBoolean("Sitting");
- this.setInSittingPose(this.orderedToSit);
+ this.setInSittingPose(this.orderedToSit, false); // Paper - Add EntityToggleSitEvent
}
@Override
@@ -96,8 +101,16 @@
@Override
public boolean handleLeashAtDistance(Entity leashHolder, float distance) {
if (this.isInSittingPose()) {
- if (distance > 10.0F) {
- this.dropLeash();
+ if (distance > (float) this.level().paperConfig().misc.maxLeashDistance.or(Leashable.LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance
+ // Paper start - Expand EntityUnleashEvent
+ org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(this.getBukkitEntity(), org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.DISTANCE, true);
+ if (!event.callEvent()) return false;
+ if (event.isDropLeash()) {
+ this.dropLeash();
+ } else {
+ this.removeLeash();
+ }
+ // Paper end - Expand EntityUnleashEvent
}
return false;
@@ -161,6 +174,12 @@
}
public void setInSittingPose(boolean inSittingPose) {
+ // Paper start - Add EntityToggleSitEvent
+ this.setInSittingPose(inSittingPose, true);
+ }
+ public void setInSittingPose(boolean inSittingPose, boolean callEvent) {
+ if (callEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), inSittingPose).callEvent()) return;
+ // Paper end - Add EntityToggleSitEvent
byte b0 = (Byte) this.entityData.get(TamableAnimal.DATA_FLAGS_ID);
if (inSittingPose) {
@@ -244,7 +263,12 @@
if (entityliving instanceof ServerPlayer) {
ServerPlayer entityplayer = (ServerPlayer) entityliving;
- entityplayer.sendSystemMessage(this.getCombatTracker().getDeathMessage());
+ // Paper start - Add TameableDeathMessageEvent
+ io.papermc.paper.event.entity.TameableDeathMessageEvent event = new io.papermc.paper.event.entity.TameableDeathMessageEvent((org.bukkit.entity.Tameable) getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getCombatTracker().getDeathMessage()));
+ if (event.callEvent()) {
+ entityplayer.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.deathMessage()));
+ }
+ // Paper end - Add TameableDeathMessageEvent
}
}
}
@@ -295,7 +319,14 @@
if (!this.canTeleportTo(new BlockPos(x, y, z))) {
return false;
} else {
- this.moveTo((double) x + 0.5D, (double) y, (double) z + 0.5D, this.getYRot(), this.getXRot());
+ // CraftBukkit start
+ EntityTeleportEvent event = CraftEventFactory.callEntityTeleportEvent(this, (double) x + 0.5D, (double) y, (double) z + 0.5D);
+ if (event.isCancelled() || event.getTo() == null) { // Paper - prevent NP on null event to location
+ return false;
+ }
+ Location to = event.getTo();
+ this.moveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch());
+ // CraftBukkit end
this.navigation.stop();
return true;
}

View File

@@ -0,0 +1,27 @@
--- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
+++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
@@ -153,20 +153,20 @@
double d = this.getBaseValue();
for (AttributeModifier attributeModifier : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_VALUE)) {
- d += attributeModifier.amount();
+ d += attributeModifier.amount(); // Paper - destroy speed API - diff on change
}
double e = d;
for (AttributeModifier attributeModifier2 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_BASE)) {
- e += d * attributeModifier2.amount();
+ e += d * attributeModifier2.amount(); // Paper - destroy speed API - diff on change
}
for (AttributeModifier attributeModifier3 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)) {
- e *= 1.0 + attributeModifier3.amount();
+ e *= 1.0 + attributeModifier3.amount(); // Paper - destroy speed API - diff on change
}
- return this.attribute.value().sanitizeValue(e);
+ return attribute.value().sanitizeValue(e); // Paper - destroy speed API - diff on change
}
private Collection<AttributeModifier> getModifiersOrEmpty(AttributeModifier.Operation operation) {

View File

@@ -0,0 +1,15 @@
--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java
+++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
@@ -162,4 +162,12 @@
}
}
}
+
+ // Paper - start - living entity allow attribute registration
+ public void registerAttribute(Holder<Attribute> attributeBase) {
+ AttributeInstance attributeModifiable = new AttributeInstance(attributeBase, AttributeInstance::getAttribute);
+ attributes.put(attributeBase, attributeModifiable);
+ }
+ // Paper - end - living entity allow attribute registration
+
}

View File

@@ -0,0 +1,31 @@
--- a/net/minecraft/world/entity/ai/attributes/Attributes.java
+++ b/net/minecraft/world/entity/ai/attributes/Attributes.java
@@ -1,3 +1,4 @@
+// mc-dev import
package net.minecraft.world.entity.ai.attributes;
import net.minecraft.core.Holder;
@@ -9,7 +10,7 @@
public static final Holder<Attribute> ARMOR = Attributes.register("armor", (new RangedAttribute("attribute.name.armor", 0.0D, 0.0D, 30.0D)).setSyncable(true));
public static final Holder<Attribute> ARMOR_TOUGHNESS = Attributes.register("armor_toughness", (new RangedAttribute("attribute.name.armor_toughness", 0.0D, 0.0D, 20.0D)).setSyncable(true));
- public static final Holder<Attribute> ATTACK_DAMAGE = Attributes.register("attack_damage", new RangedAttribute("attribute.name.attack_damage", 2.0D, 0.0D, 2048.0D));
+ public static final Holder<Attribute> ATTACK_DAMAGE = Attributes.register("attack_damage", new RangedAttribute("attribute.name.attack_damage", 2.0D, 0.0D, org.spigotmc.SpigotConfig.attackDamage));
public static final Holder<Attribute> ATTACK_KNOCKBACK = Attributes.register("attack_knockback", new RangedAttribute("attribute.name.attack_knockback", 0.0D, 0.0D, 5.0D));
public static final Holder<Attribute> ATTACK_SPEED = Attributes.register("attack_speed", (new RangedAttribute("attribute.name.attack_speed", 4.0D, 0.0D, 1024.0D)).setSyncable(true));
public static final Holder<Attribute> BLOCK_BREAK_SPEED = Attributes.register("block_break_speed", (new RangedAttribute("attribute.name.block_break_speed", 1.0D, 0.0D, 1024.0D)).setSyncable(true));
@@ -24,11 +25,11 @@
public static final Holder<Attribute> JUMP_STRENGTH = Attributes.register("jump_strength", (new RangedAttribute("attribute.name.jump_strength", 0.41999998688697815D, 0.0D, 32.0D)).setSyncable(true));
public static final Holder<Attribute> KNOCKBACK_RESISTANCE = Attributes.register("knockback_resistance", new RangedAttribute("attribute.name.knockback_resistance", 0.0D, 0.0D, 1.0D));
public static final Holder<Attribute> LUCK = Attributes.register("luck", (new RangedAttribute("attribute.name.luck", 0.0D, -1024.0D, 1024.0D)).setSyncable(true));
- public static final Holder<Attribute> MAX_ABSORPTION = Attributes.register("max_absorption", (new RangedAttribute("attribute.name.max_absorption", 0.0D, 0.0D, 2048.0D)).setSyncable(true));
- public static final Holder<Attribute> MAX_HEALTH = Attributes.register("max_health", (new RangedAttribute("attribute.name.max_health", 20.0D, 1.0D, 1024.0D)).setSyncable(true));
+ public static final Holder<Attribute> MAX_ABSORPTION = Attributes.register("max_absorption", (new RangedAttribute("attribute.name.max_absorption", 0.0D, 0.0D, org.spigotmc.SpigotConfig.maxAbsorption)).setSyncable(true));
+ public static final Holder<Attribute> MAX_HEALTH = Attributes.register("max_health", (new RangedAttribute("attribute.name.max_health", 20.0D, 1.0D, org.spigotmc.SpigotConfig.maxHealth)).setSyncable(true));
public static final Holder<Attribute> MINING_EFFICIENCY = Attributes.register("mining_efficiency", (new RangedAttribute("attribute.name.mining_efficiency", 0.0D, 0.0D, 1024.0D)).setSyncable(true));
public static final Holder<Attribute> MOVEMENT_EFFICIENCY = Attributes.register("movement_efficiency", (new RangedAttribute("attribute.name.movement_efficiency", 0.0D, 0.0D, 1.0D)).setSyncable(true));
- public static final Holder<Attribute> MOVEMENT_SPEED = Attributes.register("movement_speed", (new RangedAttribute("attribute.name.movement_speed", 0.7D, 0.0D, 1024.0D)).setSyncable(true));
+ public static final Holder<Attribute> MOVEMENT_SPEED = Attributes.register("movement_speed", (new RangedAttribute("attribute.name.movement_speed", 0.7D, 0.0D, org.spigotmc.SpigotConfig.movementSpeed)).setSyncable(true));
public static final Holder<Attribute> OXYGEN_BONUS = Attributes.register("oxygen_bonus", (new RangedAttribute("attribute.name.oxygen_bonus", 0.0D, 0.0D, 1024.0D)).setSyncable(true));
public static final Holder<Attribute> SAFE_FALL_DISTANCE = Attributes.register("safe_fall_distance", (new RangedAttribute("attribute.name.safe_fall_distance", 3.0D, -1024.0D, 1024.0D)).setSyncable(true));
public static final Holder<Attribute> SCALE = Attributes.register("scale", (new RangedAttribute("attribute.name.scale", 1.0D, 0.0625D, 16.0D)).setSyncable(true).setSentiment(Attribute.Sentiment.NEUTRAL));

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
+++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
@@ -70,6 +70,7 @@
return false;
} else {
mutableLong.setValue(time + 20L + (long)world.getRandom().nextInt(20));
+ if (entity.getNavigation().isStuck()) mutableLong.add(200); // Paper - Perf: Wait an additional 10s to check again if they're stuck
PoiManager poiManager = world.getPoiManager();
long2ObjectMap.long2ObjectEntrySet().removeIf(entry -> !entry.getValue().isStillValid(time));
Predicate<BlockPos> predicate2 = pos -> {

View File

@@ -0,0 +1,31 @@
--- a/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java
+++ b/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java
@@ -9,6 +9,12 @@
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.VillagerProfession;
+// CraftBukkit start
+import org.bukkit.craftbukkit.entity.CraftVillager;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.VillagerCareerChangeEvent;
+// CraftBukkit end
+
public class AssignProfessionFromJobSite {
public AssignProfessionFromJobSite() {}
@@ -37,7 +43,14 @@
return villagerprofession.heldJobSite().test(holder);
}).findFirst();
}).ifPresent((villagerprofession) -> {
- entityvillager.setVillagerData(entityvillager.getVillagerData().setProfession(villagerprofession));
+ // CraftBukkit start - Fire VillagerCareerChangeEvent where Villager gets employed
+ VillagerCareerChangeEvent event = CraftEventFactory.callVillagerCareerChangeEvent(entityvillager, CraftVillager.CraftProfession.minecraftToBukkit(villagerprofession), VillagerCareerChangeEvent.ChangeReason.EMPLOYED);
+ if (event.isCancelled()) {
+ return;
+ }
+
+ entityvillager.setVillagerData(entityvillager.getVillagerData().setProfession(CraftVillager.CraftProfession.bukkitToMinecraft(event.getProfession())));
+ // CraftBukkit end
entityvillager.refreshBrain(worldserver);
});
return true;

View File

@@ -0,0 +1,37 @@
--- a/net/minecraft/world/entity/ai/behavior/BabyFollowAdult.java
+++ b/net/minecraft/world/entity/ai/behavior/BabyFollowAdult.java
@@ -7,6 +7,12 @@
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.memory.WalkTarget;
+// CraftBukkit start
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
+// CraftBukkit end
public class BabyFollowAdult {
@@ -25,9 +31,20 @@
if (!entityageable.isBaby()) {
return false;
} else {
- AgeableMob entityageable1 = (AgeableMob) behaviorbuilder_b.get(memoryaccessor);
+ LivingEntity entityageable1 = (AgeableMob) behaviorbuilder_b.get(memoryaccessor); // CraftBukkit - type
if (entityageable.closerThan(entityageable1, (double) (executionRange.getMaxValue() + 1)) && !entityageable.closerThan(entityageable1, (double) executionRange.getMinValue())) {
+ // CraftBukkit start
+ EntityTargetLivingEntityEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityageable, entityageable1, EntityTargetEvent.TargetReason.FOLLOW_LEADER);
+ if (event.isCancelled()) {
+ return false;
+ }
+ if (event.getTarget() == null) {
+ memoryaccessor.erase();
+ return true;
+ }
+ entityageable1 = ((CraftLivingEntity) event.getTarget()).getHandle();
+ // CraftBukkit end
WalkTarget memorytarget = new WalkTarget(new EntityTracker(entityageable1, false), (Float) speed.apply(entityageable), executionRange.getMinValue() - 1);
memoryaccessor1.set(new EntityTracker(entityageable1, true));

View File

@@ -0,0 +1,40 @@
--- a/net/minecraft/world/entity/ai/behavior/Behavior.java
+++ b/net/minecraft/world/entity/ai/behavior/Behavior.java
@@ -14,6 +14,9 @@
private long endTimestamp;
private final int minDuration;
private final int maxDuration;
+ // Paper start - configurable behavior tick rate and timings
+ private final String configKey;
+ // Paper end - configurable behavior tick rate and timings
public Behavior(Map<MemoryModuleType<?>, MemoryStatus> requiredMemoryState) {
this(requiredMemoryState, 60);
@@ -27,6 +30,14 @@
this.minDuration = minRunTime;
this.maxDuration = maxRunTime;
this.entryCondition = requiredMemoryState;
+ // Paper start - configurable behavior tick rate and timings
+ String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName();
+ int lastSeparator = key.lastIndexOf('.');
+ if (lastSeparator != -1) {
+ key = key.substring(lastSeparator + 1);
+ }
+ this.configKey = key.toLowerCase(java.util.Locale.ROOT);
+ // Paper end - configurable behavior tick rate and timings
}
@Override
@@ -36,6 +47,12 @@
@Override
public final boolean tryStart(ServerLevel world, E entity, long time) {
+ // Paper start - configurable behavior tick rate and timings
+ int tickRate = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.behavior.get(entity.getType(), this.configKey), -1);
+ if (tickRate > -1 && time < this.endTimestamp + tickRate) {
+ return false;
+ }
+ // Paper end - configurable behavior tick rate and timings
if (this.hasRequiredMemories(entity) && this.checkExtraStartConditions(world, entity)) {
this.status = Behavior.Status.RUNNING;
int i = this.minDuration + world.getRandom().nextInt(this.maxDuration + 1 - this.minDuration);

View File

@@ -0,0 +1,64 @@
--- a/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java
+++ b/net/minecraft/world/entity/ai/behavior/BehaviorUtils.java
@@ -60,7 +60,7 @@
}
public static void lookAtEntity(LivingEntity entity, LivingEntity target) {
- entity.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, (Object) (new EntityTracker(target, true)));
+ entity.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, (new EntityTracker(target, true))); // CraftBukkit - decompile error
}
private static void setWalkAndLookTargetMemoriesToEachOther(LivingEntity first, LivingEntity second, float speed, int completionRange) {
@@ -79,8 +79,8 @@
public static void setWalkAndLookTargetMemories(LivingEntity entity, PositionTracker target, float speed, int completionRange) {
WalkTarget memorytarget = new WalkTarget(target, speed, completionRange);
- entity.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, (Object) target);
- entity.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (Object) memorytarget);
+ entity.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, target); // CraftBukkit - decompile error
+ entity.getBrain().setMemory(MemoryModuleType.WALK_TARGET, memorytarget); // CraftBukkit - decompile error
}
public static void throwItem(LivingEntity entity, ItemStack stack, Vec3 targetLocation) {
@@ -90,6 +90,7 @@
}
public static void throwItem(LivingEntity entity, ItemStack stack, Vec3 targetLocation, Vec3 velocityFactor, float yOffset) {
+ if (stack.isEmpty()) return; // CraftBukkit - SPIGOT-4940: no empty loot
double d0 = entity.getEyeY() - (double) yOffset;
ItemEntity entityitem = new ItemEntity(entity.level(), entity.getX(), d0, entity.getZ(), stack);
@@ -99,12 +100,19 @@
vec3d2 = vec3d2.normalize().multiply(velocityFactor.x, velocityFactor.y, velocityFactor.z);
entityitem.setDeltaMovement(vec3d2);
entityitem.setDefaultPickUpDelay();
+ // CraftBukkit start
+ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(entity.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity());
+ entityitem.level().getCraftServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return;
+ }
+ // CraftBukkit end
entity.level().addFreshEntity(entityitem);
}
public static SectionPos findSectionClosestToVillage(ServerLevel world, SectionPos center, int radius) {
int j = world.sectionsToVillage(center);
- Stream stream = SectionPos.cube(center, radius).filter((sectionposition1) -> {
+ Stream<SectionPos> stream = SectionPos.cube(center, radius).filter((sectionposition1) -> { // CraftBukkit - decompile error
return world.sectionsToVillage(sectionposition1) < j;
});
@@ -161,10 +169,10 @@
return optional.map((uuid) -> {
return ((ServerLevel) entity.level()).getEntity(uuid);
- }).map((entity) -> {
+ }).map((entity1) -> { // Paper - remap fix
LivingEntity entityliving1;
- if (entity instanceof LivingEntity entityliving2) {
+ if (entity1 instanceof LivingEntity entityliving2) { // Paper - remap fix
entityliving1 = entityliving2;
} else {
entityliving1 = null;

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java
+++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java
@@ -18,7 +18,7 @@
private final Set<MemoryModuleType<?>> exitErasedMemories;
private final GateBehavior.OrderPolicy orderPolicy;
private final GateBehavior.RunningPolicy runningPolicy;
- private final ShufflingList<BehaviorControl<? super E>> behaviors = new ShufflingList<>();
+ private final ShufflingList<BehaviorControl<? super E>> behaviors = new ShufflingList<>(false); // Paper - Fix Concurrency issue in ShufflingList during worldgen
private Behavior.Status status = Behavior.Status.STOPPED;
public GateBehavior(

View File

@@ -0,0 +1,24 @@
--- a/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java
+++ b/net/minecraft/world/entity/ai/behavior/GoToWantedItem.java
@@ -28,6 +28,21 @@
ItemEntity entityitem = (ItemEntity) behaviorbuilder_b.get(memoryaccessor2);
if (behaviorbuilder_b.tryGet(memoryaccessor3).isEmpty() && startCondition.test(entityliving) && entityitem.closerThan(entityliving, (double) radius) && entityliving.level().getWorldBorder().isWithinBounds(entityitem.blockPosition()) && entityliving.canPickUpLoot()) {
+ // CraftBukkit start
+ if (entityliving instanceof net.minecraft.world.entity.animal.allay.Allay) {
+ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetEvent(entityliving, entityitem, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY);
+
+ if (event.isCancelled()) {
+ return false;
+ }
+ if (!(event.getTarget() instanceof org.bukkit.craftbukkit.entity.CraftItem)) { // Paper - only erase allay memory on non-item targets
+ memoryaccessor2.erase();
+ return false; // Paper - only erase allay memory on non-item targets
+ }
+
+ entityitem = (ItemEntity) ((org.bukkit.craftbukkit.entity.CraftEntity) event.getTarget()).getHandle();
+ }
+ // CraftBukkit end
WalkTarget memorytarget = new WalkTarget(new EntityTracker(entityitem, false), speed, 0);
memoryaccessor.set(new EntityTracker(entityitem, true));

View File

@@ -0,0 +1,63 @@
--- a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
+++ b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
@@ -22,10 +22,15 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.gameevent.GameEvent;
+
+// CraftBukkit start
+import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.CropBlock;
import net.minecraft.world.level.block.FarmBlock;
import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.gameevent.GameEvent;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+// CraftBukkit end
public class HarvestFarmland extends Behavior<Villager> {
@@ -82,8 +87,8 @@
protected void start(ServerLevel worldserver, Villager entityvillager, long i) {
if (i > this.nextOkStartTime && this.aboveFarmlandPos != null) {
- entityvillager.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, (Object) (new BlockPosTracker(this.aboveFarmlandPos)));
- entityvillager.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (Object) (new WalkTarget(new BlockPosTracker(this.aboveFarmlandPos), 0.5F, 1)));
+ entityvillager.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, (new BlockPosTracker(this.aboveFarmlandPos))); // CraftBukkit - decompile error
+ entityvillager.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (new WalkTarget(new BlockPosTracker(this.aboveFarmlandPos), 0.5F, 1))); // CraftBukkit - decompile error
}
}
@@ -103,7 +108,9 @@
Block block1 = world.getBlockState(this.aboveFarmlandPos.below()).getBlock();
if (block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata)) {
+ if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit // Paper - fix wrong block state
world.destroyBlock(this.aboveFarmlandPos, true, entity);
+ } // CraftBukkit
}
if (iblockdata.isAir() && block1 instanceof FarmBlock && entity.hasFarmSeeds()) {
@@ -120,9 +127,11 @@
BlockItem itemblock = (BlockItem) item;
BlockState iblockdata1 = itemblock.getBlock().defaultBlockState();
+ if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, iblockdata1)) { // CraftBukkit
world.setBlockAndUpdate(this.aboveFarmlandPos, iblockdata1);
world.gameEvent((Holder) GameEvent.BLOCK_PLACE, this.aboveFarmlandPos, GameEvent.Context.of(entity, iblockdata1));
flag = true;
+ } // CraftBukkit
}
}
@@ -142,8 +151,8 @@
this.aboveFarmlandPos = this.getValidFarmland(world);
if (this.aboveFarmlandPos != null) {
this.nextOkStartTime = time + 20L;
- entity.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (Object) (new WalkTarget(new BlockPosTracker(this.aboveFarmlandPos), 0.5F, 1)));
- entity.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, (Object) (new BlockPosTracker(this.aboveFarmlandPos)));
+ entity.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (new WalkTarget(new BlockPosTracker(this.aboveFarmlandPos), 0.5F, 1))); // CraftBukkit - decompile error
+ entity.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, (new BlockPosTracker(this.aboveFarmlandPos))); // CraftBukkit - decompile error
}
}
}

View File

@@ -0,0 +1,39 @@
--- a/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java
+++ b/net/minecraft/world/entity/ai/behavior/InteractWithDoor.java
@@ -61,6 +61,13 @@
DoorBlock blockdoor = (DoorBlock) iblockdata.getBlock();
if (!blockdoor.isOpen(iblockdata)) {
+ // CraftBukkit start - entities opening doors
+ org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(entityliving.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(entityliving.level(), blockposition));
+ entityliving.level().getCraftServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return false;
+ }
+ // CraftBukkit end
blockdoor.setOpen(entityliving, worldserver, iblockdata, blockposition, true);
}
@@ -76,6 +83,13 @@
DoorBlock blockdoor1 = (DoorBlock) iblockdata1.getBlock();
if (!blockdoor1.isOpen(iblockdata1)) {
+ // CraftBukkit start - entities opening doors
+ org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(entityliving.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(entityliving.level(), blockposition1));
+ entityliving.level().getCraftServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return false;
+ }
+ // CraftBukkit end
blockdoor1.setOpen(entityliving, worldserver, iblockdata1, blockposition1, true);
optional = InteractWithDoor.rememberDoorToClose(memoryaccessor1, optional, worldserver, blockposition1);
}
@@ -129,7 +143,7 @@
}
private static boolean areOtherMobsComingThroughDoor(LivingEntity entity, BlockPos pos, Optional<List<LivingEntity>> otherMobs) {
- return otherMobs.isEmpty() ? false : ((List) otherMobs.get()).stream().filter((entityliving1) -> {
+ return otherMobs.isEmpty() ? false : (otherMobs.get()).stream().filter((entityliving1) -> { // CraftBukkit - decompile error
return entityliving1.getType() == entity.getType();
}).filter((entityliving1) -> {
return pos.closerToCenterThan(entityliving1.position(), 2.0D);

View File

@@ -0,0 +1,73 @@
--- a/net/minecraft/world/entity/ai/behavior/PrepareRamNearestTarget.java
+++ b/net/minecraft/world/entity/ai/behavior/PrepareRamNearestTarget.java
@@ -13,6 +13,7 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
@@ -30,6 +31,10 @@
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator;
import net.minecraft.world.phys.Vec3;
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityTargetEvent;
+// CraftBukkit end
public class PrepareRamNearestTarget<E extends PathfinderMob> extends Behavior<E> {
@@ -63,6 +68,13 @@
return this.ramTargeting.test(worldserver, entitycreature, entityliving);
});
}).ifPresent((entityliving) -> {
+ // CraftBukkit start
+ EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entitycreature, entityliving, (entityliving instanceof ServerPlayer) ? EntityTargetEvent.TargetReason.CLOSEST_PLAYER : EntityTargetEvent.TargetReason.CLOSEST_ENTITY);
+ if (event.isCancelled() || event.getTarget() == null) {
+ return;
+ }
+ entityliving = ((CraftLivingEntity) event.getTarget()).getHandle();
+ // CraftBukkit end
this.chooseRamPosition(entitycreature, entityliving);
});
}
@@ -72,7 +84,7 @@
if (!behaviorcontroller.hasMemoryValue(MemoryModuleType.RAM_TARGET)) {
world.broadcastEntityEvent(entity, (byte) 59);
- behaviorcontroller.setMemory(MemoryModuleType.RAM_COOLDOWN_TICKS, (Object) this.getCooldownOnFail.applyAsInt(entity));
+ behaviorcontroller.setMemory(MemoryModuleType.RAM_COOLDOWN_TICKS, this.getCooldownOnFail.applyAsInt(entity)); // CraftBukkit - decompile error
}
}
@@ -83,8 +95,8 @@
protected void tick(ServerLevel worldserver, E e0, long i) {
if (!this.ramCandidate.isEmpty()) {
- e0.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (Object) (new WalkTarget(((PrepareRamNearestTarget.RamCandidate) this.ramCandidate.get()).getStartPosition(), this.walkSpeed, 0)));
- e0.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, (Object) (new EntityTracker(((PrepareRamNearestTarget.RamCandidate) this.ramCandidate.get()).getTarget(), true)));
+ e0.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (new WalkTarget(((PrepareRamNearestTarget.RamCandidate) this.ramCandidate.get()).getStartPosition(), this.walkSpeed, 0))); // CraftBukkit - decompile error
+ e0.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, (new EntityTracker(((PrepareRamNearestTarget.RamCandidate) this.ramCandidate.get()).getTarget(), true))); // CraftBukkit - decompile error
boolean flag = !((PrepareRamNearestTarget.RamCandidate) this.ramCandidate.get()).getTarget().blockPosition().equals(((PrepareRamNearestTarget.RamCandidate) this.ramCandidate.get()).getTargetPosition());
if (flag) {
@@ -101,7 +113,7 @@
}
if (i - (Long) this.reachedRamPositionTimestamp.get() >= (long) this.ramPrepareTime) {
- e0.getBrain().setMemory(MemoryModuleType.RAM_TARGET, (Object) this.getEdgeOfBlock(blockposition, ((PrepareRamNearestTarget.RamCandidate) this.ramCandidate.get()).getTargetPosition()));
+ e0.getBrain().setMemory(MemoryModuleType.RAM_TARGET, this.getEdgeOfBlock(blockposition, ((PrepareRamNearestTarget.RamCandidate) this.ramCandidate.get()).getTargetPosition())); // CraftBukkit - decompile error
worldserver.playSound((Player) null, (Entity) e0, (SoundEvent) this.getPrepareRamSound.apply(e0), SoundSource.NEUTRAL, 1.0F, e0.getVoicePitch());
this.ramCandidate = Optional.empty();
}
@@ -153,7 +165,7 @@
}
PathNavigation navigationabstract = entity.getNavigation();
- Stream stream = list.stream();
+ Stream<BlockPos> stream = list.stream(); // CraftBukkit - decompile error
BlockPos blockposition1 = entity.blockPosition();
Objects.requireNonNull(blockposition1);

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/behavior/RamTarget.java
+++ b/net/minecraft/world/entity/ai/behavior/RamTarget.java
@@ -89,7 +89,7 @@
float f = 0.25F * (float)(i - j);
float g = Mth.clamp(entity.getSpeed() * 1.65F, 0.2F, 3.0F) + f;
float h = livingEntity.isDamageSourceBlocked(world.damageSources().mobAttack(entity)) ? 0.5F : 1.0F;
- livingEntity.knockback((double)(h * g) * this.getKnockbackForce.applyAsDouble(entity), this.ramDirection.x(), this.ramDirection.z());
+ livingEntity.knockback(h * g * this.getKnockbackForce.applyAsDouble(entity), this.ramDirection.x(), this.ramDirection.z(), entity, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
this.finishRam(world, entity);
world.playSound(null, entity, this.getImpactSound.apply(entity), SoundSource.NEUTRAL, 1.0F, 1.0F);
} else if (this.hasRammedHornBreakingBlock(world, entity)) {

View File

@@ -0,0 +1,31 @@
--- a/net/minecraft/world/entity/ai/behavior/ResetProfession.java
+++ b/net/minecraft/world/entity/ai/behavior/ResetProfession.java
@@ -6,6 +6,12 @@
import net.minecraft.world.entity.npc.VillagerData;
import net.minecraft.world.entity.npc.VillagerProfession;
+// CraftBukkit start
+import org.bukkit.craftbukkit.entity.CraftVillager;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.VillagerCareerChangeEvent;
+// CraftBukkit end
+
public class ResetProfession {
public ResetProfession() {}
@@ -17,7 +23,14 @@
VillagerData villagerdata = entityvillager.getVillagerData();
if (villagerdata.getProfession() != VillagerProfession.NONE && villagerdata.getProfession() != VillagerProfession.NITWIT && entityvillager.getVillagerXp() == 0 && villagerdata.getLevel() <= 1) {
- entityvillager.setVillagerData(entityvillager.getVillagerData().setProfession(VillagerProfession.NONE));
+ // CraftBukkit start
+ VillagerCareerChangeEvent event = CraftEventFactory.callVillagerCareerChangeEvent(entityvillager, CraftVillager.CraftProfession.minecraftToBukkit(VillagerProfession.NONE), VillagerCareerChangeEvent.ChangeReason.LOSING_JOB);
+ if (event.isCancelled()) {
+ return false;
+ }
+
+ entityvillager.setVillagerData(entityvillager.getVillagerData().setProfession(CraftVillager.CraftProfession.bukkitToMinecraft(event.getProfession())));
+ // CraftBukkit end
entityvillager.refreshBrain(worldserver);
return true;
} else {

View File

@@ -0,0 +1,44 @@
--- a/net/minecraft/world/entity/ai/behavior/ShufflingList.java
+++ b/net/minecraft/world/entity/ai/behavior/ShufflingList.java
@@ -16,12 +16,25 @@
public class ShufflingList<U> implements Iterable<U> {
protected final List<ShufflingList.WeightedEntry<U>> entries;
private final RandomSource random = RandomSource.create();
+ private final boolean isUnsafe; // Paper - Fix Concurrency issue in ShufflingList during worldgen
public ShufflingList() {
+ // Paper start - Fix Concurrency issue in ShufflingList during worldgen
+ this(true);
+ }
+ public ShufflingList(boolean isUnsafe) {
+ this.isUnsafe = isUnsafe;
+ // Paper end - Fix Concurrency issue in ShufflingList during worldgen
this.entries = Lists.newArrayList();
}
private ShufflingList(List<ShufflingList.WeightedEntry<U>> list) {
+ // Paper start - Fix Concurrency issue in ShufflingList during worldgen
+ this(list, true);
+ }
+ private ShufflingList(List<ShufflingList.WeightedEntry<U>> list, boolean isUnsafe) {
+ this.isUnsafe = isUnsafe;
+ // Paper end - Fix Concurrency issue in ShufflingList during worldgen
this.entries = Lists.newArrayList(list);
}
@@ -35,9 +48,12 @@
}
public ShufflingList<U> shuffle() {
- this.entries.forEach(entry -> entry.setRandom(this.random.nextFloat()));
- this.entries.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight));
- return this;
+ // Paper start - Fix Concurrency issue in ShufflingList during worldgen
+ List<ShufflingList.WeightedEntry<U>> list = this.isUnsafe ? Lists.newArrayList(this.entries) : this.entries;
+ list.forEach(entry -> entry.setRandom(this.random.nextFloat()));
+ list.sort(Comparator.comparingDouble(ShufflingList.WeightedEntry::getRandWeight));
+ return this.isUnsafe ? new ShufflingList<>(list, this.isUnsafe) : this;
+ // Paper end - Fix Concurrency issue in ShufflingList during worldgen
}
public Stream<U> stream() {

View File

@@ -0,0 +1,12 @@
--- a/net/minecraft/world/entity/ai/behavior/SleepInBed.java
+++ b/net/minecraft/world/entity/ai/behavior/SleepInBed.java
@@ -42,7 +42,8 @@
}
}
- BlockState blockState = world.getBlockState(globalPos.pos());
+ BlockState blockState = world.getBlockStateIfLoaded(globalPos.pos()); // Paper - Prevent sync chunk loads when villagers try to find beds
+ if (blockState == null) { return false; } // Paper - Prevent sync chunk loads when villagers try to find beds
return globalPos.pos().closerToCenterThan(entity.position(), 2.0) && blockState.is(BlockTags.BEDS) && !blockState.getValue(BedBlock.OCCUPIED);
}
}

View File

@@ -0,0 +1,36 @@
--- a/net/minecraft/world/entity/ai/behavior/StartAttacking.java
+++ b/net/minecraft/world/entity/ai/behavior/StartAttacking.java
@@ -2,10 +2,15 @@
import java.util.Optional;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityTargetEvent;
+// CraftBukkit end
public class StartAttacking {
@@ -34,6 +39,17 @@
if (!entityinsentient.canAttack(entityliving)) {
return false;
} else {
+ // CraftBukkit start
+ EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, entityliving, (entityliving instanceof ServerPlayer) ? EntityTargetEvent.TargetReason.CLOSEST_PLAYER : EntityTargetEvent.TargetReason.CLOSEST_ENTITY);
+ if (event.isCancelled()) {
+ return false;
+ }
+ if (event.getTarget() == null) {
+ memoryaccessor.erase();
+ return true;
+ }
+ entityliving = ((CraftLivingEntity) event.getTarget()).getHandle();
+ // CraftBukkit end
memoryaccessor.set(entityliving);
memoryaccessor1.erase();
return true;

View File

@@ -0,0 +1,46 @@
--- a/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
+++ b/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
@@ -7,6 +7,12 @@
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
+// CraftBukkit start
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityTargetEvent;
+// CraftBukkit end
+
public class StopAttackingIfTargetInvalid {
private static final int TIMEOUT_TO_GET_WITHIN_ATTACK_RANGE = 200;
@@ -40,6 +46,30 @@
if (entityinsentient.canAttack(entityliving) && (!shouldForgetIfTargetUnreachable || !StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) && entityliving.isAlive() && entityliving.level() == entityinsentient.level() && !condition.test(worldserver, entityliving)) {
return true;
} else {
+ // Paper start - better track target change reason
+ final EntityTargetEvent.TargetReason reason;
+ if (!entityinsentient.canAttack(entityliving)) {
+ reason = EntityTargetEvent.TargetReason.TARGET_INVALID;
+ } else if (shouldForgetIfTargetUnreachable && StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) {
+ reason = EntityTargetEvent.TargetReason.FORGOT_TARGET;
+ } else if (!entityliving.isAlive()) {
+ reason = EntityTargetEvent.TargetReason.TARGET_DIED;
+ } else if (entityliving.level() != entityinsentient.level()) {
+ reason = EntityTargetEvent.TargetReason.TARGET_OTHER_LEVEL;
+ } else {
+ reason = EntityTargetEvent.TargetReason.TARGET_INVALID;
+ }
+ // Paper end
+ // CraftBukkit start
+ EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, null, reason); // Paper
+ if (event.isCancelled()) {
+ return false;
+ }
+ if (event.getTarget() != null) {
+ entityinsentient.getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, ((CraftLivingEntity) event.getTarget()).getHandle());
+ return true;
+ }
+ // CraftBukkit end
callback.accept(worldserver, entityinsentient, entityliving);
memoryaccessor.erase();
return true;

View File

@@ -0,0 +1,15 @@
--- a/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnWaterNearLand.java
+++ b/net/minecraft/world/entity/ai/behavior/TryLaySpawnOnWaterNearLand.java
@@ -39,6 +39,12 @@
if (worldserver.getBlockState(blockposition2).isAir()) {
BlockState iblockdata = frogSpawn.defaultBlockState();
+ // CraftBukkit start
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entityliving, blockposition2, iblockdata)) {
+ memoryaccessor2.erase();
+ return true;
+ }
+ // CraftBukkit end
worldserver.setBlock(blockposition2, iblockdata, 3);
worldserver.gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition2, GameEvent.Context.of(entityliving, iblockdata));
worldserver.playSound((Player) null, (Entity) entityliving, SoundEvents.FROG_LAY_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F);

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
+++ b/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
@@ -42,7 +42,7 @@
Pair.of(1, new MoveToTargetSink()),
Pair.of(2, PoiCompetitorScan.create()),
Pair.of(3, new LookAndFollowTradingPlayerSink(speed)),
- Pair.of(5, GoToWantedItem.create(speed, false, 4)),
+ Pair.of(5, GoToWantedItem.create(villager -> !villager.isSleeping(), speed, false, 4)), // Paper - Fix MC-157464
Pair.of(
6,
AcquirePoi.create(

View File

@@ -0,0 +1,42 @@
--- a/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java
+++ b/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java
@@ -17,6 +17,10 @@
import net.minecraft.world.entity.ai.village.poi.PoiTypes;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.level.pathfinder.Path;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+// CraftBukkit end
public class VillagerMakeLove extends Behavior<Villager> {
@@ -114,11 +118,17 @@
if (entityvillager2 == null) {
return Optional.empty();
} else {
- parent.setAge(6000);
- partner.setAge(6000);
entityvillager2.setAge(-24000);
entityvillager2.moveTo(parent.getX(), parent.getY(), parent.getZ(), 0.0F, 0.0F);
- world.addFreshEntityWithPassengers(entityvillager2);
+ // CraftBukkit start - call EntityBreedEvent
+ if (CraftEventFactory.callEntityBreedEvent(entityvillager2, parent, partner, null, null, 0).isCancelled()) {
+ return Optional.empty();
+ }
+ // Move age setting down
+ parent.setAge(6000);
+ partner.setAge(6000);
+ world.addFreshEntityWithPassengers(entityvillager2, CreatureSpawnEvent.SpawnReason.BREEDING);
+ // CraftBukkit end
world.broadcastEntityEvent(entityvillager2, (byte) 12);
return Optional.of(entityvillager2);
}
@@ -127,6 +137,6 @@
private void giveBedToChild(ServerLevel world, Villager child, BlockPos pos) {
GlobalPos globalpos = GlobalPos.of(world.dimension(), pos);
- child.getBrain().setMemory(MemoryModuleType.HOME, (Object) globalpos);
+ child.getBrain().setMemory(MemoryModuleType.HOME, globalpos); // CraftBukkit - decompile error
}
}

View File

@@ -0,0 +1,12 @@
--- a/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java
+++ b/net/minecraft/world/entity/ai/behavior/WorkAtComposter.java
@@ -86,7 +86,9 @@
simpleContainer.removeItemType(Items.WHEAT, m);
ItemStack itemStack = simpleContainer.addItem(new ItemStack(Items.BREAD, l));
if (!itemStack.isEmpty()) {
+ villager.forceDrops = true; // Paper - Add missing forceDrop toggles
villager.spawnAtLocation(world, itemStack, 0.5F);
+ villager.forceDrops = false; // Paper - Add missing forceDrop toggles
}
}
}

View File

@@ -0,0 +1,22 @@
--- a/net/minecraft/world/entity/ai/behavior/warden/Digging.java
+++ b/net/minecraft/world/entity/ai/behavior/warden/Digging.java
@@ -10,6 +10,10 @@
import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.entity.monster.warden.Warden;
+// CraftBukkit start - imports
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
+
public class Digging<E extends Warden> extends Behavior<E> {
public Digging(int duration) {
@@ -37,7 +41,7 @@
protected void stop(ServerLevel worldserver, E e0, long i) {
if (e0.getRemovalReason() == null) {
- e0.remove(Entity.RemovalReason.DISCARDED);
+ e0.remove(Entity.RemovalReason.DISCARDED, EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - Add bukkit remove cause
}
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java
+++ b/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java
@@ -83,7 +83,7 @@
if (target.hurtServer(world, world.damageSources().sonicBoom(entity), 10.0F)) {
double d = 0.5 * (1.0 - target.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE));
double e = 2.5 * (1.0 - target.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE));
- target.push(vec33.x() * e, vec33.y() * d, vec33.z() * e);
+ target.push(vec33.x() * e, vec33.y() * d, vec33.z() * e, entity); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
}
});
}

View File

@@ -0,0 +1,20 @@
--- a/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
+++ b/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
@@ -72,9 +72,16 @@
}
if (this.breakTime == this.getDoorBreakTime() && this.isValidDifficulty(this.mob.level().getDifficulty())) {
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreakDoorEvent(this.mob, this.doorPos, this.mob.level().getFluidState(this.doorPos).createLegacyBlock()).isCancelled()) { // Paper - fix wrong block state
+ this.start();
+ return;
+ }
+ // CraftBukkit end
+ final net.minecraft.world.level.block.state.BlockState oldState = this.mob.level().getBlockState(this.doorPos); // Paper - fix MC-263999
this.mob.level().removeBlock(this.doorPos, false);
this.mob.level().levelEvent(1021, this.doorPos, 0);
- this.mob.level().levelEvent(2001, this.doorPos, Block.getId(this.mob.level().getBlockState(this.doorPos)));
+ this.mob.level().levelEvent(2001, this.doorPos, Block.getId(oldState)); // Paper - fix MC-263999
}
}

View File

@@ -0,0 +1,46 @@
--- a/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
+++ b/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
@@ -11,6 +11,10 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.predicate.BlockStatePredicate;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+// CraftBukkit end
+
public class EatBlockGoal extends Goal {
private static final int EAT_ANIMATION_TICKS = 40;
@@ -27,6 +31,11 @@
@Override
public boolean canUse() {
+ // Paper start - Fix MC-210802
+ if (!((net.minecraft.server.level.ServerLevel) this.level).chunkSource.chunkMap.anyPlayerCloseEnoughForSpawning(this.mob.chunkPosition())) {
+ return false;
+ }
+ // Paper end
if (this.mob.getRandom().nextInt(this.mob.isBaby() ? 50 : 1000) != 0) {
return false;
} else {
@@ -63,8 +72,9 @@
if (this.eatAnimationTick == this.adjustedTickDelay(4)) {
BlockPos blockposition = this.mob.blockPosition();
- if (EatBlockGoal.IS_TALL_GRASS.test(this.level.getBlockState(blockposition))) {
- if (getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
+ final BlockState blockState = this.level.getBlockState(blockposition); // Paper - fix wrong block state
+ if (EatBlockGoal.IS_TALL_GRASS.test(blockState)) { // Paper - fix wrong block state
+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, blockState.getFluidState().createLegacyBlock(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state
this.level.destroyBlock(blockposition, false);
}
@@ -73,7 +83,7 @@
BlockPos blockposition1 = blockposition.below();
if (this.level.getBlockState(blockposition1).is(Blocks.GRASS_BLOCK)) {
- if (getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.DIRT.defaultBlockState(), !getServerLevel(this.level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state
this.level.levelEvent(2001, blockposition1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState()));
this.level.setBlock(blockposition1, Blocks.DIRT.defaultBlockState(), 2);
}

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/world/entity/ai/goal/FloatGoal.java
+++ b/net/minecraft/world/entity/ai/goal/FloatGoal.java
@@ -9,6 +9,7 @@
public FloatGoal(Mob mob) {
this.mob = mob;
+ if (mob.getCommandSenderWorld().paperConfig().entities.behavior.spawnerNerfedMobsShouldJump) mob.goalFloat = this; // Paper - Allow nerfed mobs to jump and float
this.setFlags(EnumSet.of(Goal.Flag.JUMP));
mob.getNavigation().setCanFloat(true);
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java
+++ b/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java
@@ -72,7 +72,7 @@
public void tick() {
boolean bl = this.tamable.shouldTryTeleportToOwner();
if (!bl) {
- this.tamable.getLookControl().setLookAt(this.owner, 10.0F, (float)this.tamable.getMaxHeadXRot());
+ if (this.tamable.distanceToSqr(this.owner) <= 16 * 16) this.tamable.getLookControl().setLookAt(this.owner, 10.0F, (float)this.tamable.getMaxHeadXRot()); // Paper - Limit pet look distance
}
if (--this.timeToRecalcPath <= 0) {

View File

@@ -0,0 +1,39 @@
--- a/net/minecraft/world/entity/ai/goal/Goal.java
+++ b/net/minecraft/world/entity/ai/goal/Goal.java
@@ -46,6 +46,16 @@
return this.flags;
}
+ // Paper start - Mob Goal API
+ public boolean hasFlag(final Goal.Flag flag) {
+ return this.flags.contains(flag);
+ }
+
+ public void addFlag(final Goal.Flag flag) {
+ this.flags.add(flag);
+ }
+ // Paper end - Mob Goal API
+
protected int adjustedTickDelay(int ticks) {
return this.requiresUpdateEveryTick() ? ticks : reducedTickDelay(ticks);
}
@@ -62,7 +72,19 @@
return (ServerLevel)world;
}
+ // Paper start - Mob goal api
+ private com.destroystokyo.paper.entity.ai.PaperVanillaGoal<?> vanillaGoal;
+ public <T extends org.bukkit.entity.Mob> com.destroystokyo.paper.entity.ai.Goal<T> asPaperVanillaGoal() {
+ if(this.vanillaGoal == null) {
+ this.vanillaGoal = new com.destroystokyo.paper.entity.ai.PaperVanillaGoal<>(this);
+ }
+ //noinspection unchecked
+ return (com.destroystokyo.paper.entity.ai.Goal<T>) this.vanillaGoal;
+ }
+ // Paper end - Mob goal api
+
public static enum Flag {
+ UNKNOWN_BEHAVIOR, // Paper - add UNKNOWN_BEHAVIOR
MOVE,
LOOK,
JUMP,

View File

@@ -0,0 +1,55 @@
--- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
+++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
@@ -21,6 +21,10 @@
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+// CraftBukkit end
public class RemoveBlockGoal extends MoveToBlockGoal {
@@ -97,6 +101,11 @@
}
if (this.ticksSinceReachedGoal > 60) {
+ // CraftBukkit start - Step on eggs
+ if (!CraftEventFactory.callEntityInteractEvent(this.removerMob, CraftBlock.at(world, blockposition1))) {
+ return;
+ }
+ // CraftBukkit end
world.removeBlock(blockposition1, false);
if (!world.isClientSide) {
for (int i = 0; i < 20; ++i) {
@@ -118,7 +127,9 @@
@Nullable
private BlockPos getPosWithBlock(BlockPos pos, BlockGetter world) {
- if (world.getBlockState(pos).is(this.blockToRemove)) {
+ net.minecraft.world.level.block.state.BlockState block = world.getBlockStateIfLoaded(pos); // Paper - Prevent AI rules from loading chunks
+ if (block == null) return null; // Paper - Prevent AI rules from loading chunks
+ if (block.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks
return pos;
} else {
BlockPos[] ablockposition = new BlockPos[]{pos.below(), pos.west(), pos.east(), pos.north(), pos.south(), pos.below().below()};
@@ -128,7 +139,8 @@
for (int j = 0; j < i; ++j) {
BlockPos blockposition1 = ablockposition1[j];
- if (world.getBlockState(blockposition1).is(this.blockToRemove)) {
+ net.minecraft.world.level.block.state.BlockState block2 = world.getBlockStateIfLoaded(blockposition1); // Paper - Prevent AI rules from loading chunks
+ if (block2 != null && block2.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks
return blockposition1;
}
}
@@ -139,7 +151,7 @@
@Override
protected boolean isValidTarget(LevelReader world, BlockPos pos) {
- ChunkAccess ichunkaccess = world.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()), ChunkStatus.FULL, false);
+ ChunkAccess ichunkaccess = world.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); // Paper - Prevent AI rules from loading chunks
return ichunkaccess == null ? false : ichunkaccess.getBlockState(pos).is(this.blockToRemove) && ichunkaccess.getBlockState(pos.above()).isAir() && ichunkaccess.getBlockState(pos.above(2)).isAir();
}

View File

@@ -0,0 +1,22 @@
--- a/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java
+++ b/net/minecraft/world/entity/ai/goal/RunAroundLikeCrazyGoal.java
@@ -6,6 +6,10 @@
import net.minecraft.world.entity.animal.horse.AbstractHorse;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+// CraftBukkit end
public class RunAroundLikeCrazyGoal extends Goal {
@@ -63,7 +67,7 @@
int i = this.horse.getTemper();
int j = this.horse.getMaxTemper();
- if (j > 0 && this.horse.getRandom().nextInt(j) < i) {
+ if (j > 0 && this.horse.getRandom().nextInt(j) < i && !CraftEventFactory.callEntityTameEvent(this.horse, ((CraftHumanEntity) this.horse.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { // CraftBukkit - fire EntityTameEvent
this.horse.tameWithName(entityhuman);
return;
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/goal/SitWhenOrderedToGoal.java
+++ b/net/minecraft/world/entity/ai/goal/SitWhenOrderedToGoal.java
@@ -22,7 +22,7 @@
@Override
public boolean canUse() {
if (!this.mob.isTame()) {
- return false;
+ return this.mob.isOrderedToSit() && this.mob.getTarget() == null; // CraftBukkit - Allow sitting for wild animals
} else if (this.mob.isInWaterOrBubble()) {
return false;
} else if (!this.mob.onGround()) {

View File

@@ -0,0 +1,17 @@
--- a/net/minecraft/world/entity/ai/goal/SwellGoal.java
+++ b/net/minecraft/world/entity/ai/goal/SwellGoal.java
@@ -21,7 +21,14 @@
return this.creeper.getSwellDir() > 0 || livingEntity != null && this.creeper.distanceToSqr(livingEntity) < 9.0;
}
+ // Paper start - Fix MC-179072
@Override
+ public boolean canContinueToUse() {
+ return !net.minecraft.world.entity.EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(this.creeper.getTarget()) && canUse();
+ }
+ // Paper end
+
+ @Override
public void start() {
this.creeper.getNavigation().stop();
this.target = this.creeper.getTarget();

View File

@@ -0,0 +1,44 @@
--- a/net/minecraft/world/entity/ai/goal/TemptGoal.java
+++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java
@@ -8,9 +8,15 @@
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
-import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
+// CraftBukkit start
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
+// CraftBukkit end
+
public class TemptGoal extends Goal {
private static final TargetingConditions TEMPT_TARGETING = TargetingConditions.forNonCombat().ignoreLineOfSight();
@@ -23,7 +29,7 @@
private double pRotX;
private double pRotY;
@Nullable
- protected Player player;
+ protected LivingEntity player; // CraftBukkit
private int calmDown;
private boolean isRunning;
private final Predicate<ItemStack> items;
@@ -47,6 +53,15 @@
return false;
} else {
this.player = getServerLevel((Entity) this.mob).getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob);
+ // CraftBukkit start
+ if (this.player != null) {
+ EntityTargetLivingEntityEvent event = CraftEventFactory.callEntityTargetLivingEvent(this.mob, this.player, EntityTargetEvent.TargetReason.TEMPT);
+ if (event.isCancelled()) {
+ return false;
+ }
+ this.player = (event.getTarget() == null) ? null : ((CraftLivingEntity) event.getTarget()).getHandle();
+ }
+ // CraftBukkit end
return this.player != null;
}
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java
@@ -61,7 +61,7 @@
@Override
public void start() {
- this.golem.setTarget(this.potentialTarget);
+ this.golem.setTarget(this.potentialTarget, org.bukkit.event.entity.EntityTargetEvent.TargetReason.DEFEND_VILLAGE, true); // CraftBukkit - reason
super.start();
}
}

View File

@@ -0,0 +1,19 @@
--- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
@@ -67,7 +67,7 @@
@Override
public void start() {
- this.mob.setTarget(this.mob.getLastHurtByMob());
+ this.mob.setTarget(this.mob.getLastHurtByMob(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY, true); // CraftBukkit - reason
this.targetMob = this.mob.getTarget();
this.timestamp = this.mob.getLastHurtByMobTimestamp();
this.unseenMemoryTicks = 300;
@@ -114,6 +114,6 @@
}
protected void alertOther(Mob mob, LivingEntity target) {
- mob.setTarget(target);
+ mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit - reason
}
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
@@ -70,7 +70,7 @@
@Override
public void start() {
- this.mob.setTarget(this.target);
+ this.mob.setTarget(this.target, this.target instanceof ServerPlayer ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY, true); // CraftBukkit - reason
super.start();
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/goal/target/OwnerHurtByTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/OwnerHurtByTargetGoal.java
@@ -38,7 +38,7 @@
@Override
public void start() {
- this.mob.setTarget(this.ownerLastHurtBy);
+ this.mob.setTarget(this.ownerLastHurtBy, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_OWNER, true); // CraftBukkit - reason
LivingEntity entityliving = this.tameAnimal.getOwner();
if (entityliving != null) {

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/goal/target/OwnerHurtTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/OwnerHurtTargetGoal.java
@@ -38,7 +38,7 @@
@Override
public void start() {
- this.mob.setTarget(this.ownerLastHurt);
+ this.mob.setTarget(this.ownerLastHurt, org.bukkit.event.entity.EntityTargetEvent.TargetReason.OWNER_ATTACKED_TARGET, true); // CraftBukkit - reason
LivingEntity entityliving = this.tameAnimal.getOwner();
if (entityliving != null) {

View File

@@ -0,0 +1,30 @@
--- a/net/minecraft/world/entity/ai/goal/target/TargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/TargetGoal.java
@@ -10,6 +10,9 @@
import net.minecraft.world.level.pathfinder.Node;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.scores.PlayerTeam;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityTargetEvent;
+// CraftBukkit end
public abstract class TargetGoal extends Goal {
@@ -69,7 +72,7 @@
}
}
- this.mob.setTarget(entityliving);
+ this.mob.setTarget(entityliving, EntityTargetEvent.TargetReason.CLOSEST_ENTITY, true); // CraftBukkit
return true;
}
}
@@ -89,7 +92,7 @@
@Override
public void stop() {
- this.mob.setTarget((LivingEntity) null);
+ this.mob.setTarget((LivingEntity) null, EntityTargetEvent.TargetReason.FORGOT_TARGET, true); // CraftBukkit
this.targetMob = null;
}

View File

@@ -0,0 +1,46 @@
--- a/net/minecraft/world/entity/ai/gossip/GossipContainer.java
+++ b/net/minecraft/world/entity/ai/gossip/GossipContainer.java
@@ -216,6 +216,43 @@
public void remove(GossipType gossipType) {
this.entries.removeInt(gossipType);
}
+
+ // Paper start - Add villager reputation API
+ private static final GossipType[] TYPES = GossipType.values();
+ public com.destroystokyo.paper.entity.villager.Reputation getPaperReputation() {
+ Map<com.destroystokyo.paper.entity.villager.ReputationType, Integer> map = new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class);
+ for (Object2IntMap.Entry<GossipType> type : this.entries.object2IntEntrySet()) {
+ map.put(toApi(type.getKey()), type.getIntValue());
+ }
+
+ return new com.destroystokyo.paper.entity.villager.Reputation(map);
+ }
+
+ public void assignFromPaperReputation(com.destroystokyo.paper.entity.villager.Reputation rep) {
+ for (GossipType type : TYPES) {
+ com.destroystokyo.paper.entity.villager.ReputationType api = toApi(type);
+
+ if (rep.hasReputationSet(api)) {
+ int reputation = rep.getReputation(api);
+ if (reputation == 0) {
+ this.entries.removeInt(type);
+ } else {
+ this.entries.put(type, reputation);
+ }
+ }
+ }
+ }
+
+ private static com.destroystokyo.paper.entity.villager.ReputationType toApi(GossipType type) {
+ return switch (type) {
+ case MAJOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_NEGATIVE;
+ case MINOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_NEGATIVE;
+ case MINOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_POSITIVE;
+ case MAJOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_POSITIVE;
+ case TRADING -> com.destroystokyo.paper.entity.villager.ReputationType.TRADING;
+ };
+ }
+ // Paper end - Add villager reputation API
}
static record GossipEntry(UUID target, GossipType type, int value) {

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
+++ b/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
@@ -39,7 +39,7 @@
@Override
public Path createPath(Entity entity, int distance) {
- return this.createPath(entity.blockPosition(), distance);
+ return this.createPath(entity.blockPosition(), entity, distance); // Paper - EntityPathfindEvent
}
@Override

View File

@@ -0,0 +1,46 @@
--- a/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
+++ b/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
@@ -41,7 +41,7 @@
}
@Override
- public Path createPath(BlockPos target, int distance) {
+ public Path createPath(BlockPos target, @javax.annotation.Nullable Entity entity, int distance) { // Paper - EntityPathfindEvent
LevelChunk levelChunk = this.level
.getChunkSource()
.getChunkNow(SectionPos.blockToSectionCoord(target.getX()), SectionPos.blockToSectionCoord(target.getZ()));
@@ -56,7 +56,7 @@
}
if (mutableBlockPos.getY() > this.level.getMinY()) {
- return super.createPath(mutableBlockPos.above(), distance);
+ return super.createPath(mutableBlockPos.above(), entity, distance); // Paper - EntityPathfindEvent
}
mutableBlockPos.setY(target.getY() + 1);
@@ -69,7 +69,7 @@
}
if (!levelChunk.getBlockState(target).isSolid()) {
- return super.createPath(target, distance);
+ return super.createPath(target, entity, distance); // Paper - EntityPathfindEvent
} else {
BlockPos.MutableBlockPos mutableBlockPos2 = target.mutable().move(Direction.UP);
@@ -77,14 +77,14 @@
mutableBlockPos2.move(Direction.UP);
}
- return super.createPath(mutableBlockPos2.immutable(), distance);
+ return super.createPath(mutableBlockPos2.immutable(), entity, distance); // Paper - EntityPathfindEvent
}
}
}
@Override
public Path createPath(Entity entity, int distance) {
- return this.createPath(entity.blockPosition(), distance);
+ return this.createPath(entity.blockPosition(), entity, distance); // Paper - EntityPathfindEvent
}
private int getSurfaceY() {

View File

@@ -0,0 +1,104 @@
--- a/net/minecraft/world/entity/ai/navigation/PathNavigation.java
+++ b/net/minecraft/world/entity/ai/navigation/PathNavigation.java
@@ -125,8 +125,14 @@
@Nullable
public Path createPath(BlockPos target, int distance) {
- return this.createPath(ImmutableSet.of(target), 8, false, distance);
+ // Paper start - EntityPathfindEvent
+ return this.createPath(target, null, distance);
}
+ @Nullable
+ public Path createPath(BlockPos target, @Nullable Entity entity, int distance) {
+ return this.createPath(ImmutableSet.of(target), entity, 8, false, distance);
+ // Paper end - EntityPathfindEvent
+ }
@Nullable
public Path createPath(BlockPos target, int minDistance, int maxDistance) {
@@ -135,7 +141,7 @@
@Nullable
public Path createPath(Entity entity, int distance) {
- return this.createPath(ImmutableSet.of(entity.blockPosition()), 16, true, distance);
+ return this.createPath(ImmutableSet.of(entity.blockPosition()), entity, 16, true, distance); // Paper - EntityPathfindEvent
}
@Nullable
@@ -145,6 +151,17 @@
@Nullable
protected Path createPath(Set<BlockPos> positions, int range, boolean useHeadPos, int distance, float followRange) {
+ // Paper start - EntityPathfindEvent
+ return this.createPath(positions, null, range, useHeadPos, distance, followRange);
+ }
+
+ @Nullable
+ protected Path createPath(Set<BlockPos> positions, @Nullable Entity target, int range, boolean useHeadPos, int distance) {
+ return this.createPath(positions, target, range, useHeadPos, distance, (float) this.mob.getAttributeValue(Attributes.FOLLOW_RANGE));
+ }
+
+ @Nullable protected Path createPath(Set<BlockPos> positions, @Nullable Entity target, int range, boolean useHeadPos, int distance, float followRange) {
+ // Paper end - EntityPathfindEvent
if (positions.isEmpty()) {
return null;
} else if (this.mob.getY() < (double)this.level.getMinY()) {
@@ -154,6 +171,23 @@
} else if (this.path != null && !this.path.isDone() && positions.contains(this.targetPos)) {
return this.path;
} else {
+ // Paper start - EntityPathfindEvent
+ boolean copiedSet = false;
+ for (BlockPos possibleTarget : positions) {
+ if (!this.mob.getCommandSenderWorld().getWorldBorder().isWithinBounds(possibleTarget) || !new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(), // Paper - don't path out of world border
+ io.papermc.paper.util.MCUtil.toLocation(this.mob.level(), possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) {
+ if (!copiedSet) {
+ copiedSet = true;
+ positions = new java.util.HashSet<>(positions);
+ }
+ // note: since we copy the set this remove call is safe, since we're iterating over the old copy
+ positions.remove(possibleTarget);
+ if (positions.isEmpty()) {
+ return null;
+ }
+ }
+ }
+ // Paper end - EntityPathfindEvent
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push("pathfind");
BlockPos blockPos = useHeadPos ? this.mob.blockPosition().above() : this.mob.blockPosition();
@@ -175,13 +209,33 @@
return this.moveTo(this.createPath(x, y, z, 1), speed);
}
+ // Paper start - Perf: Optimise pathfinding
+ private int lastFailure = 0;
+ private int pathfindFailures = 0;
+ // Paper end - Perf: Optimise pathfinding
+
public boolean moveTo(double x, double y, double z, int distance, double speed) {
return this.moveTo(this.createPath(x, y, z, distance), speed);
}
public boolean moveTo(Entity entity, double speed) {
+ // Paper start - Perf: Optimise pathfinding
+ if (this.pathfindFailures > 10 && this.path == null && net.minecraft.server.MinecraftServer.currentTick < this.lastFailure + 40) {
+ return false;
+ }
+ // Paper end - Perf: Optimise pathfinding
Path path = this.createPath(entity, 1);
- return path != null && this.moveTo(path, speed);
+ // Paper start - Perf: Optimise pathfinding
+ if (path != null && this.moveTo(path, speed)) {
+ this.lastFailure = 0;
+ this.pathfindFailures = 0;
+ return true;
+ } else {
+ this.pathfindFailures++;
+ this.lastFailure = net.minecraft.server.MinecraftServer.currentTick;
+ return false;
+ }
+ // Paper end - Perf: Optimise pathfinding
}
public boolean moveTo(@Nullable Path path, double speed) {

View File

@@ -0,0 +1,14 @@
--- a/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
+++ b/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
@@ -16,9 +16,9 @@
}
@Override
- public Path createPath(BlockPos target, int distance) {
+ public Path createPath(BlockPos target, @Nullable Entity entity, int distance) { // Paper - EntityPathfindEvent
this.pathToPosition = target;
- return super.createPath(target, distance);
+ return super.createPath(target, entity, distance); // Paper - EntityPathfindEvent
}
@Override

View File

@@ -0,0 +1,34 @@
--- a/net/minecraft/world/entity/ai/sensing/Sensor.java
+++ b/net/minecraft/world/entity/ai/sensing/Sensor.java
@@ -29,8 +29,19 @@
.ignoreInvisibilityTesting();
private final int scanRate;
private long timeToTick;
+ // Paper start - configurable sensor tick rate and timings
+ private final String configKey;
+ // Paper end
public Sensor(int senseInterval) {
+ // Paper start - configurable sensor tick rate and timings
+ String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName();
+ int lastSeparator = key.lastIndexOf('.');
+ if (lastSeparator != -1) {
+ key = key.substring(lastSeparator + 1);
+ }
+ this.configKey = key.toLowerCase(java.util.Locale.ROOT);
+ // Paper end
this.scanRate = senseInterval;
this.timeToTick = (long)RANDOM.nextInt(senseInterval);
}
@@ -41,8 +52,10 @@
public final void tick(ServerLevel world, E entity) {
if (--this.timeToTick <= 0L) {
- this.timeToTick = (long)this.scanRate;
+ // Paper start - configurable sensor tick rate and timings
+ this.timeToTick = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.sensor.get(entity.getType(), this.configKey), this.scanRate);
this.updateTargetingConditionRanges(entity);
+ // Paper end
this.doTick(world, entity);
}
}

View File

@@ -0,0 +1,45 @@
--- a/net/minecraft/world/entity/ai/sensing/TemptingSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/TemptingSensor.java
@@ -19,6 +19,14 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
+// CraftBukkit start
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
+// CraftBukkit end
+
public class TemptingSensor extends Sensor<PathfinderMob> {
private static final TargetingConditions TEMPT_TARGETING = TargetingConditions.forNonCombat().ignoreLineOfSight();
@@ -31,7 +39,7 @@
protected void doTick(ServerLevel world, PathfinderMob entity) {
Brain<?> behaviorcontroller = entity.getBrain();
TargetingConditions pathfindertargetcondition = TemptingSensor.TEMPT_TARGETING.copy().range((double) ((float) entity.getAttributeValue(Attributes.TEMPT_RANGE)));
- Stream stream = world.players().stream().filter(EntitySelector.NO_SPECTATORS).filter((entityplayer) -> {
+ Stream<net.minecraft.server.level.ServerPlayer> stream = world.players().stream().filter(EntitySelector.NO_SPECTATORS).filter((entityplayer) -> { // CraftBukkit - decompile error
return pathfindertargetcondition.test(world, entity, entityplayer);
}).filter(this::playerHoldingTemptation).filter((entityplayer) -> {
return !entity.hasPassenger((Entity) entityplayer);
@@ -43,7 +51,17 @@
if (!list.isEmpty()) {
Player entityhuman = (Player) list.get(0);
- behaviorcontroller.setMemory(MemoryModuleType.TEMPTING_PLAYER, (Object) entityhuman);
+ // CraftBukkit start
+ EntityTargetLivingEntityEvent event = CraftEventFactory.callEntityTargetLivingEvent(entity, entityhuman, EntityTargetEvent.TargetReason.TEMPT);
+ if (event.isCancelled()) {
+ return;
+ }
+ if (event.getTarget() instanceof HumanEntity) {
+ behaviorcontroller.setMemory(MemoryModuleType.TEMPTING_PLAYER, ((CraftHumanEntity) event.getTarget()).getHandle());
+ } else {
+ behaviorcontroller.eraseMemory(MemoryModuleType.TEMPTING_PLAYER);
+ }
+ // CraftBukkit end
} else {
behaviorcontroller.eraseMemory(MemoryModuleType.TEMPTING_PLAYER);
}

View File

@@ -0,0 +1,16 @@
--- a/net/minecraft/world/entity/ai/village/VillageSiege.java
+++ b/net/minecraft/world/entity/ai/village/VillageSiege.java
@@ -117,11 +117,12 @@
entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), EntitySpawnReason.EVENT, (SpawnGroupData) null);
} catch (Exception exception) {
VillageSiege.LOGGER.warn("Failed to create zombie for village siege at {}", vec3d, exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper - ServerExceptionEvent
return;
}
entityzombie.moveTo(vec3d.x, vec3d.y, vec3d.z, world.random.nextFloat() * 360.0F, 0.0F);
- world.addFreshEntityWithPassengers(entityzombie);
+ world.addFreshEntityWithPassengers(entityzombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_INVASION); // CraftBukkit
}
}

View File

@@ -0,0 +1,55 @@
--- a/net/minecraft/world/entity/ambient/Bat.java
+++ b/net/minecraft/world/entity/ambient/Bat.java
@@ -29,6 +29,9 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+// CraftBukkit end
public class Bat extends AmbientCreature {
@@ -88,7 +91,7 @@
}
@Override
- public boolean isPushable() {
+ public boolean isCollidable(boolean ignoreClimbing) { // Paper - Climbing should not bypass cramming gamerule
return false;
}
@@ -144,13 +147,13 @@
this.yHeadRot = (float) this.random.nextInt(360);
}
- if (world.getNearestPlayer(Bat.BAT_RESTING_TARGETING, this) != null) {
+ if (world.getNearestPlayer(Bat.BAT_RESTING_TARGETING, this) != null && CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent
this.setResting(false);
if (!flag) {
world.levelEvent((Player) null, 1025, blockposition, 0);
}
}
- } else {
+ } else if (CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent
this.setResting(false);
if (!flag) {
world.levelEvent((Player) null, 1025, blockposition, 0);
@@ -177,7 +180,7 @@
this.zza = 0.5F;
this.setYRot(this.getYRot() + f1);
- if (this.random.nextInt(100) == 0 && world.getBlockState(blockposition1).isRedstoneConductor(world, blockposition1)) {
+ if (this.random.nextInt(100) == 0 && world.getBlockState(blockposition1).isRedstoneConductor(world, blockposition1) && CraftEventFactory.handleBatToggleSleepEvent(this, false)) { // CraftBukkit - Call BatToggleSleepEvent
this.setResting(true);
}
}
@@ -202,7 +205,7 @@
if (this.isInvulnerableTo(world, source)) {
return false;
} else {
- if (this.isResting()) {
+ if (this.isResting() && CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent
this.setResting(false);
}

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/world/entity/animal/AbstractSchoolingFish.java
+++ b/net/minecraft/world/entity/animal/AbstractSchoolingFish.java
@@ -51,6 +51,7 @@
}
public void stopFollowing() {
+ if (this.leader == null) return; // Avoid NPE, plugins can now set the leader and certain fish goals might cause this method to be called
this.leader.removeFollower();
this.leader = null;
}

View File

@@ -0,0 +1,141 @@
--- a/net/minecraft/world/entity/animal/Animal.java
+++ b/net/minecraft/world/entity/animal/Animal.java
@@ -35,12 +35,20 @@
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.pathfinder.PathType;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityBreedEvent;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.EntityEnterLoveModeEvent;
+// CraftBukkit end
+
public abstract class Animal extends AgeableMob {
protected static final int PARENT_AGE_AFTER_BREEDING = 6000;
public int inLove;
@Nullable
public UUID loveCause;
+ public ItemStack breedItem; // CraftBukkit - Add breedItem variable
protected Animal(EntityType<? extends Animal> type, Level world) {
super(type, world);
@@ -82,9 +90,15 @@
}
@Override
- protected void actuallyHurt(ServerLevel world, DamageSource source, float amount) {
+ // CraftBukkit start - void -> boolean
+ public boolean actuallyHurt(ServerLevel worldserver, DamageSource damagesource, float f, EntityDamageEvent event) {
+ boolean damageResult = super.actuallyHurt(worldserver, damagesource, f, event);
+ if (!damageResult) {
+ return false;
+ }
this.resetLove();
- super.actuallyHurt(world, source, amount);
+ return true;
+ // CraftBukkit end
}
@Override
@@ -144,8 +158,9 @@
int i = this.getAge();
if (!this.level().isClientSide && i == 0 && this.canFallInLove()) {
+ final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying
this.usePlayerItem(player, hand, itemstack);
- this.setInLove(player);
+ this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying
this.playEatingSound();
return InteractionResult.SUCCESS_SERVER;
}
@@ -187,11 +202,26 @@
return this.inLove <= 0;
}
+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Fix EntityBreedEvent copying
public void setInLove(@Nullable Player player) {
- this.inLove = 600;
+ // Paper start - Fix EntityBreedEvent copying
+ this.setInLove(player, null);
+ }
+ public void setInLove(@Nullable Player player, @Nullable ItemStack breedItemCopy) {
+ if (breedItemCopy != null) this.breedItem = breedItemCopy;
+ // Paper end - Fix EntityBreedEvent copying
+ // CraftBukkit start
+ EntityEnterLoveModeEvent entityEnterLoveModeEvent = CraftEventFactory.callEntityEnterLoveModeEvent(player, this, 600);
+ if (entityEnterLoveModeEvent.isCancelled()) {
+ this.breedItem = null; // Paper - Fix EntityBreedEvent copying; clear if cancelled
+ return;
+ }
+ this.inLove = entityEnterLoveModeEvent.getTicksInLove();
+ // CraftBukkit end
if (player != null) {
this.loveCause = player.getUUID();
}
+ // Paper - Fix EntityBreedEvent copying; set breed item in better place
this.level().broadcastEntityEvent(this, (byte) 18);
}
@@ -233,25 +263,48 @@
if (entityageable != null) {
entityageable.setBaby(true);
entityageable.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F);
- this.finalizeSpawnChildFromBreeding(world, other, entityageable);
- world.addFreshEntityWithPassengers(entityageable);
+ // CraftBukkit start - call EntityBreedEvent
+ ServerPlayer breeder = Optional.ofNullable(this.getLoveCause()).or(() -> {
+ return Optional.ofNullable(other.getLoveCause());
+ }).orElse(null);
+ int experience = this.getRandom().nextInt(7) + 1;
+ EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(entityageable, this, other, breeder, this.breedItem, experience);
+ if (entityBreedEvent.isCancelled()) {
+ return;
+ }
+ experience = entityBreedEvent.getExperience();
+ this.finalizeSpawnChildFromBreeding(world, other, entityageable, experience);
+ world.addFreshEntityWithPassengers(entityageable, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING);
+ // CraftBukkit end
}
}
public void finalizeSpawnChildFromBreeding(ServerLevel world, Animal other, @Nullable AgeableMob baby) {
- Optional.ofNullable(this.getLoveCause()).or(() -> {
- return Optional.ofNullable(other.getLoveCause());
- }).ifPresent((entityplayer) -> {
+ // CraftBukkit start
+ this.finalizeSpawnChildFromBreeding(world, other, baby, this.getRandom().nextInt(7) + 1);
+ }
+
+ public void finalizeSpawnChildFromBreeding(ServerLevel worldserver, Animal entityanimal, @Nullable AgeableMob entityageable, int experience) {
+ // CraftBukkit end
+ // Paper start
+ ServerPlayer entityplayer = this.getLoveCause();
+ if (entityplayer == null) entityplayer = entityanimal.getLoveCause();
+ if (entityplayer != null) {
+ // Paper end
entityplayer.awardStat(Stats.ANIMALS_BRED);
- CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer, this, other, baby);
- });
+ CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer, this, entityanimal, entityageable);
+ } // Paper
this.setAge(6000);
- other.setAge(6000);
+ entityanimal.setAge(6000);
this.resetLove();
- other.resetLove();
- world.broadcastEntityEvent(this, (byte) 18);
- if (world.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- world.addFreshEntity(new ExperienceOrb(world, this.getX(), this.getY(), this.getZ(), this.getRandom().nextInt(7) + 1));
+ entityanimal.resetLove();
+ worldserver.broadcastEntityEvent(this, (byte) 18);
+ if (worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
+ // CraftBukkit start - use event experience
+ if (experience > 0) {
+ worldserver.addFreshEntity(new ExperienceOrb(worldserver, this.getX(), this.getY(), this.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityageable)); // Paper
+ }
+ // CraftBukkit end
}
}

View File

@@ -0,0 +1,205 @@
--- a/net/minecraft/world/entity/animal/Bee.java
+++ b/net/minecraft/world/entity/animal/Bee.java
@@ -92,6 +92,11 @@
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.level.pathfinder.PathType;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityPotionEffectEvent;
+import org.bukkit.event.entity.EntityTargetEvent;
+// CraftBukkit end
public class Bee extends Animal implements NeutralMob, FlyingAnimal {
@@ -149,7 +154,22 @@
public Bee(EntityType<? extends Bee> type, Level world) {
super(type, world);
this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60);
- this.moveControl = new FlyingMoveControl(this, 20, true);
+ // Paper start - Fix MC-167279
+ class BeeFlyingMoveControl extends FlyingMoveControl {
+ public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) {
+ super(entity, maxPitchChange, noGravity);
+ }
+
+ @Override
+ public void tick() {
+ if (this.mob.getY() <= Bee.this.level().getMinY()) {
+ this.mob.setNoGravity(false);
+ }
+ super.tick();
+ }
+ }
+ this.moveControl = new BeeFlyingMoveControl(this, 20, true);
+ // Paper end - Fix MC-167279
this.lookControl = new Bee.BeeLookControl(this);
this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
this.setPathfindingMalus(PathType.WATER, -1.0F);
@@ -198,21 +218,28 @@
@Override
public void addAdditionalSaveData(CompoundTag nbt) {
- super.addAdditionalSaveData(nbt);
- if (this.hasHive()) {
- nbt.put("hive_pos", NbtUtils.writeBlockPos(this.getHivePos()));
+ // CraftBukkit start - selectively save data
+ this.addAdditionalSaveData(nbt, true);
+ }
+
+ @Override
+ public void addAdditionalSaveData(CompoundTag nbttagcompound, boolean includeAll) {
+ // CraftBukkit end
+ super.addAdditionalSaveData(nbttagcompound);
+ if (includeAll && this.hasHive()) { // CraftBukkit - selectively save hive
+ nbttagcompound.put("hive_pos", NbtUtils.writeBlockPos(this.getHivePos()));
}
- if (this.hasSavedFlowerPos()) {
- nbt.put("flower_pos", NbtUtils.writeBlockPos(this.getSavedFlowerPos()));
+ if (includeAll && this.hasSavedFlowerPos()) { // CraftBukkit - selectively save flower
+ nbttagcompound.put("flower_pos", NbtUtils.writeBlockPos(this.getSavedFlowerPos()));
}
- nbt.putBoolean("HasNectar", this.hasNectar());
- nbt.putBoolean("HasStung", this.hasStung());
- nbt.putInt("TicksSincePollination", this.ticksWithoutNectarSinceExitingHive);
- nbt.putInt("CannotEnterHiveTicks", this.stayOutOfHiveCountdown);
- nbt.putInt("CropsGrownSincePollination", this.numCropsGrownSincePollination);
- this.addPersistentAngerSaveData(nbt);
+ nbttagcompound.putBoolean("HasNectar", this.hasNectar());
+ nbttagcompound.putBoolean("HasStung", this.hasStung());
+ nbttagcompound.putInt("TicksSincePollination", this.ticksWithoutNectarSinceExitingHive);
+ nbttagcompound.putInt("CannotEnterHiveTicks", this.stayOutOfHiveCountdown);
+ nbttagcompound.putInt("CropsGrownSincePollination", this.numCropsGrownSincePollination);
+ this.addPersistentAngerSaveData(nbttagcompound);
}
@Override
@@ -223,8 +250,8 @@
this.ticksWithoutNectarSinceExitingHive = nbt.getInt("TicksSincePollination");
this.stayOutOfHiveCountdown = nbt.getInt("CannotEnterHiveTicks");
this.numCropsGrownSincePollination = nbt.getInt("CropsGrownSincePollination");
- this.hivePos = (BlockPos) NbtUtils.readBlockPos(nbt, "hive_pos").orElse((Object) null);
- this.savedFlowerPos = (BlockPos) NbtUtils.readBlockPos(nbt, "flower_pos").orElse((Object) null);
+ this.hivePos = (BlockPos) NbtUtils.readBlockPos(nbt, "hive_pos").orElse(null); // CraftBukkit - decompile error
+ this.savedFlowerPos = (BlockPos) NbtUtils.readBlockPos(nbt, "flower_pos").orElse(null); // CraftBukkit - decompile error
this.readPersistentAngerSaveData(this.level(), nbt);
}
@@ -248,7 +275,7 @@
}
if (b0 > 0) {
- entityliving.addEffect(new MobEffectInstance(MobEffects.POISON, b0 * 20, 0), this);
+ entityliving.addEffect(new MobEffectInstance(MobEffects.POISON, b0 * 20, 0), this, EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit
}
}
@@ -506,7 +533,12 @@
@Nullable
BeehiveBlockEntity getBeehiveBlockEntity() {
- return this.hivePos == null ? null : (this.isTooFarAway(this.hivePos) ? null : (BeehiveBlockEntity) this.level().getBlockEntity(this.hivePos, BlockEntityType.BEEHIVE).orElse((Object) null));
+ // Paper start - move over logic to accommodate isTooFarAway with chunk load check
+ if (this.hivePos != null && !this.isTooFarAway(this.hivePos) && this.level().getChunkIfLoadedImmediately(this.hivePos.getX() >> 4, this.hivePos.getZ() >> 4) != null) {
+ return (BeehiveBlockEntity) this.level().getBlockEntity(this.hivePos, BlockEntityType.BEEHIVE).orElse(null);
+ }
+ return null;
+ // Paper end
}
boolean isHiveValid() {
@@ -533,11 +565,13 @@
this.setFlag(4, hasStung);
}
+ public net.kyori.adventure.util.TriState rollingOverride = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Rolling override
public boolean isRolling() {
return this.getFlag(2);
}
public void setRolling(boolean nearTarget) {
+ nearTarget = rollingOverride.toBooleanOrElse(nearTarget); // Paper - Rolling override
this.setFlag(2, nearTarget);
}
@@ -602,7 +636,7 @@
if (mobeffect != null) {
this.usePlayerItem(player, hand, itemstack);
if (!this.level().isClientSide) {
- this.addEffect(mobeffect);
+ this.addEffect(mobeffect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD); // Paper - Add missing effect cause
}
return InteractionResult.SUCCESS;
@@ -671,8 +705,14 @@
if (this.isInvulnerableTo(world, source)) {
return false;
} else {
+ // CraftBukkit start - Only stop pollinating if entity was damaged
+ boolean result = super.hurtServer(world, source, amount);
+ if (!result) {
+ return result;
+ }
+ // CraftBukkit end
this.beePollinateGoal.stopPollinating();
- return super.hurtServer(world, source, amount);
+ return result; // CraftBukkit
}
}
@@ -934,7 +974,7 @@
Bee.this.dropFlower();
this.pollinating = false;
Bee.this.remainingCooldownBeforeLocatingNewFlower = 200;
- } else {
+ } else if (Bee.this.savedFlowerPos != null) { // Paper - add null check since API can manipulate this
Vec3 vec3d = Vec3.atBottomCenterOf(Bee.this.savedFlowerPos).add(0.0D, 0.6000000238418579D, 0.0D);
if (vec3d.distanceTo(Bee.this.position()) > 1.0D) {
@@ -1082,7 +1122,7 @@
BeeGoToHiveGoal() {
super();
- this.travellingTicks = Bee.this.level().random.nextInt(10);
+ this.travellingTicks = Bee.this.random.nextInt(10); // CraftBukkit - SPIGOT-7495: Give Bees another chance and let them use their own random, avoid concurrency issues
this.blacklistedTargets = Lists.newArrayList();
this.setFlags(EnumSet.of(Goal.Flag.MOVE));
}
@@ -1196,7 +1236,7 @@
BeeGoToKnownFlowerGoal() {
super();
- this.travellingTicks = Bee.this.level().random.nextInt(10);
+ this.travellingTicks = Bee.this.random.nextInt(10); // CraftBukkit - SPIGOT-7495: Give Bees another chance and let them use their own random, avoid concurrency issues
this.setFlags(EnumSet.of(Goal.Flag.MOVE));
}
@@ -1301,7 +1341,7 @@
}
}
- if (iblockdata1 != null) {
+ if (iblockdata1 != null && CraftEventFactory.callEntityChangeBlockEvent(Bee.this, blockposition, iblockdata1)) { // CraftBukkit
Bee.this.level().levelEvent(2011, blockposition, 15);
Bee.this.level().setBlockAndUpdate(blockposition, iblockdata1);
Bee.this.incrementNumCropsGrownSincePollination();
@@ -1378,7 +1418,7 @@
@Override
protected void alertOther(Mob mob, LivingEntity target) {
if (mob instanceof Bee && this.mob.hasLineOfSight(target)) {
- mob.setTarget(target);
+ mob.setTarget(target, EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY, true); // CraftBukkit - reason
}
}
@@ -1387,7 +1427,7 @@
private static class BeeBecomeAngryTargetGoal extends NearestAttackableTargetGoal<Player> {
BeeBecomeAngryTargetGoal(Bee bee) {
- Objects.requireNonNull(bee);
+ // Objects.requireNonNull(entitybee); // CraftBukkit - decompile error
super(bee, Player.class, 10, true, false, bee::isAngryAt);
}

View File

@@ -0,0 +1,46 @@
--- a/net/minecraft/world/entity/animal/Bucketable.java
+++ b/net/minecraft/world/entity/animal/Bucketable.java
@@ -16,6 +16,11 @@
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.Level;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.entity.EntityRemoveEvent;
+import org.bukkit.event.player.PlayerBucketEntityEvent;
+// CraftBukkit end
public interface Bucketable {
@@ -93,10 +98,21 @@
ItemStack itemstack = player.getItemInHand(hand);
if (itemstack.getItem() == Items.WATER_BUCKET && entity.isAlive()) {
- entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F);
+ // CraftBukkit start
+ // t0.playSound(((Bucketable) t0).getPickupSound(), 1.0F, 1.0F); // CraftBukkit - moved down
ItemStack itemstack1 = ((Bucketable) entity).getBucketItemStack();
((Bucketable) entity).saveToBucketTag(itemstack1);
+
+ PlayerBucketEntityEvent playerBucketFishEvent = CraftEventFactory.callPlayerFishBucketEvent(entity, player, itemstack, itemstack1, hand);
+ itemstack1 = CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket());
+ if (playerBucketFishEvent.isCancelled()) {
+ ((ServerPlayer) player).containerMenu.sendAllDataToRemote(); // We need to update inventory to resync client's bucket
+ entity.resendPossiblyDesyncedEntityData((ServerPlayer) player); // Paper
+ return Optional.of(InteractionResult.FAIL);
+ }
+ entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F);
+ // CraftBukkit end
ItemStack itemstack2 = ItemUtils.createFilledResult(itemstack, player, itemstack1, false);
player.setItemInHand(hand, itemstack2);
@@ -106,7 +122,7 @@
CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer) player, itemstack1);
}
- entity.discard();
+ entity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
return Optional.of(InteractionResult.SUCCESS);
} else {
return Optional.empty();

View File

@@ -0,0 +1,96 @@
--- a/net/minecraft/world/entity/animal/Cat.java
+++ b/net/minecraft/world/entity/animal/Cat.java
@@ -174,10 +174,10 @@
@Override
public void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
- Optional optional = Optional.ofNullable(ResourceLocation.tryParse(nbt.getString("variant"))).map((minecraftkey) -> {
+ Optional<ResourceKey<CatVariant>> optional = Optional.ofNullable(ResourceLocation.tryParse(nbt.getString("variant"))).map((minecraftkey) -> { // CraftBukkit - decompile error
return ResourceKey.create(Registries.CAT_VARIANT, minecraftkey);
});
- Registry iregistry = BuiltInRegistries.CAT_VARIANT;
+ Registry<CatVariant> iregistry = BuiltInRegistries.CAT_VARIANT; // CraftBukkit - decompile error
Objects.requireNonNull(iregistry);
optional.flatMap(iregistry::get).ifPresent(this::setVariant);
@@ -365,7 +365,7 @@
BuiltInRegistries.CAT_VARIANT.getRandomElementOf(tagkey, world.getRandom()).ifPresent(this::setVariant);
ServerLevel worldserver = world.getLevel();
- if (worldserver.structureManager().getStructureWithPieceAt(this.blockPosition(), StructureTags.CATS_SPAWN_AS_BLACK).isValid()) {
+ if (worldserver.structureManager().getStructureWithPieceAt(this.blockPosition(), StructureTags.CATS_SPAWN_AS_BLACK, world).isValid()) { // Paper - Fix swamp hut cat generation deadlock
this.setVariant((Holder) BuiltInRegistries.CAT_VARIANT.getOrThrow(CatVariant.ALL_BLACK));
this.setPersistenceRequired();
}
@@ -386,6 +386,13 @@
DyeColor enumcolor = itemdye.getDyeColor();
if (enumcolor != this.getCollarColor()) {
+ // Paper start - Add EntityDyeEvent and CollarColorable interface
+ final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) enumcolor.getId()), ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity());
+ if (!event.callEvent()) {
+ return InteractionResult.FAIL;
+ }
+ enumcolor = DyeColor.byId(event.getColor().getWoolData());
+ // Paper end - Add EntityDyeEvent and CollarColorable interface
if (!this.level().isClientSide()) {
this.setCollarColor(enumcolor);
itemstack.consume(1, player);
@@ -399,7 +406,7 @@
this.usePlayerItem(player, hand, itemstack);
FoodProperties foodinfo = (FoodProperties) itemstack.get(DataComponents.FOOD);
- this.heal(foodinfo != null ? (float) foodinfo.nutrition() : 1.0F);
+ this.heal(foodinfo != null ? (float) foodinfo.nutrition() : 1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason
this.playEatingSound();
}
@@ -462,7 +469,7 @@
}
private void tryToTame(Player player) {
- if (this.random.nextInt(3) == 0) {
+ if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit
this.tame(player);
this.setOrderedToSit(true);
this.level().broadcastEntityEvent(this, (byte) 7);
@@ -480,7 +487,7 @@
private static class CatTemptGoal extends TemptGoal {
@Nullable
- private Player selectedPlayer;
+ private LivingEntity selectedPlayer; // CraftBukkit
private final Cat cat;
public CatTemptGoal(Cat cat, double speed, Predicate<ItemStack> foodPredicate, boolean canBeScared) {
@@ -614,7 +621,15 @@
this.cat.randomTeleport((double) (blockposition_mutableblockposition.getX() + randomsource.nextInt(11) - 5), (double) (blockposition_mutableblockposition.getY() + randomsource.nextInt(5) - 2), (double) (blockposition_mutableblockposition.getZ() + randomsource.nextInt(11) - 5), false);
blockposition_mutableblockposition.set(this.cat.blockPosition());
this.cat.dropFromGiftLootTable(getServerLevel((Entity) this.cat), BuiltInLootTables.CAT_MORNING_GIFT, (worldserver, itemstack) -> {
- worldserver.addFreshEntity(new ItemEntity(worldserver, (double) blockposition_mutableblockposition.getX() - (double) Mth.sin(this.cat.yBodyRot * 0.017453292F), (double) blockposition_mutableblockposition.getY(), (double) blockposition_mutableblockposition.getZ() + (double) Mth.cos(this.cat.yBodyRot * 0.017453292F), itemstack));
+ // CraftBukkit start
+ ItemEntity entityitem = new ItemEntity(worldserver, (double) blockposition_mutableblockposition.getX() - (double) Mth.sin(this.cat.yBodyRot * 0.017453292F), (double) blockposition_mutableblockposition.getY(), (double) blockposition_mutableblockposition.getZ() + (double) Mth.cos(this.cat.yBodyRot * 0.017453292F), itemstack);
+ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.cat.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity());
+ entityitem.level().getCraftServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return;
+ }
+ worldserver.addFreshEntity(entityitem);
+ // CraftBukkit end
});
}
@@ -645,10 +660,10 @@
private final Cat cat;
public CatAvoidEntityGoal(Cat cat, Class<T> fleeFromType, float distance, double slowSpeed, double fastSpeed) {
- Predicate predicate = EntitySelector.NO_CREATIVE_OR_SPECTATOR;
+ // Predicate predicate = IEntitySelector.NO_CREATIVE_OR_SPECTATOR; // CraftBukkit - decompile error
- Objects.requireNonNull(predicate);
- super(cat, fleeFromType, distance, slowSpeed, fastSpeed, predicate::test);
+ // Objects.requireNonNull(predicate); // CraftBukkit - decompile error
+ super(cat, fleeFromType, distance, slowSpeed, fastSpeed, EntitySelector.NO_CREATIVE_OR_SPECTATOR::test); // CraftBukkit - decompile error
this.cat = cat;
}

View File

@@ -0,0 +1,15 @@
--- a/net/minecraft/world/entity/animal/Chicken.java
+++ b/net/minecraft/world/entity/animal/Chicken.java
@@ -99,10 +99,12 @@
if (world instanceof ServerLevel worldserver) {
if (this.isAlive() && !this.isBaby() && !this.isChickenJockey() && --this.eggTime <= 0) {
+ this.forceDrops = true; // CraftBukkit
if (this.dropFromGiftLootTable(worldserver, BuiltInLootTables.CHICKEN_LAY, this::spawnAtLocation)) {
this.playSound(SoundEvents.CHICKEN_EGG, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
this.gameEvent(GameEvent.ENTITY_PLACE);
}
+ this.forceDrops = false; // CraftBukkit
this.eggTime = this.random.nextInt(6000) + 6000;
}

View File

@@ -0,0 +1,33 @@
--- a/net/minecraft/world/entity/animal/Cow.java
+++ b/net/minecraft/world/entity/animal/Cow.java
@@ -30,6 +30,11 @@
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.player.PlayerBucketFillEvent;
+// CraftBukkit end
public class Cow extends Animal {
@@ -92,8 +97,17 @@
ItemStack itemstack = player.getItemInHand(hand);
if (itemstack.is(Items.BUCKET) && !this.isBaby()) {
+ // CraftBukkit start - Got milk?
+ PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) player.level(), player, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, hand);
+
+ if (event.isCancelled()) {
+ player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync
+ return InteractionResult.PASS;
+ }
+ // CraftBukkit end
+
player.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F);
- ItemStack itemstack1 = ItemUtils.createFilledResult(itemstack, player, Items.MILK_BUCKET.getDefaultInstance());
+ ItemStack itemstack1 = ItemUtils.createFilledResult(itemstack, player, CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit
player.setItemInHand(hand, itemstack1);
return InteractionResult.SUCCESS;

View File

@@ -0,0 +1,87 @@
--- a/net/minecraft/world/entity/animal/Dolphin.java
+++ b/net/minecraft/world/entity/animal/Dolphin.java
@@ -61,9 +61,20 @@
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.pathfinder.PathComputationType;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityPotionEffectEvent;
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
public class Dolphin extends AgeableWaterCreature {
+ // CraftBukkit start - SPIGOT-6907: re-implement LivingEntity#setMaximumAir()
+ @Override
+ public int getDefaultMaxAirSupply() {
+ return Dolphin.TOTAL_AIR_SUPPLY;
+ }
+ // CraftBukkit end
private static final EntityDataAccessor<BlockPos> TREASURE_POS = SynchedEntityData.defineId(Dolphin.class, EntityDataSerializers.BLOCK_POS);
private static final EntityDataAccessor<Boolean> GOT_FISH = SynchedEntityData.defineId(Dolphin.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Integer> MOISTNESS_LEVEL = SynchedEntityData.defineId(Dolphin.class, EntityDataSerializers.INT);
@@ -200,7 +211,7 @@
@Override
public int getMaxAirSupply() {
- return 4800;
+ return this.maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir()
}
@Override
@@ -234,11 +245,17 @@
ItemStack itemstack = itemEntity.getItem();
if (this.canHoldItem(itemstack)) {
+ // CraftBukkit start - call EntityPickupItemEvent
+ if (CraftEventFactory.callEntityPickupItemEvent(this, itemEntity, 0, false).isCancelled()) {
+ return;
+ }
+ itemstack = itemEntity.getItem(); // CraftBukkit- update ItemStack from event
+ // CraftBukkit start
this.onItemPickup(itemEntity);
this.setItemSlot(EquipmentSlot.MAINHAND, itemstack);
this.setGuaranteedDrop(EquipmentSlot.MAINHAND);
this.take(itemEntity, itemstack.getCount());
- itemEntity.discard();
+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
}
}
@@ -332,7 +349,7 @@
@Nullable
@Override
- protected SoundEvent getDeathSound() {
+ public SoundEvent getDeathSound() { // Paper - decompile error
return SoundEvents.DOLPHIN_DEATH;
}
@@ -495,7 +512,7 @@
@Override
public void start() {
- this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin);
+ this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin, EntityPotionEffectEvent.Cause.DOLPHIN); // CraftBukkit
}
@Override
@@ -514,7 +531,7 @@
}
if (this.player.isSwimming() && this.player.level().random.nextInt(6) == 0) {
- this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin);
+ this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin, EntityPotionEffectEvent.Cause.DOLPHIN); // CraftBukkit
}
}
@@ -587,7 +604,7 @@
float f2 = 0.02F * Dolphin.this.random.nextFloat();
entityitem.setDeltaMovement((double) (0.3F * -Mth.sin(Dolphin.this.getYRot() * 0.017453292F) * Mth.cos(Dolphin.this.getXRot() * 0.017453292F) + Mth.cos(f1) * f2), (double) (0.3F * Mth.sin(Dolphin.this.getXRot() * 0.017453292F) * 1.5F), (double) (0.3F * Mth.cos(Dolphin.this.getYRot() * 0.017453292F) * Mth.cos(Dolphin.this.getXRot() * 0.017453292F) + Mth.sin(f1) * f2));
- Dolphin.this.level().addFreshEntity(entityitem);
+ Dolphin.this.spawnAtLocation(getServerLevel(Dolphin.this), entityitem); // Paper - Call EntityDropItemEvent
}
}
}

View File

@@ -0,0 +1,168 @@
--- a/net/minecraft/world/entity/animal/Fox.java
+++ b/net/minecraft/world/entity/animal/Fox.java
@@ -90,6 +90,9 @@
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.pathfinder.PathType;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
public class Fox extends Animal implements VariantHolder<Fox.Variant> {
@@ -416,7 +419,7 @@
this.setSleeping(nbt.getBoolean("Sleeping"));
this.setVariant(Fox.Variant.byName(nbt.getString("Type")));
- this.setSitting(nbt.getBoolean("Sitting"));
+ this.setSitting(nbt.getBoolean("Sitting"), false); // Paper - Add EntityToggleSitEvent
this.setIsCrouching(nbt.getBoolean("Crouching"));
if (this.level() instanceof ServerLevel) {
this.setTargetGoals();
@@ -429,6 +432,12 @@
}
public void setSitting(boolean sitting) {
+ // Paper start - Add EntityToggleSitEvent
+ this.setSitting(sitting, true);
+ }
+ public void setSitting(boolean sitting, boolean fireEvent) {
+ if (fireEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return;
+ // Paper end - Add EntityToggleSitEvent
this.setFlag(1, sitting);
}
@@ -489,21 +498,22 @@
entityitem.setPickUpDelay(40);
entityitem.setThrower(this);
this.playSound(SoundEvents.FOX_SPIT, 1.0F, 1.0F);
- this.level().addFreshEntity(entityitem);
+ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), entityitem); // Paper - Call EntityDropItemEvent
}
}
private void dropItemStack(ItemStack stack) {
ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), stack);
- this.level().addFreshEntity(entityitem);
+ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), entityitem); // Paper - Call EntityDropItemEvent
}
@Override
protected void pickUpItem(ServerLevel world, ItemEntity itemEntity) {
ItemStack itemstack = itemEntity.getItem();
- if (this.canHoldItem(itemstack)) {
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, itemEntity, itemstack.getCount() - 1, !this.canHoldItem(itemstack)).isCancelled()) { // CraftBukkit - call EntityPickupItemEvent
+ itemstack = itemEntity.getItem(); // CraftBukkit - update ItemStack from event
int i = itemstack.getCount();
if (i > 1) {
@@ -515,7 +525,7 @@
this.setItemSlot(EquipmentSlot.MAINHAND, itemstack.split(1));
this.setGuaranteedDrop(EquipmentSlot.MAINHAND);
this.take(itemEntity, itemstack.getCount());
- itemEntity.discard();
+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
this.ticksSinceEaten = 0;
}
@@ -685,16 +695,38 @@
return this.getTrustedUUIDs().contains(uuid);
}
+ // Paper start - handle the bitten item separately like vanilla
@Override
- protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
+ protected boolean shouldSkipLoot(EquipmentSlot slot) {
+ return slot == EquipmentSlot.MAINHAND;
+ }
+ // Paper end
+
+ @Override
+ // Paper start - Cancellable death event
+ protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
ItemStack itemstack = this.getItemBySlot(EquipmentSlot.MAINHAND);
- if (!itemstack.isEmpty()) {
+ boolean releaseMouth = false;
+ if (!itemstack.isEmpty() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Fix MC-153010
this.spawnAtLocation(world, itemstack);
+ releaseMouth = true;
+ }
+
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = super.dropAllDeathLoot(world, damageSource);
+
+ // Below is code to drop
+
+ if (deathEvent == null || deathEvent.isCancelled()) {
+ return deathEvent;
+ }
+
+ if (releaseMouth) {
+ // Paper end - Cancellable death event
this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
}
- super.dropAllDeathLoot(world, damageSource);
+ return deathEvent; // Paper - Cancellable death event
}
public static boolean isPathClear(Fox fox, LivingEntity chasedEntity) {
@@ -853,6 +885,16 @@
if (entityplayer1 != null && entityplayer != entityplayer1) {
entityfox.addTrustedUUID(entityplayer1.getUUID());
}
+ // CraftBukkit start - call EntityBreedEvent
+ entityfox.setAge(-24000);
+ entityfox.moveTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F);
+ int experience = this.animal.getRandom().nextInt(7) + 1;
+ org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(entityfox, this.animal, this.partner, entityplayer, this.animal.breedItem, experience);
+ if (entityBreedEvent.isCancelled()) {
+ return;
+ }
+ experience = entityBreedEvent.getExperience();
+ // CraftBukkit end
if (entityplayer2 != null) {
entityplayer2.awardStat(Stats.ANIMALS_BRED);
@@ -863,12 +905,14 @@
this.partner.setAge(6000);
this.animal.resetLove();
this.partner.resetLove();
- entityfox.setAge(-24000);
- entityfox.moveTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F);
- worldserver.addFreshEntityWithPassengers(entityfox);
+ worldserver.addFreshEntityWithPassengers(entityfox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason
this.level.broadcastEntityEvent(this.animal, (byte) 18);
if (worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), this.animal.getRandom().nextInt(7) + 1));
+ // CraftBukkit start - use event experience
+ if (experience > 0) {
+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityfox)); // Paper
+ }
+ // CraftBukkit end
}
}
@@ -1264,6 +1308,11 @@
int i = (Integer) state.getValue(SweetBerryBushBlock.AGE);
state.setValue(SweetBerryBushBlock.AGE, 1);
+ // CraftBukkit start - call EntityChangeBlockEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(Fox.this, this.blockPos, state.setValue(SweetBerryBushBlock.AGE, 1))) {
+ return;
+ }
+ // CraftBukkit end
int j = 1 + Fox.this.level().random.nextInt(2) + (i == 3 ? 1 : 0);
ItemStack itemstack = Fox.this.getItemBySlot(EquipmentSlot.MAINHAND);
@@ -1494,7 +1543,7 @@
}
public static Fox.Variant byName(String name) {
- return (Fox.Variant) Fox.Variant.CODEC.byName(name, (Enum) Fox.Variant.RED);
+ return (Fox.Variant) Fox.Variant.CODEC.byName(name, Fox.Variant.RED); // CraftBukkit - decompile error
}
public static Fox.Variant byId(int id) {

View File

@@ -0,0 +1,20 @@
--- a/net/minecraft/world/entity/animal/IronGolem.java
+++ b/net/minecraft/world/entity/animal/IronGolem.java
@@ -98,7 +98,7 @@
@Override
protected void doPush(Entity entity) {
if (entity instanceof Enemy && !(entity instanceof Creeper) && this.getRandom().nextInt(20) == 0) {
- this.setTarget((LivingEntity) entity);
+ this.setTarget((LivingEntity) entity, org.bukkit.event.entity.EntityTargetLivingEntityEvent.TargetReason.COLLISION, true); // CraftBukkit - set reason
}
super.doPush(entity);
@@ -319,7 +319,7 @@
BlockPos blockposition1 = blockposition.below();
BlockState iblockdata = world.getBlockState(blockposition1);
- if (!iblockdata.entityCanStandOn(world, blockposition1, this)) {
+ if (!iblockdata.entityCanStandOn(world, blockposition1, this) && !this.level().paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper - Add option to allow iron golems to spawn in air
return false;
} else {
for (int i = 1; i < 3; ++i) {

View File

@@ -0,0 +1,85 @@
--- a/net/minecraft/world/entity/animal/MushroomCow.java
+++ b/net/minecraft/world/entity/animal/MushroomCow.java
@@ -42,6 +42,13 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
+// CraftBukkit start
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.entity.EntityDropItemEvent;
+import org.bukkit.event.entity.EntityTransformEvent;
+// CraftBukkit end
public class MushroomCow extends Cow implements Shearable, VariantHolder<MushroomCow.Variant> {
@@ -120,7 +127,19 @@
if (world instanceof ServerLevel) {
ServerLevel worldserver = (ServerLevel) world;
- this.shear(worldserver, SoundSource.PLAYERS, itemstack);
+ // CraftBukkit start
+ // Paper start - custom shear drops
+ java.util.List<ItemStack> drops = this.generateDefaultDrops(worldserver, itemstack);
+ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops);
+ if (event != null) {
+ if (event.isCancelled()) {
+ return InteractionResult.PASS;
+ }
+ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
+ // Paper end - custom shear drops
+ }
+ // CraftBukkit end
+ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops
this.gameEvent(GameEvent.SHEAR, player);
itemstack.hurtAndBreak(1, player, getSlotForHand(hand));
}
@@ -158,16 +177,32 @@
@Override
public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) {
+ // Paper start - custom shear drops
+ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears));
+ }
+
+ @Override
+ public java.util.List<ItemStack> generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) {
+ final java.util.List<ItemStack> drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.SHEAR_MOOSHROOM, shears, (ignored, stack) -> {
+ for (int i = 0; i < stack.getCount(); ++i) drops.add(stack.copyWithCount(1));
+ });
+ return drops;
+ }
+
+ @Override
+ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List<ItemStack> drops) {
+ // Paper end - custom shear drops
world.playSound((Player) null, (Entity) this, SoundEvents.MOOSHROOM_SHEAR, shearedSoundCategory, 1.0F, 1.0F);
this.convertTo(EntityType.COW, ConversionParams.single(this, false, false), (entitycow) -> {
world.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(0.5D), this.getZ(), 1, 0.0D, 0.0D, 0.0D, 0.0D);
- this.dropFromShearingLootTable(world, BuiltInLootTables.SHEAR_MOOSHROOM, shears, (worldserver1, itemstack1) -> {
- for (int i = 0; i < itemstack1.getCount(); ++i) {
- worldserver1.addFreshEntity(new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), itemstack1.copyWithCount(1)));
- }
-
+ // Paper start - custom shear drops; moved drop generation to separate method
+ drops.forEach(drop -> {
+ ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), drop);
+ this.spawnAtLocation(world, entityitem);
+ // Paper end - custom shear drops; moved drop generation to separate method
});
- });
+ }, EntityTransformEvent.TransformReason.SHEARED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SHEARED); // CraftBukkit
}
@Override
@@ -263,7 +298,7 @@
}
static MushroomCow.Variant byName(String name) {
- return (MushroomCow.Variant) MushroomCow.Variant.CODEC.byName(name, (Enum) MushroomCow.Variant.RED);
+ return (MushroomCow.Variant) MushroomCow.Variant.CODEC.byName(name, MushroomCow.Variant.RED); // CraftBukkit - decompile error
}
}
}

View File

@@ -0,0 +1,34 @@
--- a/net/minecraft/world/entity/animal/Ocelot.java
+++ b/net/minecraft/world/entity/animal/Ocelot.java
@@ -132,7 +132,7 @@
@Override
public boolean removeWhenFarAway(double distanceSquared) {
- return !this.isTrusting() && this.tickCount > 2400;
+ return !this.isTrusting() && this.tickCount > 2400 && !this.hasCustomName() && !this.isLeashed(); // Paper - honor name and leash
}
public static AttributeSupplier.Builder createAttributes() {
@@ -167,7 +167,7 @@
if ((this.temptGoal == null || this.temptGoal.isRunning()) && !this.isTrusting() && this.isFood(itemstack) && player.distanceToSqr((Entity) this) < 9.0D) {
this.usePlayerItem(player, hand, itemstack);
if (!this.level().isClientSide) {
- if (this.random.nextInt(3) == 0) {
+ if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit - added event call and isCancelled check
this.setTrusting(true);
this.spawnTrustingParticles(true);
this.level().broadcastEntityEvent(this, (byte) 41);
@@ -298,10 +298,10 @@
private final Ocelot ocelot;
public OcelotAvoidEntityGoal(Ocelot ocelot, Class<T> fleeFromType, float distance, double slowSpeed, double fastSpeed) {
- Predicate predicate = EntitySelector.NO_CREATIVE_OR_SPECTATOR;
+ // Predicate predicate = IEntitySelector.NO_CREATIVE_OR_SPECTATOR; // CraftBukkit - decompile error
- Objects.requireNonNull(predicate);
- super(ocelot, fleeFromType, distance, slowSpeed, fastSpeed, predicate::test);
+ // Objects.requireNonNull(predicate); // CraftBukkit - decompile error
+ super(ocelot, fleeFromType, distance, slowSpeed, fastSpeed, EntitySelector.NO_CREATIVE_OR_SPECTATOR::test); // CraftBukkit - decompile error
this.ocelot = ocelot;
}

View File

@@ -0,0 +1,122 @@
--- a/net/minecraft/world/entity/animal/Panda.java
+++ b/net/minecraft/world/entity/animal/Panda.java
@@ -68,6 +68,11 @@
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityRemoveEvent;
+import org.bukkit.event.entity.EntityTargetEvent;
+// CraftBukkit end
public class Panda extends Animal {
@@ -129,6 +134,7 @@
}
public void sit(boolean sitting) {
+ if (!new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return; // Paper - Add EntityToggleSitEvent
this.setFlag(8, sitting);
}
@@ -525,7 +531,9 @@
Panda entitypanda = (Panda) iterator.next();
if (!entitypanda.isBaby() && entitypanda.onGround() && !entitypanda.isInWater() && entitypanda.canPerformAction()) {
+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API
entitypanda.jumpFromGround();
+ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop
}
}
@@ -533,7 +541,9 @@
if (world1 instanceof ServerLevel worldserver) {
if (worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
+ this.forceDrops = true; // Paper - Add missing forceDrop toggles
this.dropFromGiftLootTable(worldserver, BuiltInLootTables.PANDA_SNEEZE, this::spawnAtLocation);
+ this.forceDrops = false; // Paper - Add missing forceDrop toggles
}
}
@@ -541,14 +551,14 @@
@Override
protected void pickUpItem(ServerLevel world, ItemEntity itemEntity) {
- if (this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty() && Panda.canPickUpAndEat(itemEntity)) {
+ if (!CraftEventFactory.callEntityPickupItemEvent(this, itemEntity, 0, !(this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty() && Panda.canPickUpAndEat(itemEntity))).isCancelled()) { // CraftBukkit
this.onItemPickup(itemEntity);
ItemStack itemstack = itemEntity.getItem();
this.setItemSlot(EquipmentSlot.MAINHAND, itemstack);
this.setGuaranteedDrop(EquipmentSlot.MAINHAND);
this.take(itemEntity, itemstack.getCount());
- itemEntity.discard();
+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
}
}
@@ -643,8 +653,9 @@
this.usePlayerItem(player, hand, itemstack);
this.ageUp((int) ((float) (-this.getAge() / 20) * 0.1F), true);
} else if (!this.level().isClientSide && this.getAge() == 0 && this.canFallInLove()) {
+ final ItemStack breedCopy = itemstack.copy(); // Paper - Fix EntityBreedEvent copying
this.usePlayerItem(player, hand, itemstack);
- this.setInLove(player);
+ this.setInLove(player, breedCopy); // Paper - Fix EntityBreedEvent copying
} else {
Level world = this.level();
@@ -657,7 +668,9 @@
ItemStack itemstack1 = this.getItemBySlot(EquipmentSlot.MAINHAND);
if (!itemstack1.isEmpty() && !player.hasInfiniteMaterials()) {
+ this.forceDrops = true; // Paper - Add missing forceDrop toggles
this.spawnAtLocation(worldserver, itemstack1);
+ this.forceDrops = false; // Paper - Add missing forceDrop toggles
}
this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(itemstack.getItem(), 1));
@@ -772,7 +785,7 @@
}
public static Panda.Gene byName(String name) {
- return (Panda.Gene) Panda.Gene.CODEC.byName(name, (Enum) Panda.Gene.NORMAL);
+ return (Panda.Gene) Panda.Gene.CODEC.byName(name, Panda.Gene.NORMAL); // CraftBukkit - decompile error
}
public static Panda.Gene getRandom(RandomSource random) {
@@ -876,10 +889,10 @@
private final Panda panda;
public PandaAvoidGoal(Panda panda, Class<T> fleeFromType, float distance, double slowSpeed, double fastSpeed) {
- Predicate predicate = EntitySelector.NO_SPECTATORS;
+ // Predicate predicate = IEntitySelector.NO_SPECTATORS;
- Objects.requireNonNull(predicate);
- super(panda, fleeFromType, distance, slowSpeed, fastSpeed, predicate::test);
+ // Objects.requireNonNull(predicate);
+ super(panda, fleeFromType, distance, slowSpeed, fastSpeed, EntitySelector.NO_SPECTATORS::test);
this.panda = panda;
}
@@ -935,7 +948,9 @@
ItemStack itemstack = Panda.this.getItemBySlot(EquipmentSlot.MAINHAND);
if (!itemstack.isEmpty()) {
+ Panda.this.forceDrops = true; // Paper - Add missing forceDrop toggles
Panda.this.spawnAtLocation(getServerLevel(Panda.this.level()), itemstack);
+ Panda.this.forceDrops = false; // Paper - Add missing forceDrop toggles
Panda.this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
int i = Panda.this.isLazy() ? Panda.this.random.nextInt(50) + 10 : Panda.this.random.nextInt(150) + 10;
@@ -1116,7 +1131,7 @@
@Override
protected void alertOther(Mob mob, LivingEntity target) {
if (mob instanceof Panda && mob.isAggressive()) {
- mob.setTarget(target);
+ mob.setTarget(target, EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY, true); // CraftBukkit
}
}

View File

@@ -0,0 +1,47 @@
--- a/net/minecraft/world/entity/animal/Parrot.java
+++ b/net/minecraft/world/entity/animal/Parrot.java
@@ -248,7 +248,7 @@
}
if (!this.level().isClientSide) {
- if (this.random.nextInt(10) == 0) {
+ if (this.random.nextInt(10) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) { // CraftBukkit
this.tame(player);
this.level().broadcastEntityEvent(this, (byte) 7);
} else {
@@ -269,7 +269,7 @@
}
} else {
this.usePlayerItem(player, hand, itemstack);
- this.addEffect(new MobEffectInstance(MobEffects.POISON, 900));
+ this.addEffect(new MobEffectInstance(MobEffects.POISON, 900), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD); // CraftBukkit
if (player.isCreative() || !this.isInvulnerable()) {
this.hurt(this.damageSources().playerAttack(player), Float.MAX_VALUE);
}
@@ -362,8 +362,8 @@
}
@Override
- public boolean isPushable() {
- return true;
+ public boolean isCollidable(boolean ignoreClimbing) { // Paper - Climbing should not bypass cramming gamerule
+ return super.isCollidable(ignoreClimbing); // CraftBukkit - collidable API // Paper - Climbing should not bypass cramming gamerule
}
@Override
@@ -378,8 +378,14 @@
if (this.isInvulnerableTo(world, source)) {
return false;
} else {
+ // CraftBukkit start
+ boolean result = super.hurtServer(world, source, amount);
+ if (!result) {
+ return result;
+ }
+ // CraftBukkit end
this.setOrderedToSit(false);
- return super.hurtServer(world, source, amount);
+ return result; // CraftBukkit
}
}

View File

@@ -0,0 +1,29 @@
--- a/net/minecraft/world/entity/animal/Pig.java
+++ b/net/minecraft/world/entity/animal/Pig.java
@@ -49,6 +49,10 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
public class Pig extends Animal implements ItemSteerable, Saddleable {
@@ -247,7 +251,14 @@
}
entitypigzombie1.setPersistenceRequired();
- });
+ // CraftBukkit start
+ }, null, null);
+ if (CraftEventFactory.callPigZapEvent(this, lightning, entitypigzombie).isCancelled()) {
+ return;
+ }
+ world.addFreshEntity(entitypigzombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING);
+ this.discard(EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause
+ // CraftBukkit end
if (entitypigzombie == null) {
super.thunderHit(world, lightning);

View File

@@ -0,0 +1,60 @@
--- a/net/minecraft/world/entity/animal/Pufferfish.java
+++ b/net/minecraft/world/entity/animal/Pufferfish.java
@@ -102,25 +102,39 @@
public void tick() {
if (!this.level().isClientSide && this.isAlive() && this.isEffectiveAi()) {
if (this.inflateCounter > 0) {
+ boolean increase = true; // Paper - Add PufferFishStateChangeEvent
if (this.getPuffState() == 0) {
+ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 1).callEvent()) { // Paper - Add PufferFishStateChangeEvent
this.makeSound(SoundEvents.PUFFER_FISH_BLOW_UP);
this.setPuffState(1);
+ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent
} else if (this.inflateCounter > 40 && this.getPuffState() == 1) {
+ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 2).callEvent()) { // Paper - Add PufferFishStateChangeEvent
this.makeSound(SoundEvents.PUFFER_FISH_BLOW_UP);
this.setPuffState(2);
+ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent
}
+ if (increase) { // Paper - Add PufferFishStateChangeEvent
++this.inflateCounter;
+ } // Paper - Add PufferFishStateChangeEvent
} else if (this.getPuffState() != 0) {
+ boolean increase = true; // Paper - Add PufferFishStateChangeEvent
if (this.deflateTimer > 60 && this.getPuffState() == 2) {
+ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 1).callEvent()) { // Paper - Add PufferFishStateChangeEvent
this.makeSound(SoundEvents.PUFFER_FISH_BLOW_OUT);
this.setPuffState(1);
+ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent
} else if (this.deflateTimer > 100 && this.getPuffState() == 1) {
+ if (new io.papermc.paper.event.entity.PufferFishStateChangeEvent((org.bukkit.entity.PufferFish) getBukkitEntity(), 0).callEvent()) { // Paper - Add PufferFishStateChangeEvent
this.makeSound(SoundEvents.PUFFER_FISH_BLOW_OUT);
this.setPuffState(0);
+ } else { increase = false; } // Paper - Add PufferFishStateChangeEvent
}
+ if (increase) { // Paper - Add PufferFishStateChangeEvent
++this.deflateTimer;
+ } // Paper - Add PufferFishStateChangeEvent
}
}
@@ -155,7 +169,7 @@
int i = this.getPuffState();
if (target.hurtServer(world, this.damageSources().mobAttack(this), (float) (1 + i))) {
- target.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * i, 0), this);
+ target.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * i, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit
this.playSound(SoundEvents.PUFFER_FISH_STING, 1.0F, 1.0F);
}
@@ -171,7 +185,7 @@
entityplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.PUFFER_FISH_STING, 0.0F));
}
- player.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * i, 0), this);
+ player.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * i, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit
}
}

View File

@@ -0,0 +1,40 @@
--- a/net/minecraft/world/entity/animal/Rabbit.java
+++ b/net/minecraft/world/entity/animal/Rabbit.java
@@ -65,6 +65,9 @@
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+// CraftBukkit end
public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
@@ -90,7 +93,6 @@
super(type, world);
this.jumpControl = new Rabbit.RabbitJumpControl(this);
this.moveControl = new Rabbit.RabbitMoveControl(this);
- this.setSpeedModifier(0.0D);
}
@Override
@@ -577,9 +579,19 @@
int i = (Integer) iblockdata.getValue(CarrotBlock.AGE);
if (i == 0) {
+ // CraftBukkit start
+ if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
+ return;
+ }
+ // CraftBukkit end
world.setBlock(blockposition, Blocks.AIR.defaultBlockState(), 2);
world.destroyBlock(blockposition, true, this.rabbit);
} else {
+ // CraftBukkit start
+ if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockposition, iblockdata.setValue(CarrotBlock.AGE, i - 1))) {
+ return;
+ }
+ // CraftBukkit end
world.setBlock(blockposition, (BlockState) iblockdata.setValue(CarrotBlock.AGE, i - 1), 2);
world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of((Entity) this.rabbit));
world.levelEvent(2001, blockposition, Block.getId(iblockdata));

View File

@@ -0,0 +1,90 @@
--- a/net/minecraft/world/entity/animal/Sheep.java
+++ b/net/minecraft/world/entity/animal/Sheep.java
@@ -41,7 +41,6 @@
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
-import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
@@ -49,6 +48,12 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
+import net.minecraft.world.item.DyeColor;
+// CraftBukkit start
+import net.minecraft.world.item.Item;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.SheepRegrowWoolEvent;
+// CraftBukkit end
public class Sheep extends Animal implements Shearable {
@@ -160,7 +165,19 @@
ServerLevel worldserver = (ServerLevel) world;
if (this.readyForShearing()) {
- this.shear(worldserver, SoundSource.PLAYERS, itemstack);
+ // CraftBukkit start
+ // Paper start - custom shear drops
+ java.util.List<ItemStack> drops = this.generateDefaultDrops(worldserver, itemstack);
+ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops);
+ if (event != null) {
+ if (event.isCancelled()) {
+ return InteractionResult.PASS;
+ }
+ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
+ // Paper end - custom shear drops
+ }
+ // CraftBukkit end
+ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops
this.gameEvent(GameEvent.SHEAR, player);
itemstack.hurtAndBreak(1, player, getSlotForHand(hand));
return InteractionResult.SUCCESS_SERVER;
@@ -175,10 +192,29 @@
@Override
public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) {
+ // Paper start - custom shear drops
+ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears));
+ }
+
+ @Override
+ public java.util.List<ItemStack> generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) {
+ final java.util.List<ItemStack> drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.SHEAR_SHEEP, shears, (ignored, stack) -> {
+ for (int i = 0; i < stack.getCount(); ++i) drops.add(stack.copyWithCount(1));
+ });
+ return drops;
+ }
+
+ @Override
+ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List<ItemStack> drops) {
+ final ServerLevel worldserver1 = world; // Named for lambda consumption
+ // Paper end - custom shear drops
world.playSound((Player) null, (Entity) this, SoundEvents.SHEEP_SHEAR, shearedSoundCategory, 1.0F, 1.0F);
- this.dropFromShearingLootTable(world, BuiltInLootTables.SHEAR_SHEEP, shears, (worldserver1, itemstack1) -> {
- for (int i = 0; i < itemstack1.getCount(); ++i) {
- ItemEntity entityitem = this.spawnAtLocation(worldserver1, itemstack1.copyWithCount(1), 1.0F);
+ drops.forEach(itemstack1 -> { // Paper - custom drops - loop in generated default drops
+ if (true) { // Paper - custom drops - loop in generated default drops
+ this.forceDrops = true; // CraftBukkit
+ ItemEntity entityitem = this.spawnAtLocation(worldserver1, itemstack1, 1.0F); // Paper - custom drops - copy already done above
+ this.forceDrops = false; // CraftBukkit
if (entityitem != null) {
entityitem.setDeltaMovement(entityitem.getDeltaMovement().add((double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.1F), (double) (this.random.nextFloat() * 0.05F), (double) ((this.random.nextFloat() - this.random.nextFloat()) * 0.1F)));
@@ -276,6 +312,12 @@
@Override
public void ate() {
+ // CraftBukkit start
+ SheepRegrowWoolEvent event = new SheepRegrowWoolEvent((org.bukkit.entity.Sheep) this.getBukkitEntity());
+ this.level().getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) return;
+ // CraftBukkit end
super.ate();
this.setSheared(false);
if (this.isBaby()) {

View File

@@ -0,0 +1,21 @@
--- a/net/minecraft/world/entity/animal/ShoulderRidingEntity.java
+++ b/net/minecraft/world/entity/animal/ShoulderRidingEntity.java
@@ -5,6 +5,9 @@
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.level.Level;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
public abstract class ShoulderRidingEntity extends TamableAnimal {
@@ -21,7 +24,7 @@
nbttagcompound.putString("id", this.getEncodeId());
this.saveWithoutId(nbttagcompound);
if (player.setEntityOnShoulder(nbttagcompound)) {
- this.discard();
+ this.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
return true;
} else {
return false;

View File

@@ -0,0 +1,86 @@
--- a/net/minecraft/world/entity/animal/SnowGolem.java
+++ b/net/minecraft/world/entity/animal/SnowGolem.java
@@ -42,6 +42,9 @@
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+// CraftBukkit end
public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackMob {
@@ -100,7 +103,7 @@
if (world instanceof ServerLevel worldserver) {
if (this.level().getBiome(this.blockPosition()).is(BiomeTags.SNOW_GOLEM_MELTS)) {
- this.hurtServer(worldserver, this.damageSources().onFire(), 1.0F);
+ this.hurtServer(worldserver, this.damageSources().melting(), 1.0F); // CraftBukkit - DamageSources.ON_FIRE -> CraftEventFactory.MELTING
}
if (!worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
@@ -116,7 +119,11 @@
BlockPos blockposition = new BlockPos(j, k, l);
if (this.level().getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level(), blockposition)) {
- this.level().setBlockAndUpdate(blockposition, iblockdata);
+ // CraftBukkit start
+ if (!CraftEventFactory.handleBlockFormEvent(this.level(), blockposition, iblockdata, this)) {
+ continue;
+ }
+ // CraftBukkit end
this.level().gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition, GameEvent.Context.of(this, iblockdata));
}
}
@@ -153,7 +160,19 @@
if (world instanceof ServerLevel) {
ServerLevel worldserver = (ServerLevel) world;
- this.shear(worldserver, SoundSource.PLAYERS, itemstack);
+ // CraftBukkit start
+ // Paper start - custom shear drops
+ java.util.List<ItemStack> drops = this.generateDefaultDrops(worldserver, itemstack);
+ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops);
+ if (event != null) {
+ if (event.isCancelled()) {
+ return InteractionResult.PASS;
+ }
+ drops = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getDrops());
+ // Paper end - custom shear drops
+ }
+ // CraftBukkit end
+ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops
this.gameEvent(GameEvent.SHEAR, player);
itemstack.hurtAndBreak(1, player, getSlotForHand(hand));
}
@@ -166,10 +185,29 @@
@Override
public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) {
+ // Paper start - custom shear drops
+ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears));
+ }
+
+ @Override
+ public java.util.List<ItemStack> generateDefaultDrops(final ServerLevel serverLevel, final ItemStack shears) {
+ final java.util.List<ItemStack> drops = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+ this.dropFromShearingLootTable(serverLevel, BuiltInLootTables.SHEAR_SNOW_GOLEM, shears, (ignored, stack) -> {
+ drops.add(stack);
+ });
+ return drops;
+ }
+
+ @Override
+ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List<ItemStack> drops) {
+ final ServerLevel worldserver1 = world; // Named for lambda consumption
+ // Paper end - custom shear drops
world.playSound((Player) null, (Entity) this, SoundEvents.SNOW_GOLEM_SHEAR, shearedSoundCategory, 1.0F, 1.0F);
this.setPumpkin(false);
- this.dropFromShearingLootTable(world, BuiltInLootTables.SHEAR_SNOW_GOLEM, shears, (worldserver1, itemstack1) -> {
+ drops.forEach(itemstack1 -> { // Paper - custom shear drops
+ this.forceDrops = true; // CraftBukkit
this.spawnAtLocation(worldserver1, itemstack1, this.getEyeHeight());
+ this.forceDrops = false; // CraftBukkit
});
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/entity/animal/Squid.java
+++ b/net/minecraft/world/entity/animal/Squid.java
@@ -46,7 +46,7 @@
public Squid(EntityType<? extends Squid> type, Level world) {
super(type, world);
- this.random.setSeed((long)this.getId());
+ //this.random.setSeed((long)this.getId()); // Paper - Share random for entities to make them more random
this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F;
}

View File

@@ -0,0 +1,74 @@
--- a/net/minecraft/world/entity/animal/Turtle.java
+++ b/net/minecraft/world/entity/animal/Turtle.java
@@ -310,7 +310,9 @@
ServerLevel worldserver = (ServerLevel) world;
if (worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
+ this.forceDrops = true; // CraftBukkit
this.spawnAtLocation(worldserver, Items.TURTLE_SCUTE, 1);
+ this.forceDrops = false; // CraftBukkit
}
}
}
@@ -339,7 +341,7 @@
@Override
public void thunderHit(ServerLevel world, LightningBolt lightning) {
- this.hurtServer(world, this.damageSources().lightningBolt(), Float.MAX_VALUE);
+ this.hurtServer(world, this.damageSources().lightningBolt().customEventDamager(lightning), Float.MAX_VALUE); // CraftBukkit // Paper - fix DamageSource API
}
@Override
@@ -446,6 +448,10 @@
if (entityplayer == null && this.partner.getLoveCause() != null) {
entityplayer = this.partner.getLoveCause();
}
+ // Paper start - Add EntityFertilizeEggEvent event
+ io.papermc.paper.event.entity.EntityFertilizeEggEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this.animal, this.partner);
+ if (event.isCancelled()) return;
+ // Paper end - Add EntityFertilizeEggEvent event
if (entityplayer != null) {
entityplayer.awardStat(Stats.ANIMALS_BRED);
@@ -460,7 +466,7 @@
RandomSource randomsource = this.animal.getRandom();
if (getServerLevel((Level) this.level).getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1));
+ if (event.getExperience() > 0) this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), event.getExperience(), org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper - Add EntityFertilizeEggEvent event
}
}
@@ -492,16 +498,21 @@
if (!this.turtle.isInWater() && this.isReachedTarget()) {
if (this.turtle.layEggCounter < 1) {
- this.turtle.setLayingEgg(true);
+ this.turtle.setLayingEgg(new com.destroystokyo.paper.event.entity.TurtleStartDiggingEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level(), this.blockPos)).callEvent()); // Paper - Turtle API
} else if (this.turtle.layEggCounter > this.adjustedTickDelay(200)) {
Level world = this.turtle.level();
+ // Paper start - Turtle API
+ int eggCount = this.turtle.random.nextInt(4) + 1;
+ com.destroystokyo.paper.event.entity.TurtleLayEggEvent layEggEvent = new com.destroystokyo.paper.event.entity.TurtleLayEggEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level(), this.blockPos.above()), eggCount);
+ if (layEggEvent.callEvent() && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()))) {
world.playSound((Player) null, blockposition, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + world.random.nextFloat() * 0.2F);
BlockPos blockposition1 = this.blockPos.above();
- BlockState iblockdata = (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1);
+ BlockState iblockdata = (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount()); // Paper
world.setBlock(blockposition1, iblockdata, 3);
world.gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition1, GameEvent.Context.of(this.turtle, iblockdata));
+ } // CraftBukkit
this.turtle.setHasEgg(false);
this.turtle.setLayingEgg(false);
this.turtle.setInLoveTime(600);
@@ -567,7 +578,7 @@
@Override
public boolean canUse() {
- return this.turtle.isBaby() ? false : (this.turtle.hasEgg() ? true : (this.turtle.getRandom().nextInt(reducedTickDelay(700)) != 0 ? false : !this.turtle.getHomePos().closerToCenterThan(this.turtle.position(), 64.0D)));
+ return this.turtle.isBaby() ? false : (this.turtle.hasEgg() ? true : (this.turtle.getRandom().nextInt(reducedTickDelay(700)) != 0 ? false : !this.turtle.getHomePos().closerToCenterThan(this.turtle.position(), 64.0D))) && new com.destroystokyo.paper.event.entity.TurtleGoHomeEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity()).callEvent(); // Paper - Turtle API
}
@Override

View File

@@ -0,0 +1,13 @@
--- a/net/minecraft/world/entity/animal/WaterAnimal.java
+++ b/net/minecraft/world/entity/animal/WaterAnimal.java
@@ -70,6 +70,10 @@
) {
int i = world.getSeaLevel();
int j = i - 13;
+ // Paper start - Make water animal spawn height configurable
+ i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i);
+ j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j);
+ // Paper end - Make water animal spawn height configurable
return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER);
}
}

View File

@@ -0,0 +1,126 @@
--- a/net/minecraft/world/entity/animal/Wolf.java
+++ b/net/minecraft/world/entity/animal/Wolf.java
@@ -85,6 +85,12 @@
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.pathfinder.PathType;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.EntityRegainHealthEvent;
+import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+// CraftBukkit end
public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Holder<WolfVariant>> {
@@ -345,8 +351,14 @@
if (this.isInvulnerableTo(world, source)) {
return false;
} else {
+ // CraftBukkit start
+ boolean result = super.hurtServer(world, source, amount);
+ if (!result) {
+ return result;
+ }
+ // CraftBukkit end
this.setOrderedToSit(false);
- return super.hurtServer(world, source, amount);
+ return result; // CraftBukkit
}
}
@@ -356,21 +368,27 @@
}
@Override
- protected void actuallyHurt(ServerLevel world, DamageSource source, float amount) {
- if (!this.canArmorAbsorb(source)) {
- super.actuallyHurt(world, source, amount);
+ public boolean actuallyHurt(ServerLevel worldserver, DamageSource damagesource, float f, EntityDamageEvent event) { // CraftBukkit - void -> boolean
+ if (!this.canArmorAbsorb(damagesource)) {
+ return super.actuallyHurt(worldserver, damagesource, f, event); // CraftBukkit
} else {
+ // CraftBukkit start - SPIGOT-7815: if the damage was cancelled, no need to run the wolf armor behaviour
+ if (event.isCancelled()) {
+ return false;
+ }
+ // CraftBukkit end
ItemStack itemstack = this.getBodyArmorItem();
int i = itemstack.getDamageValue();
int j = itemstack.getMaxDamage();
- itemstack.hurtAndBreak(Mth.ceil(amount), this, EquipmentSlot.BODY);
+ itemstack.hurtAndBreak(Mth.ceil(f), this, EquipmentSlot.BODY);
if (Crackiness.WOLF_ARMOR.byDamage(i, j) != Crackiness.WOLF_ARMOR.byDamage(this.getBodyArmorItem())) {
this.playSound(SoundEvents.WOLF_ARMOR_CRACK);
- world.sendParticles(new ItemParticleOption(ParticleTypes.ITEM, Items.ARMADILLO_SCUTE.getDefaultInstance()), this.getX(), this.getY() + 1.0D, this.getZ(), 20, 0.2D, 0.1D, 0.2D, 0.1D);
+ worldserver.sendParticles(new ItemParticleOption(ParticleTypes.ITEM, Items.ARMADILLO_SCUTE.getDefaultInstance()), this.getX(), this.getY() + 1.0D, this.getZ(), 20, 0.2D, 0.1D, 0.2D, 0.1D);
}
}
+ return true; // CraftBukkit // Paper - return false ONLY if event was cancelled
}
private boolean canArmorAbsorb(DamageSource source) {
@@ -381,7 +399,7 @@
protected void applyTamingSideEffects() {
if (this.isTame()) {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(40.0D);
- this.setHealth(40.0F);
+ this.setHealth(this.getMaxHealth()); // CraftBukkit - 40.0 -> getMaxHealth()
} else {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(8.0D);
}
@@ -404,7 +422,7 @@
FoodProperties foodinfo = (FoodProperties) itemstack.get(DataComponents.FOOD);
float f = foodinfo != null ? (float) foodinfo.nutrition() : 1.0F;
- this.heal(2.0F * f);
+ this.heal(2.0F * f, EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit
return InteractionResult.SUCCESS;
} else {
if (item instanceof DyeItem) {
@@ -414,6 +432,14 @@
DyeColor enumcolor = itemdye.getDyeColor();
if (enumcolor != this.getCollarColor()) {
+ // Paper start - Add EntityDyeEvent and CollarColorable interface
+ final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) enumcolor.getId()), ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity());
+ if (!event.callEvent()) {
+ return InteractionResult.FAIL;
+ }
+ enumcolor = DyeColor.byId(event.getColor().getWoolData());
+ // Paper end - Add EntityDyeEvent and CollarColorable interface
+
this.setCollarColor(enumcolor);
itemstack.consume(1, player);
return InteractionResult.SUCCESS;
@@ -440,7 +466,9 @@
if (world instanceof ServerLevel) {
ServerLevel worldserver = (ServerLevel) world;
+ this.forceDrops = true; // CraftBukkit
this.spawnAtLocation(worldserver, itemstack1);
+ this.forceDrops = false; // CraftBukkit
}
return InteractionResult.SUCCESS;
@@ -459,7 +487,7 @@
this.setOrderedToSit(!this.isOrderedToSit());
this.jumping = false;
this.navigation.stop();
- this.setTarget((LivingEntity) null);
+ this.setTarget((LivingEntity) null, EntityTargetEvent.TargetReason.FORGOT_TARGET, true); // CraftBukkit - reason
return InteractionResult.SUCCESS.withoutItem();
} else {
return enuminteractionresult;
@@ -477,7 +505,8 @@
}
private void tryToTame(Player player) {
- if (this.random.nextInt(3) == 0) {
+ // CraftBukkit - added event call and isCancelled check.
+ if (this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) {
this.tame(player);
this.navigation.stop();
this.setTarget((LivingEntity) null);

View File

@@ -0,0 +1,102 @@
--- a/net/minecraft/world/entity/animal/allay/Allay.java
+++ b/net/minecraft/world/entity/animal/allay/Allay.java
@@ -103,6 +103,7 @@
private float dancingAnimationTicks;
private float spinningAnimationTicks;
private float spinningAnimationTicks0;
+ public boolean forceDancing = false; // CraftBukkit
public Allay(EntityType<? extends Allay> type, Level world) {
super(type, world);
@@ -114,6 +115,12 @@
this.dynamicJukeboxListener = new DynamicGameEventListener<>(new Allay.JukeboxListener(this.vibrationUser.getPositionSource(), ((GameEvent) GameEvent.JUKEBOX_PLAY.value()).notificationRadius()));
}
+ // CraftBukkit start
+ public void setCanDuplicate(boolean canDuplicate) {
+ this.entityData.set(Allay.DATA_CAN_DUPLICATE, canDuplicate);
+ }
+ // CraftBukkit end
+
@Override
protected Brain.Provider<Allay> brainProvider() {
return Brain.provider(Allay.MEMORY_TYPES, Allay.SENSOR_TYPES);
@@ -126,7 +133,7 @@
@Override
public Brain<Allay> getBrain() {
- return super.getBrain();
+ return (Brain<Allay>) super.getBrain(); // CraftBukkit - decompile error
}
public static AttributeSupplier.Builder createAttributes() {
@@ -233,7 +240,7 @@
public void aiStep() {
super.aiStep();
if (!this.level().isClientSide && this.isAlive() && this.tickCount % 10 == 0) {
- this.heal(1.0F);
+ this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit
}
if (this.isDancing() && this.shouldStopDancing() && this.tickCount % 20 == 0) {
@@ -303,7 +310,12 @@
ItemStack itemstack1 = this.getItemInHand(InteractionHand.MAIN_HAND);
if (this.isDancing() && itemstack.is(ItemTags.DUPLICATES_ALLAYS) && this.canDuplicate()) {
- this.duplicateAllay();
+ // CraftBukkit start - handle cancel duplication
+ Allay allay = this.duplicateAllay();
+ if (allay == null) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
this.level().broadcastEntityEvent(this, (byte) 18);
this.level().playSound(player, (Entity) this, SoundEvents.AMETHYST_BLOCK_CHIME, SoundSource.NEUTRAL, 2.0F, 1.0F);
this.removeInteractionItem(player, itemstack);
@@ -314,7 +326,7 @@
this.setItemInHand(InteractionHand.MAIN_HAND, itemstack2);
this.removeInteractionItem(player, itemstack);
this.level().playSound(player, (Entity) this, SoundEvents.ALLAY_ITEM_GIVEN, SoundSource.NEUTRAL, 2.0F, 1.0F);
- this.getBrain().setMemory(MemoryModuleType.LIKED_PLAYER, (Object) player.getUUID());
+ this.getBrain().setMemory(MemoryModuleType.LIKED_PLAYER, player.getUUID()); // CraftBukkit - decompile error
return InteractionResult.SUCCESS;
} else if (!itemstack1.isEmpty() && hand == InteractionHand.MAIN_HAND && itemstack.isEmpty()) {
this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
@@ -415,6 +427,7 @@
}
private boolean shouldStopDancing() {
+ if (this.forceDancing) {return false;} // CraftBukkit
return this.jukeboxPos == null || !this.jukeboxPos.closerToCenterThan(this.position(), (double) ((GameEvent) GameEvent.JUKEBOX_PLAY.value()).notificationRadius()) || !this.level().getBlockState(this.jukeboxPos).is(Blocks.JUKEBOX);
}
@@ -486,7 +499,7 @@
});
}
- this.duplicationCooldown = (long) nbt.getInt("DuplicationCooldown");
+ this.duplicationCooldown = nbt.getLong("DuplicationCooldown"); // Paper - Load as long
this.entityData.set(Allay.DATA_CAN_DUPLICATE, nbt.getBoolean("CanDuplicate"));
}
@@ -506,7 +519,7 @@
}
- public void duplicateAllay() {
+ public Allay duplicateAllay() { // CraftBukkit - return allay
Allay allay = (Allay) EntityType.ALLAY.create(this.level(), EntitySpawnReason.BREEDING);
if (allay != null) {
@@ -514,9 +527,9 @@
allay.setPersistenceRequired();
allay.resetDuplicationCooldown();
this.resetDuplicationCooldown();
- this.level().addFreshEntity(allay);
+ this.level().addFreshEntity(allay, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DUPLICATION); // CraftBukkit - reason for duplicated allay
}
-
+ return allay; // CraftBukkit
}
public void resetDuplicationCooldown() {

View File

@@ -0,0 +1,81 @@
--- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java
+++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java
@@ -47,6 +47,9 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityDamageEvent;
+// CraftBukkit end
public class Armadillo extends Animal {
@@ -135,16 +138,18 @@
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push("armadilloBrain");
- this.brain.tick(world, this);
+ ((Brain<Armadillo>) this.brain).tick(world, this); // CraftBukkit - decompile error
gameprofilerfiller.pop();
gameprofilerfiller.push("armadilloActivityUpdate");
ArmadilloAi.updateActivity(this);
gameprofilerfiller.pop();
if (this.isAlive() && !this.isBaby() && --this.scuteTime <= 0) {
+ this.forceDrops = true; // CraftBukkit
if (this.dropFromGiftLootTable(world, BuiltInLootTables.ARMADILLO_SHED, this::spawnAtLocation)) {
this.playSound(SoundEvents.ARMADILLO_SCUTE_DROP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
this.gameEvent(GameEvent.ENTITY_PLACE);
}
+ this.forceDrops = false; // CraftBukkit
this.scuteTime = this.pickNextScuteDropTime();
}
@@ -291,19 +296,25 @@
}
@Override
- protected void actuallyHurt(ServerLevel world, DamageSource source, float amount) {
- super.actuallyHurt(world, source, amount);
+ // CraftBukkit start - void -> boolean
+ public boolean actuallyHurt(ServerLevel worldserver, DamageSource damagesource, float f, EntityDamageEvent event) {
+ boolean damageResult = super.actuallyHurt(worldserver, damagesource, f, event);
+ if (!damageResult) {
+ return false;
+ }
+ // CraftBukkit end
if (!this.isNoAi() && !this.isDeadOrDying()) {
- if (source.getEntity() instanceof LivingEntity) {
+ if (damagesource.getEntity() instanceof LivingEntity) {
this.getBrain().setMemoryWithExpiry(MemoryModuleType.DANGER_DETECTED_RECENTLY, true, 80L);
if (this.canStayRolledUp()) {
this.rollUp();
}
- } else if (source.is(DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES)) {
+ } else if (damagesource.is(DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES)) {
this.rollOut();
}
}
+ return true; // CraftBukkit
}
@Override
@@ -327,7 +338,9 @@
if (world instanceof ServerLevel) {
ServerLevel worldserver = (ServerLevel) world;
+ this.forceDrops = true; // CraftBukkit
this.spawnAtLocation(worldserver, new ItemStack(Items.ARMADILLO_SCUTE));
+ this.forceDrops = false; // CraftBukkit
this.gameEvent(GameEvent.ENTITY_INTERACT);
this.playSound(SoundEvents.ARMADILLO_BRUSH);
}
@@ -431,7 +444,7 @@
}
public static Armadillo.ArmadilloState fromName(String name) {
- return (Armadillo.ArmadilloState) Armadillo.ArmadilloState.CODEC.byName(name, (Enum) Armadillo.ArmadilloState.IDLE);
+ return (Armadillo.ArmadilloState) Armadillo.ArmadilloState.CODEC.byName(name, Armadillo.ArmadilloState.IDLE); // CraftBukkit - decompile error
}
@Override

View File

@@ -0,0 +1,52 @@
--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java
+++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
@@ -67,10 +67,17 @@
public class Axolotl extends Animal implements VariantHolder<Axolotl.Variant>, Bucketable {
+ // CraftBukkit start - SPIGOT-6907: re-implement LivingEntity#setMaximumAir()
+ @Override
+ public int getDefaultMaxAirSupply() {
+ return Axolotl.AXOLOTL_TOTAL_AIR_SUPPLY;
+ }
+ // CraftBukkit end
public static final int TOTAL_PLAYDEAD_TIME = 200;
private static final int POSE_ANIMATION_TICKS = 10;
protected static final ImmutableList<? extends SensorType<? extends Sensor<? super Axolotl>>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_ADULT, SensorType.HURT_BY, SensorType.AXOLOTL_ATTACKABLES, SensorType.AXOLOTL_TEMPTATIONS);
- protected static final ImmutableList<? extends MemoryModuleType<?>> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.BREED_TARGET, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_VISIBLE_ADULT, new MemoryModuleType[]{MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.PLAY_DEAD_TICKS, MemoryModuleType.NEAREST_ATTACKABLE, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.HAS_HUNTING_COOLDOWN, MemoryModuleType.IS_PANICKING});
+ // CraftBukkit - decompile error
+ protected static final ImmutableList<? extends MemoryModuleType<?>> MEMORY_TYPES = ImmutableList.<MemoryModuleType<?>>of(MemoryModuleType.BREED_TARGET, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_VISIBLE_ADULT, new MemoryModuleType[]{MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.PLAY_DEAD_TICKS, MemoryModuleType.NEAREST_ATTACKABLE, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.HAS_HUNTING_COOLDOWN, MemoryModuleType.IS_PANICKING});
private static final EntityDataAccessor<Integer> DATA_VARIANT = SynchedEntityData.defineId(Axolotl.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> DATA_PLAYING_DEAD = SynchedEntityData.defineId(Axolotl.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Boolean> FROM_BUCKET = SynchedEntityData.defineId(Axolotl.class, EntityDataSerializers.BOOLEAN);
@@ -210,7 +217,7 @@
@Override
public int getMaxAirSupply() {
- return 6000;
+ return this.maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir()
}
@Override
@@ -414,10 +421,10 @@
int i = mobeffect != null ? mobeffect.getDuration() : 0;
int j = Math.min(2400, 100 + i);
- player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, j, 0), this);
+ player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, j, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // CraftBukkit
}
- player.removeEffect(MobEffects.DIG_SLOWDOWN);
+ player.removeEffect(MobEffects.DIG_SLOWDOWN, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // Paper - Add missing effect cause
}
@Override
@@ -464,7 +471,7 @@
@Override
public Brain<Axolotl> getBrain() {
- return super.getBrain();
+ return (Brain<Axolotl>) super.getBrain(); // CraftBukkit - decompile error
}
@Override

View File

@@ -0,0 +1,81 @@
--- a/net/minecraft/world/entity/animal/camel/Camel.java
+++ b/net/minecraft/world/entity/animal/camel/Camel.java
@@ -49,6 +49,9 @@
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityDamageEvent;
+// CraftBukkit end
public class Camel extends AbstractHorse {
@@ -143,7 +146,7 @@
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push("camelBrain");
- Brain<?> behaviorcontroller = this.getBrain();
+ Brain<Camel> behaviorcontroller = (Brain<Camel>) this.getBrain(); // CraftBukkit - decompile error
behaviorcontroller.tick(world, this);
gameprofilerfiller.pop();
@@ -386,13 +389,13 @@
boolean flag = this.getHealth() < this.getMaxHealth();
if (flag) {
- this.heal(2.0F);
+ this.heal(2.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason
}
boolean flag1 = this.isTamed() && this.getAge() == 0 && this.canFallInLove();
if (flag1) {
- this.setInLove(player);
+ this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying
}
boolean flag2 = this.isBaby();
@@ -454,9 +457,15 @@
}
@Override
- protected void actuallyHurt(ServerLevel world, DamageSource source, float amount) {
+ // CraftBukkit start - void -> boolean
+ public boolean actuallyHurt(ServerLevel worldserver, DamageSource damagesource, float f, EntityDamageEvent event) {
+ boolean damageResult = super.actuallyHurt(worldserver, damagesource, f, event);
+ if (!damageResult) {
+ return false;
+ }
+ // CraftBukkit end
this.standUpInstantly();
- super.actuallyHurt(world, source, amount);
+ return true; // CraftBukkit
}
@Override
@@ -563,7 +572,7 @@
}
public void sitDown() {
- if (!this.isCamelSitting()) {
+ if (!this.isCamelSitting() && new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), true).callEvent()) { // Paper - Add EntityToggleSitEvent
this.makeSound(SoundEvents.CAMEL_SIT);
this.setPose(Pose.SITTING);
this.gameEvent(GameEvent.ENTITY_ACTION);
@@ -572,7 +581,7 @@
}
public void standUp() {
- if (this.isCamelSitting()) {
+ if (this.isCamelSitting() && new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), false).callEvent()) { // Paper - Add EntityToggleSitEvent
this.makeSound(SoundEvents.CAMEL_STAND);
this.setPose(Pose.STANDING);
this.gameEvent(GameEvent.ENTITY_ACTION);
@@ -581,6 +590,7 @@
}
public void standUpInstantly() {
+ if (this.isCamelSitting() && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), false).callEvent()) return; // Paper - Add EntityToggleSitEvent
this.setPose(Pose.STANDING);
this.gameEvent(GameEvent.ENTITY_ACTION);
this.resetLastPoseChangeTickToFullStand(this.level().getGameTime());

View File

@@ -0,0 +1,16 @@
--- a/net/minecraft/world/entity/animal/frog/Frog.java
+++ b/net/minecraft/world/entity/animal/frog/Frog.java
@@ -270,7 +270,12 @@
@Override
public void spawnChildFromBreeding(ServerLevel world, Animal other) {
- this.finalizeSpawnChildFromBreeding(world, other, null);
+ // Paper start - Add EntityFertilizeEggEvent event
+ final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other);
+ if (result.isCancelled()) return;
+
+ this.finalizeSpawnChildFromBreeding(world, other, null, result.getExperience()); // Paper - use craftbukkit call that takes experience amount
+ // Paper end - Add EntityFertilizeEggEvent event
this.getBrain().setMemory(MemoryModuleType.IS_PREGNANT, Unit.INSTANCE);
}

View File

@@ -0,0 +1,39 @@
--- a/net/minecraft/world/entity/animal/frog/ShootTongue.java
+++ b/net/minecraft/world/entity/animal/frog/ShootTongue.java
@@ -19,6 +19,9 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
public class ShootTongue extends Behavior<Frog> {
@@ -64,7 +67,7 @@
BehaviorUtils.lookAtEntity(frog, entityliving);
frog.setTongueTarget(entityliving);
- frog.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (Object) (new WalkTarget(entityliving.position(), 2.0F, 0)));
+ frog.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (new WalkTarget(entityliving.position(), 2.0F, 0))); // CraftBukkit - decompile error
this.calculatePathCounter = 10;
this.state = ShootTongue.State.MOVE_TO_TARGET;
}
@@ -85,7 +88,7 @@
if (entity.isAlive()) {
frog.doHurtTarget(world, entity);
if (!entity.isAlive()) {
- entity.remove(Entity.RemovalReason.KILLED);
+ entity.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause
}
}
}
@@ -106,7 +109,7 @@
this.eatAnimationTimer = 0;
this.state = ShootTongue.State.CATCH_ANIMATION;
} else if (this.calculatePathCounter <= 0) {
- frog.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (Object) (new WalkTarget(entityliving.position(), 2.0F, 0)));
+ frog.getBrain().setMemory(MemoryModuleType.WALK_TARGET, (new WalkTarget(entityliving.position(), 2.0F, 0))); // CraftBukkit - decompile error
this.calculatePathCounter = 10;
} else {
--this.calculatePathCounter;

Some files were not shown because too many files have changed in this diff Show More