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,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
}
}