More mobs

This commit is contained in:
Nassim Jahnke
2024-12-13 19:25:16 +01:00
parent 7d42b87010
commit 3ef3394311
9 changed files with 349 additions and 432 deletions

View File

@@ -0,0 +1,36 @@
--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java
+++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
@@ -226,7 +_,7 @@
@Override
public int getMaxAirSupply() {
- return 6000;
+ return this.maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir()
}
@Override
@@ -426,10 +_,10 @@
if (effect == null || effect.endsWithin(2399)) {
int i = effect != null ? effect.getDuration() : 0;
int min = Math.min(2400, 100 + i);
- player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, min, 0), this);
+ player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, min, 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
@@ -620,4 +_,11 @@
return Util.getRandom(variants, random);
}
}
+
+ // CraftBukkit start - SPIGOT-6907: re-implement LivingEntity#setMaximumAir()
+ @Override
+ public int getDefaultMaxAirSupply() {
+ return Axolotl.AXOLOTL_TOTAL_AIR_SUPPLY;
+ }
+ // CraftBukkit end
}

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/world/entity/monster/breeze/Breeze.java
+++ b/net/minecraft/world/entity/monster/breeze/Breeze.java
@@ -250,6 +_,7 @@
@Override
public boolean canAttackType(EntityType<?> type) {
+ if (this.getTarget() != null) return this.getTarget().getType() == type; // SPIGOT-7957: Allow attack if target from brain was set
return type == EntityType.PLAYER || type == EntityType.IRON_GOLEM;
}

View File

@@ -0,0 +1,19 @@
--- a/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java
+++ b/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java
@@ -99,9 +_,14 @@
}
protected void finishConversion(ServerLevel serverLevel) {
- this.convertTo(
- EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), mob -> mob.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0))
+ net.minecraft.world.entity.Entity converted = this.convertTo( // Paper - Fix issues with mob conversion; reset to prevent event spam
+ EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), mob -> {mob.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0));}, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED // CraftBukkit - add spawn and transform reasons
);
+ // Paper start - Fix issues with mob conversion; reset to prevent event spam
+ if (converted == null) {
+ this.timeInOverworld = 0;
+ }
+ // Paper end - Fix issues with mob conversion
}
public boolean isAdult() {

View File

@@ -0,0 +1,119 @@
--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
@@ -4,15 +_,6 @@
import com.mojang.serialization.Dynamic;
import java.util.List;
import javax.annotation.Nullable;
-import net.minecraft.core.BlockPos;
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.network.syncher.EntityDataAccessor;
-import net.minecraft.network.syncher.EntityDataSerializers;
-import net.minecraft.network.syncher.SynchedEntityData;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.sounds.SoundEvent;
-import net.minecraft.sounds.SoundEvents;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagKey;
import net.minecraft.util.RandomSource;
@@ -59,6 +_,25 @@
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
+// CraftBukkit start
+import java.util.stream.Collectors;
+import java.util.HashSet;
+import java.util.Set;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.ListTag;
+import net.minecraft.nbt.StringTag;
+import net.minecraft.nbt.Tag;
+import net.minecraft.network.syncher.EntityDataAccessor;
+import net.minecraft.network.syncher.EntityDataSerializers;
+import net.minecraft.network.syncher.SynchedEntityData;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.sounds.SoundEvent;
+import net.minecraft.sounds.SoundEvents;
+import net.minecraft.world.item.Item;
+// CraftBukkit end
public class Piglin extends AbstractPiglin implements CrossbowAttackMob, InventoryCarrier {
private static final EntityDataAccessor<Boolean> DATA_BABY_ID = SynchedEntityData.defineId(Piglin.class, EntityDataSerializers.BOOLEAN);
@@ -122,6 +_,10 @@
MemoryModuleType.ATE_RECENTLY,
MemoryModuleType.NEAREST_REPELLENT
);
+ // CraftBukkit start - Custom bartering and interest list
+ public Set<Item> allowedBarterItems = new HashSet<>();
+ public Set<Item> interestItems = new HashSet<>();
+ // CraftBukkit end
public Piglin(EntityType<? extends AbstractPiglin> entityType, Level level) {
super(entityType, level);
@@ -140,6 +_,14 @@
}
this.writeInventoryToTag(compound, this.registryAccess());
+ // CraftBukkit start
+ ListTag barterList = new ListTag();
+ this.allowedBarterItems.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).map(StringTag::valueOf).forEach(barterList::add);
+ compound.put("Bukkit.BarterList", barterList);
+ ListTag interestList = new ListTag();
+ this.interestItems.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).map(StringTag::valueOf).forEach(interestList::add);
+ compound.put("Bukkit.InterestList", interestList);
+ // CraftBukkit end
}
@Override
@@ -148,6 +_,10 @@
this.setBaby(compound.getBoolean("IsBaby"));
this.setCannotHunt(compound.getBoolean("CannotHunt"));
this.readInventoryFromTag(compound, this.registryAccess());
+ // CraftBukkit start
+ this.allowedBarterItems = compound.getList("Bukkit.BarterList", 8).stream().map(Tag::getAsString).map(ResourceLocation::tryParse).map(BuiltInRegistries.ITEM::getValue).collect(Collectors.toCollection(HashSet::new));
+ this.interestItems = compound.getList("Bukkit.InterestList", 8).stream().map(Tag::getAsString).map(ResourceLocation::tryParse).map(BuiltInRegistries.ITEM::getValue).collect(Collectors.toCollection(HashSet::new));
+ // CraftBukkit end
}
@VisibleForDebug
@@ -325,7 +_,9 @@
@Override
protected void finishConversion(ServerLevel serverLevel) {
PiglinAi.cancelAdmiring(serverLevel, this);
+ this.forceDrops = true; // Paper - Add missing forceDrop toggles
this.inventory.removeAllItems().forEach(itemStack -> this.spawnAtLocation(serverLevel, itemStack));
+ this.forceDrops = false; // Paper - Add missing forceDrop toggles
super.finishConversion(serverLevel);
}
@@ -400,7 +_,7 @@
}
protected void holdInOffHand(ItemStack stack) {
- if (stack.is(PiglinAi.BARTERING_ITEM)) {
+ if (stack.is(PiglinAi.BARTERING_ITEM) || this.allowedBarterItems.contains(stack.getItem())) { // CraftBukkit - Changes to accept custom payment items
this.setItemSlot(EquipmentSlot.OFFHAND, stack);
this.setGuaranteedDrop(EquipmentSlot.OFFHAND);
} else {
@@ -425,15 +_,15 @@
return false;
} else {
TagKey<Item> preferredWeaponType = this.getPreferredWeaponType();
- boolean flag = PiglinAi.isLovedItem(newItem) || preferredWeaponType != null && newItem.is(preferredWeaponType);
- boolean flag1 = PiglinAi.isLovedItem(currentItem) || preferredWeaponType != null && currentItem.is(preferredWeaponType);
+ boolean flag = PiglinAi.isLovedItem(newItem, this) || preferredWeaponType != null && newItem.is(preferredWeaponType); // CraftBukkit
+ boolean flag1 = PiglinAi.isLovedItem(currentItem, this) || preferredWeaponType != null && currentItem.is(preferredWeaponType); // CraftBukkit
return flag && !flag1 || (flag || !flag1) && super.canReplaceCurrentItem(newItem, currentItem, slot);
}
}
@Override
protected void pickUpItem(ServerLevel level, ItemEntity entity) {
- this.onItemPickup(entity);
+ // this.onItemPickup(entity); // Paper - EntityPickupItemEvent fixes; call in PiglinAi#pickUpItem after EntityPickupItemEvent is fired
PiglinAi.pickUpItem(level, this, entity);
}

View File

@@ -0,0 +1,174 @@
--- a/net/minecraft/world/entity/monster/piglin/PiglinAi.java
+++ b/net/minecraft/world/entity/monster/piglin/PiglinAi.java
@@ -70,6 +_,13 @@
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import java.util.stream.Collectors;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.entity.EntityRemoveEvent;
+import org.bukkit.event.entity.PiglinBarterEvent;
+// CraftBukkit end
public class PiglinAi {
public static final int REPELLENT_DETECTION_RANGE_HORIZONTAL = 8;
@@ -328,23 +_,32 @@
protected static void pickUpItem(ServerLevel level, Piglin piglin, ItemEntity itemEntity) {
stopWalking(piglin);
ItemStack item;
- if (itemEntity.getItem().is(Items.GOLD_NUGGET)) {
+ // CraftBukkit start
+ // Paper start - EntityPickupItemEvent fixes; fix event firing twice
+ if (itemEntity.getItem().is(Items.GOLD_NUGGET)/* && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()*/) { // Paper
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()) return;
+ piglin.onItemPickup(itemEntity); // Paper - moved from Piglin#pickUpItem - call prior to item entity modification
+ // Paper end
piglin.take(itemEntity, itemEntity.getItem().getCount());
item = itemEntity.getItem();
- itemEntity.discard();
- } else {
+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
+ } else if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, itemEntity.getItem().getCount() - 1, false).isCancelled()) {
+ piglin.onItemPickup(itemEntity); // Paper - EntityPickupItemEvent fixes; moved from Piglin#pickUpItem - call prior to item entity modification
piglin.take(itemEntity, 1);
item = removeOneItemFromItemEntity(itemEntity);
+ } else {
+ return;
+ // CraftBukkit end
}
- if (isLovedItem(item)) {
+ if (isLovedItem(item, piglin)) { // CraftBukkit - Changes to allow for custom payment in bartering
piglin.getBrain().eraseMemory(MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM);
holdInOffhand(level, piglin, item);
admireGoldItem(piglin);
} else if (isFood(item) && !hasEatenRecently(piglin)) {
eat(piglin);
} else {
- boolean flag = !piglin.equipItemIfPossible(level, item).equals(ItemStack.EMPTY);
+ boolean flag = !piglin.equipItemIfPossible(level, item, null).equals(ItemStack.EMPTY); // CraftBukkit // Paper - pass null item entity to prevent duplicate pickup item event call - called above.
if (!flag) {
putInInventory(piglin, item);
}
@@ -353,7 +_,9 @@
private static void holdInOffhand(ServerLevel level, Piglin piglin, ItemStack stack) {
if (isHoldingItemInOffHand(piglin)) {
+ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles
piglin.spawnAtLocation(level, piglin.getItemInHand(InteractionHand.OFF_HAND));
+ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles
}
piglin.holdInOffHand(stack);
@@ -363,7 +_,7 @@
ItemStack item = itemEntity.getItem();
ItemStack itemStack = item.split(1);
if (item.isEmpty()) {
- itemEntity.discard();
+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
} else {
itemEntity.setItem(item);
}
@@ -375,9 +_,14 @@
ItemStack itemInHand = piglin.getItemInHand(InteractionHand.OFF_HAND);
piglin.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY);
if (piglin.isAdult()) {
- boolean isBarterCurrency = isBarterCurrency(itemInHand);
+ boolean isBarterCurrency = isBarterCurrency(itemInHand, piglin); // CraftBukkit - Changes to allow custom payment for bartering
if (barter && isBarterCurrency) {
- throwItems(piglin, getBarterResponseItems(piglin));
+ // CraftBukkit start
+ PiglinBarterEvent event = CraftEventFactory.callPiglinBarterEvent(piglin, getBarterResponseItems(piglin), itemInHand);
+ if (!event.isCancelled()) {
+ throwItems(piglin, event.getOutcome().stream().map(CraftItemStack::asNMSCopy).collect(Collectors.toList()));
+ }
+ // CraftBukkit end
} else if (!isBarterCurrency) {
boolean flag = !piglin.equipItemIfPossible(level, itemInHand).isEmpty();
if (!flag) {
@@ -388,7 +_,7 @@
boolean isBarterCurrency = !piglin.equipItemIfPossible(level, itemInHand).isEmpty();
if (!isBarterCurrency) {
ItemStack mainHandItem = piglin.getMainHandItem();
- if (isLovedItem(mainHandItem)) {
+ if (isLovedItem(mainHandItem, piglin)) { // CraftBukkit - Changes to allow for custom payment in bartering
putInInventory(piglin, mainHandItem);
} else {
throwItems(piglin, Collections.singletonList(mainHandItem));
@@ -401,7 +_,9 @@
protected static void cancelAdmiring(ServerLevel level, Piglin piglin) {
if (isAdmiringItem(piglin) && !piglin.getOffhandItem().isEmpty()) {
+ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles
piglin.spawnAtLocation(level, piglin.getOffhandItem());
+ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles
piglin.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY);
}
}
@@ -457,7 +_,7 @@
return false;
} else if (isAdmiringDisabled(piglin) && piglin.getBrain().hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) {
return false;
- } else if (isBarterCurrency(stack)) {
+ } else if (isBarterCurrency(stack, piglin)) { // CraftBukkit
return isNotHoldingLovedItemInOffHand(piglin);
} else {
boolean canAddToInventory = piglin.canAddToInventory(stack);
@@ -466,11 +_,16 @@
} else if (isFood(stack)) {
return !hasEatenRecently(piglin) && canAddToInventory;
} else {
- return !isLovedItem(stack) ? piglin.canReplaceCurrentItem(stack) : isNotHoldingLovedItemInOffHand(piglin) && canAddToInventory;
+ return !isLovedItem(stack, piglin) ? piglin.canReplaceCurrentItem(stack) : isNotHoldingLovedItemInOffHand(piglin) && canAddToInventory; // Paper - upstream missed isLovedItem check
}
}
}
+ // CraftBukkit start - Added method to allow checking for custom payment items
+ protected static boolean isLovedItem(ItemStack item, Piglin piglin) {
+ return PiglinAi.isLovedItem(item) || (piglin.interestItems.contains(item.getItem()) || piglin.allowedBarterItems.contains(item.getItem()));
+ }
+ // CraftBukkit end
protected static boolean isLovedItem(ItemStack item) {
return item.is(ItemTags.PIGLIN_LOVED);
}
@@ -522,6 +_,7 @@
}
public static void angerNearbyPiglins(ServerLevel level, Player player, boolean requireLineOfSight) {
+ if (!player.level().paperConfig().entities.behavior.piglinsGuardChests) return; // Paper - Config option for Piglins guarding chests
List<Piglin> entitiesOfClass = player.level().getEntitiesOfClass(Piglin.class, player.getBoundingBox().inflate(16.0));
entitiesOfClass.stream().filter(PiglinAi::isIdle).filter(piglin -> !requireLineOfSight || BehaviorUtils.canSee(piglin, player)).forEach(piglin -> {
if (level.getGameRules().getBoolean(GameRules.RULE_UNIVERSAL_ANGER)) {
@@ -546,7 +_,7 @@
}
protected static boolean canAdmire(Piglin piglin, ItemStack stack) {
- return !isAdmiringDisabled(piglin) && !isAdmiringItem(piglin) && piglin.isAdult() && isBarterCurrency(stack);
+ return !isAdmiringDisabled(piglin) && !isAdmiringItem(piglin) && piglin.isAdult() && isBarterCurrency(stack, piglin); // CraftBukkit
}
protected static void wasHurtBy(ServerLevel level, Piglin piglin, LivingEntity entity) {
@@ -794,6 +_,11 @@
return piglin.getBrain().hasMemoryValue(MemoryModuleType.ADMIRING_ITEM);
}
+ // CraftBukkit start - Changes to allow custom payment for bartering
+ private static boolean isBarterCurrency(ItemStack item, Piglin piglin) {
+ return PiglinAi.isBarterCurrency(item) || piglin.allowedBarterItems.contains(item.getItem());
+ }
+ // CraftBukkit end
private static boolean isBarterCurrency(ItemStack stack) {
return stack.is(BARTERING_ITEM);
}
@@ -831,7 +_,7 @@
}
private static boolean isNotHoldingLovedItemInOffHand(Piglin piglin) {
- return piglin.getOffhandItem().isEmpty() || !isLovedItem(piglin.getOffhandItem());
+ return piglin.getOffhandItem().isEmpty() || !isLovedItem(piglin.getOffhandItem(), piglin); // CraftBukkit - Changes to allow custom payment for bartering
}
public static boolean isZombified(EntityType<?> entityType) {