diff options
Diffstat (limited to 'patch-remap/mache-vineflower/net/minecraft/world/entity/monster/Zombie.java.patch')
-rw-r--r-- | patch-remap/mache-vineflower/net/minecraft/world/entity/monster/Zombie.java.patch | 718 |
1 files changed, 718 insertions, 0 deletions
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/entity/monster/Zombie.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/entity/monster/Zombie.java.patch new file mode 100644 index 0000000000..d2568e3ef0 --- /dev/null +++ b/patch-remap/mache-vineflower/net/minecraft/world/entity/monster/Zombie.java.patch @@ -0,0 +1,718 @@ +--- a/net/minecraft/world/entity/monster/Zombie.java ++++ b/net/minecraft/world/entity/monster/Zombie.java +@@ -6,17 +6,6 @@ + import java.util.UUID; + import java.util.function.Predicate; + import javax.annotation.Nullable; +-import net.minecraft.core.BlockPos; +-import net.minecraft.nbt.CompoundTag; +-import net.minecraft.nbt.NbtOps; +-import net.minecraft.network.syncher.EntityDataAccessor; +-import net.minecraft.network.syncher.EntityDataSerializers; +-import net.minecraft.network.syncher.SynchedEntityData; +-import net.minecraft.server.level.ServerLevel; +-import net.minecraft.sounds.SoundEvent; +-import net.minecraft.sounds.SoundEvents; +-import net.minecraft.sounds.SoundSource; +-import net.minecraft.tags.FluidTags; + import net.minecraft.util.Mth; + import net.minecraft.util.RandomSource; + import net.minecraft.world.Difficulty; +@@ -24,15 +13,15 @@ + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityDimensions; ++import net.minecraft.world.entity.EntityPose; + import net.minecraft.world.entity.EntitySelector; + import net.minecraft.world.entity.EntityType; ++import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.EnumMonsterType; + import net.minecraft.world.entity.EquipmentSlot; ++import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.LivingEntity; +-import net.minecraft.world.entity.MobSpawnType; +-import net.minecraft.world.entity.MobType; + import net.minecraft.world.entity.PathfinderMob; +-import net.minecraft.world.entity.Pose; +-import net.minecraft.world.entity.SpawnGroupData; + import net.minecraft.world.entity.SpawnPlacements; + import net.minecraft.world.entity.ai.attributes.AttributeInstance; + import net.minecraft.world.entity.ai.attributes.AttributeModifier; +@@ -63,31 +52,53 @@ + import net.minecraft.world.level.NaturalSpawner; + import net.minecraft.world.level.ServerLevelAccessor; + import net.minecraft.world.level.block.Blocks; +-import net.minecraft.world.level.block.state.BlockState; ++import net.minecraft.world.level.block.state.IBlockData; + import org.joml.Vector3f; ++import net.minecraft.core.BlockPos; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.nbt.NbtOps; ++import net.minecraft.nbt.Tag; ++import net.minecraft.network.syncher.EntityDataAccessor; ++import net.minecraft.network.syncher.EntityDataSerializers; ++import net.minecraft.network.syncher.SynchedEntityData; ++// CraftBukkit start ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.sounds.SoundEvent; ++import net.minecraft.sounds.SoundEvents; ++import net.minecraft.sounds.SoundSource; ++import net.minecraft.tags.FluidTags; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.bukkit.event.entity.EntityCombustByEntityEvent; ++import org.bukkit.event.entity.EntityTargetEvent; ++import org.bukkit.event.entity.EntityTransformEvent; ++// CraftBukkit end + + public class Zombie extends Monster { ++ + private static final UUID SPEED_MODIFIER_BABY_UUID = UUID.fromString("B9766B59-9566-4402-BC1F-2EE2A276D836"); +- private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier( +- SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5, AttributeModifier.Operation.MULTIPLY_BASE +- ); ++ private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5D, AttributeModifier.Operation.MULTIPLY_BASE); + private static final EntityDataAccessor<Boolean> DATA_BABY_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor<Integer> DATA_SPECIAL_TYPE_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.INT); +- private static final EntityDataAccessor<Boolean> DATA_DROWNED_CONVERSION_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.BOOLEAN); ++ public static final EntityDataAccessor<Boolean> DATA_DROWNED_CONVERSION_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.BOOLEAN); + public static final float ZOMBIE_LEADER_CHANCE = 0.05F; + public static final int REINFORCEMENT_ATTEMPTS = 50; + public static final int REINFORCEMENT_RANGE_MAX = 40; + public static final int REINFORCEMENT_RANGE_MIN = 7; + protected static final float BABY_EYE_HEIGHT_ADJUSTMENT = 0.81F; + private static final float BREAK_DOOR_CHANCE = 0.1F; +- private static final Predicate<Difficulty> DOOR_BREAKING_PREDICATE = difficulty -> difficulty == Difficulty.HARD; +- private final BreakDoorGoal breakDoorGoal = new BreakDoorGoal(this, DOOR_BREAKING_PREDICATE); ++ private static final Predicate<Difficulty> DOOR_BREAKING_PREDICATE = (enumdifficulty) -> { ++ return enumdifficulty == Difficulty.HARD; ++ }; ++ private final BreakDoorGoal breakDoorGoal; + private boolean canBreakDoors; + private int inWaterTime; +- private int conversionTime; ++ public int conversionTime; ++ private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field + + public Zombie(EntityType<? extends Zombie> entityType, Level level) { + super(entityType, level); ++ this.breakDoorGoal = new BreakDoorGoal(this, Zombie.DOOR_BREAKING_PREDICATE); + } + + public Zombie(Level level) { +@@ -96,17 +107,17 @@ + + @Override + protected void registerGoals() { +- this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0, 3)); ++ this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); + this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.addBehaviourGoals(); + } + + protected void addBehaviourGoals() { +- this.goalSelector.addGoal(2, new ZombieAttackGoal(this, 1.0, false)); +- this.goalSelector.addGoal(6, new MoveThroughVillageGoal(this, 1.0, true, 4, this::canBreakDoors)); +- this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0)); +- this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class)); ++ this.goalSelector.addGoal(2, new ZombieAttackGoal(this, 1.0D, false)); ++ this.goalSelector.addGoal(6, new MoveThroughVillageGoal(this, 1.0D, true, 4, this::canBreakDoors)); ++ this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D)); ++ this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers(ZombifiedPiglin.class)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); +@@ -114,24 +125,19 @@ + } + + public static AttributeSupplier.Builder createAttributes() { +- return Monster.createMonsterAttributes() +- .add(Attributes.FOLLOW_RANGE, 35.0) +- .add(Attributes.MOVEMENT_SPEED, 0.23F) +- .add(Attributes.ATTACK_DAMAGE, 3.0) +- .add(Attributes.ARMOR, 2.0) +- .add(Attributes.SPAWN_REINFORCEMENTS_CHANCE); ++ return Monster.createMonsterAttributes().add(Attributes.FOLLOW_RANGE, 35.0D).add(Attributes.MOVEMENT_SPEED, 0.23000000417232513D).add(Attributes.ATTACK_DAMAGE, 3.0D).add(Attributes.ARMOR, 2.0D).add(Attributes.SPAWN_REINFORCEMENTS_CHANCE); + } + + @Override + protected void defineSynchedData() { + super.defineSynchedData(); +- this.getEntityData().define(DATA_BABY_ID, false); +- this.getEntityData().define(DATA_SPECIAL_TYPE_ID, 0); +- this.getEntityData().define(DATA_DROWNED_CONVERSION_ID, false); ++ this.getEntityData().define(Zombie.DATA_BABY_ID, false); ++ this.getEntityData().define(Zombie.DATA_SPECIAL_TYPE_ID, 0); ++ this.getEntityData().define(Zombie.DATA_DROWNED_CONVERSION_ID, false); + } + + public boolean isUnderWaterConverting() { +- return this.getEntityData().get(DATA_DROWNED_CONVERSION_ID); ++ return (Boolean) this.getEntityData().get(Zombie.DATA_DROWNED_CONVERSION_ID); + } + + public boolean canBreakDoors() { +@@ -142,7 +148,7 @@ + if (this.supportsBreakDoorGoal() && GoalUtils.hasGroundPathNavigation(this)) { + if (this.canBreakDoors != canBreakDoors) { + this.canBreakDoors = canBreakDoors; +- ((GroundPathNavigation)this.getNavigation()).setCanOpenDoors(canBreakDoors); ++ ((GroundPathNavigation) this.getNavigation()).setCanOpenDoors(canBreakDoors); + if (canBreakDoors) { + this.goalSelector.addGoal(1, this.breakDoorGoal); + } else { +@@ -153,6 +159,7 @@ + this.goalSelector.removeGoal(this.breakDoorGoal); + this.canBreakDoors = false; + } ++ + } + + protected boolean supportsBreakDoorGoal() { +@@ -161,13 +168,13 @@ + + @Override + public boolean isBaby() { +- return this.getEntityData().get(DATA_BABY_ID); ++ return (Boolean) this.getEntityData().get(Zombie.DATA_BABY_ID); + } + + @Override + public int getExperienceReward() { + if (this.isBaby()) { +- this.xpReward = (int)((double)this.xpReward * 2.5); ++ this.xpReward = (int) ((double) this.xpReward * 2.5D); + } + + return super.getExperienceReward(); +@@ -175,19 +182,21 @@ + + @Override + public void setBaby(boolean childZombie) { +- this.getEntityData().set(DATA_BABY_ID, childZombie); ++ this.getEntityData().set(Zombie.DATA_BABY_ID, childZombie); + if (this.level() != null && !this.level().isClientSide) { +- AttributeInstance attribute = this.getAttribute(Attributes.MOVEMENT_SPEED); +- attribute.removeModifier(SPEED_MODIFIER_BABY.getId()); ++ AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED); ++ ++ attributemodifiable.removeModifier(Zombie.SPEED_MODIFIER_BABY.getId()); + if (childZombie) { +- attribute.addTransientModifier(SPEED_MODIFIER_BABY); ++ attributemodifiable.addTransientModifier(Zombie.SPEED_MODIFIER_BABY); + } + } ++ + } + + @Override + public void onSyncedDataUpdated(EntityDataAccessor<?> key) { +- if (DATA_BABY_ID.equals(key)) { ++ if (Zombie.DATA_BABY_ID.equals(key)) { + this.refreshDimensions(); + } + +@@ -202,13 +211,16 @@ + public void tick() { + if (!this.level().isClientSide && this.isAlive() && !this.isNoAi()) { + if (this.isUnderWaterConverting()) { +- this.conversionTime--; ++ // CraftBukkit start - Use wall time instead of ticks for conversion ++ int elapsedTicks = MinecraftServer.currentTick - this.lastTick; ++ this.conversionTime -= elapsedTicks; ++ // CraftBukkit end + if (this.conversionTime < 0) { + this.doUnderWaterConversion(); + } + } else if (this.convertsInWater()) { + if (this.isEyeInFluid(FluidTags.WATER)) { +- this.inWaterTime++; ++ ++this.inWaterTime; + if (this.inWaterTime >= 600) { + this.startUnderWaterConversion(300); + } +@@ -219,18 +231,21 @@ + } + + super.tick(); ++ this.lastTick = MinecraftServer.currentTick; // CraftBukkit + } + + @Override + public void aiStep() { + if (this.isAlive()) { + boolean flag = this.isSunSensitive() && this.isSunBurnTick(); ++ + if (flag) { +- ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD); +- if (!itemBySlot.isEmpty()) { +- if (itemBySlot.isDamageableItem()) { +- itemBySlot.setDamageValue(itemBySlot.getDamageValue() + this.random.nextInt(2)); +- if (itemBySlot.getDamageValue() >= itemBySlot.getMaxDamage()) { ++ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); ++ ++ if (!itemstack.isEmpty()) { ++ if (itemstack.isDamageableItem()) { ++ itemstack.setDamageValue(itemstack.getDamageValue() + this.random.nextInt(2)); ++ if (itemstack.getDamageValue() >= itemstack.getMaxDamage()) { + this.broadcastBreakEvent(EquipmentSlot.HEAD); + this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY); + } +@@ -248,24 +263,32 @@ + super.aiStep(); + } + +- private void startUnderWaterConversion(int conversionTime) { ++ public void startUnderWaterConversion(int conversionTime) { ++ this.lastTick = MinecraftServer.currentTick; // CraftBukkit + this.conversionTime = conversionTime; +- this.getEntityData().set(DATA_DROWNED_CONVERSION_ID, true); ++ this.getEntityData().set(Zombie.DATA_DROWNED_CONVERSION_ID, true); + } + + protected void doUnderWaterConversion() { + this.convertToZombieType(EntityType.DROWNED); + if (!this.isSilent()) { +- this.level().levelEvent(null, 1040, this.blockPosition(), 0); ++ this.level().levelEvent((Player) null, 1040, this.blockPosition(), 0); + } ++ + } + + protected void convertToZombieType(EntityType<? extends Zombie> entityType) { +- Zombie zombie = this.convertTo(entityType, true); +- if (zombie != null) { +- zombie.handleAttributes(zombie.level().getCurrentDifficultyAt(zombie.blockPosition()).getSpecialMultiplier()); +- zombie.setCanBreakDoors(zombie.supportsBreakDoorGoal() && this.canBreakDoors()); ++ Zombie entityzombie = (Zombie) this.convertTo(entityType, true, EntityTransformEvent.TransformReason.DROWNED, CreatureSpawnEvent.SpawnReason.DROWNED); ++ ++ if (entityzombie != null) { ++ entityzombie.handleAttributes(entityzombie.level().getCurrentDifficultyAt(entityzombie.blockPosition()).getSpecialMultiplier()); ++ entityzombie.setCanBreakDoors(entityzombie.supportsBreakDoorGoal() && this.canBreakDoors()); ++ // CraftBukkit start - SPIGOT-5208: End conversion to stop event spam ++ } else { ++ ((org.bukkit.entity.Zombie) getBukkitEntity()).setConversionTime(-1); ++ // CraftBukkit end + } ++ + } + + protected boolean isSunSensitive() { +@@ -279,44 +302,35 @@ + } else if (!(this.level() instanceof ServerLevel)) { + return false; + } else { +- ServerLevel serverLevel = (ServerLevel)this.level(); +- LivingEntity target = this.getTarget(); +- if (target == null && source.getEntity() instanceof LivingEntity) { +- target = (LivingEntity)source.getEntity(); ++ ServerLevel worldserver = (ServerLevel) this.level(); ++ LivingEntity entityliving = this.getTarget(); ++ ++ if (entityliving == null && source.getEntity() instanceof LivingEntity) { ++ entityliving = (LivingEntity) source.getEntity(); + } + +- if (target != null +- && this.level().getDifficulty() == Difficulty.HARD +- && (double)this.random.nextFloat() < this.getAttributeValue(Attributes.SPAWN_REINFORCEMENTS_CHANCE) +- && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { +- int floor = Mth.floor(this.getX()); +- int floor1 = Mth.floor(this.getY()); +- int floor2 = Mth.floor(this.getZ()); +- Zombie zombie = new Zombie(this.level()); ++ if (entityliving != null && this.level().getDifficulty() == Difficulty.HARD && (double) this.random.nextFloat() < this.getAttributeValue(Attributes.SPAWN_REINFORCEMENTS_CHANCE) && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { ++ int i = Mth.floor(this.getX()); ++ int j = Mth.floor(this.getY()); ++ int k = Mth.floor(this.getZ()); ++ Zombie entityzombie = new Zombie(this.level()); + +- for (int i = 0; i < 50; i++) { +- int i1 = floor + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1); +- int i2 = floor1 + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1); +- int i3 = floor2 + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1); +- BlockPos blockPos = new BlockPos(i1, i2, i3); +- EntityType<?> type = zombie.getType(); +- SpawnPlacements.Type placementType = SpawnPlacements.getPlacementType(type); +- if (NaturalSpawner.isSpawnPositionOk(placementType, this.level(), blockPos, type) +- && SpawnPlacements.checkSpawnRules(type, serverLevel, MobSpawnType.REINFORCEMENT, blockPos, this.level().random)) { +- zombie.setPos((double)i1, (double)i2, (double)i3); +- if (!this.level().hasNearbyAlivePlayer((double)i1, (double)i2, (double)i3, 7.0) +- && this.level().isUnobstructed(zombie) +- && this.level().noCollision(zombie) +- && !this.level().containsAnyLiquid(zombie.getBoundingBox())) { +- zombie.setTarget(target); +- zombie.finalizeSpawn( +- serverLevel, this.level().getCurrentDifficultyAt(zombie.blockPosition()), MobSpawnType.REINFORCEMENT, null, null +- ); +- serverLevel.addFreshEntityWithPassengers(zombie); +- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE) +- .addPermanentModifier(new AttributeModifier("Zombie reinforcement caller charge", -0.05F, AttributeModifier.Operation.ADDITION)); +- zombie.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE) +- .addPermanentModifier(new AttributeModifier("Zombie reinforcement callee charge", -0.05F, AttributeModifier.Operation.ADDITION)); ++ for (int l = 0; l < 50; ++l) { ++ int i1 = i + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1); ++ int j1 = j + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1); ++ int k1 = k + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1); ++ BlockPos blockposition = new BlockPos(i1, j1, k1); ++ EntityType<?> entitytypes = entityzombie.getType(); ++ SpawnPlacements.Surface entitypositiontypes_surface = SpawnPlacements.getPlacementType(entitytypes); ++ ++ if (NaturalSpawner.isSpawnPositionOk(entitypositiontypes_surface, this.level(), blockposition, entitytypes) && SpawnPlacements.checkSpawnRules(entitytypes, worldserver, EnumMobSpawn.REINFORCEMENT, blockposition, this.level().random)) { ++ entityzombie.setPos((double) i1, (double) j1, (double) k1); ++ if (!this.level().hasNearbyAlivePlayer((double) i1, (double) j1, (double) k1, 7.0D) && this.level().isUnobstructed(entityzombie) && this.level().noCollision((Entity) entityzombie) && !this.level().containsAnyLiquid(entityzombie.getBoundingBox())) { ++ entityzombie.setTarget(entityliving, EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET, true); // CraftBukkit ++ entityzombie.finalizeSpawn(worldserver, this.level().getCurrentDifficultyAt(entityzombie.blockPosition()), EnumMobSpawn.REINFORCEMENT, (GroupDataEntity) null, (CompoundTag) null); ++ worldserver.addFreshEntityWithPassengers(entityzombie, CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit ++ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).addPermanentModifier(new AttributeModifier("Zombie reinforcement caller charge", -0.05000000074505806D, AttributeModifier.Operation.ADDITION)); ++ entityzombie.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).addPermanentModifier(new AttributeModifier("Zombie reinforcement callee charge", -0.05000000074505806D, AttributeModifier.Operation.ADDITION)); + break; + } + } +@@ -330,10 +344,19 @@ + @Override + public boolean doHurtTarget(Entity entity) { + boolean flag = super.doHurtTarget(entity); ++ + if (flag) { +- float effectiveDifficulty = this.level().getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); +- if (this.getMainHandItem().isEmpty() && this.isOnFire() && this.random.nextFloat() < effectiveDifficulty * 0.3F) { +- entity.setSecondsOnFire(2 * (int)effectiveDifficulty); ++ float f = this.level().getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); ++ ++ if (this.getMainHandItem().isEmpty() && this.isOnFire() && this.random.nextFloat() < f * 0.3F) { ++ // CraftBukkit start ++ EntityCombustByEntityEvent event = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 2 * (int) f); // PAIL: fixme ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ entity.setSecondsOnFire(event.getDuration(), false); ++ } ++ // CraftBukkit end + } + } + +@@ -360,26 +383,28 @@ + } + + @Override +- protected void playStepSound(BlockPos pos, BlockState block) { ++ protected void playStepSound(BlockPos pos, IBlockData block) { + this.playSound(this.getStepSound(), 0.15F, 1.0F); + } + + @Override +- public MobType getMobType() { +- return MobType.UNDEAD; ++ public EnumMonsterType getMobType() { ++ return EnumMonsterType.UNDEAD; + } + + @Override + protected void populateDefaultEquipmentSlots(RandomSource random, DifficultyInstance difficulty) { + super.populateDefaultEquipmentSlots(random, difficulty); + if (random.nextFloat() < (this.level().getDifficulty() == Difficulty.HARD ? 0.05F : 0.01F)) { +- int randomInt = random.nextInt(3); +- if (randomInt == 0) { ++ int i = random.nextInt(3); ++ ++ if (i == 0) { + this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.IRON_SWORD)); + } else { + this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.IRON_SHOVEL)); + } + } ++ + } + + @Override +@@ -400,107 +425,124 @@ + if (compound.contains("DrownedConversionTime", 99) && compound.getInt("DrownedConversionTime") > -1) { + this.startUnderWaterConversion(compound.getInt("DrownedConversionTime")); + } ++ + } + + @Override + public boolean killedEntity(ServerLevel level, LivingEntity entity) { + boolean flag = super.killedEntity(level, entity); +- if ((level.getDifficulty() == Difficulty.NORMAL || level.getDifficulty() == Difficulty.HARD) && entity instanceof Villager villager) { ++ ++ if ((level.getDifficulty() == Difficulty.NORMAL || level.getDifficulty() == Difficulty.HARD) && entity instanceof Villager) { ++ Villager entityvillager = (Villager) entity; ++ + if (level.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { + return flag; + } ++ // CraftBukkit start ++ flag = zombifyVillager(level, entityvillager, this.blockPosition(), this.isSilent(), CreatureSpawnEvent.SpawnReason.INFECTION) == null; ++ } + +- ZombieVillager zombieVillager = villager.convertTo(EntityType.ZOMBIE_VILLAGER, false); +- if (zombieVillager != null) { +- zombieVillager.finalizeSpawn( +- level, level.getCurrentDifficultyAt(zombieVillager.blockPosition()), MobSpawnType.CONVERSION, new Zombie.ZombieGroupData(false, true), null +- ); +- zombieVillager.setVillagerData(villager.getVillagerData()); +- zombieVillager.setGossips(villager.getGossips().store(NbtOps.INSTANCE)); +- zombieVillager.setTradeOffers(villager.getOffers().createTag()); +- zombieVillager.setVillagerXp(villager.getVillagerXp()); +- if (!this.isSilent()) { +- level.levelEvent(null, 1026, this.blockPosition(), 0); ++ return flag; ++ } ++ ++ public static ZombieVillager zombifyVillager(ServerLevel worldserver, Villager entityvillager, net.minecraft.core.BlockPos blockPosition, boolean silent, CreatureSpawnEvent.SpawnReason spawnReason) { ++ { ++ ZombieVillager entityzombievillager = (ZombieVillager) entityvillager.convertTo(EntityType.ZOMBIE_VILLAGER, false, EntityTransformEvent.TransformReason.INFECTION, spawnReason); ++ // CraftBukkit end ++ ++ if (entityzombievillager != null) { ++ entityzombievillager.finalizeSpawn(worldserver, worldserver.getCurrentDifficultyAt(entityzombievillager.blockPosition()), EnumMobSpawn.CONVERSION, new Zombie.ZombieGroupData(false, true), (CompoundTag) null); ++ entityzombievillager.setVillagerData(entityvillager.getVillagerData()); ++ entityzombievillager.setGossips((Tag) entityvillager.getGossips().store(NbtOps.INSTANCE)); ++ entityzombievillager.setTradeOffers(entityvillager.getOffers().createTag()); ++ entityzombievillager.setVillagerXp(entityvillager.getVillagerXp()); ++ // CraftBukkit start ++ if (!silent) { ++ worldserver.levelEvent((Player) null, 1026, blockPosition, 0); + } + +- flag = false; ++ // flag = false; + } +- } + +- return flag; ++ return entityzombievillager; ++ } ++ // CraftBukkit end + } + + @Override +- protected float getStandingEyeHeight(Pose pose, EntityDimensions size) { ++ protected float getStandingEyeHeight(EntityPose pose, EntityDimensions size) { + return this.isBaby() ? 0.93F : 1.74F; + } + + @Override + public boolean canHoldItem(ItemStack stack) { +- return (!stack.is(Items.EGG) || !this.isBaby() || !this.isPassenger()) && super.canHoldItem(stack); ++ return stack.is(Items.EGG) && this.isBaby() && this.isPassenger() ? false : super.canHoldItem(stack); + } + + @Override + public boolean wantsToPickUp(ItemStack stack) { +- return !stack.is(Items.GLOW_INK_SAC) && super.wantsToPickUp(stack); ++ return stack.is(Items.GLOW_INK_SAC) ? false : super.wantsToPickUp(stack); + } + + @Nullable + @Override +- public SpawnGroupData finalizeSpawn( +- ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType reason, @Nullable SpawnGroupData spawnData, @Nullable CompoundTag dataTag +- ) { +- RandomSource random = level.getRandom(); +- SpawnGroupData var11 = super.finalizeSpawn(level, difficulty, reason, spawnData, dataTag); +- float specialMultiplier = difficulty.getSpecialMultiplier(); +- this.setCanPickUpLoot(random.nextFloat() < 0.55F * specialMultiplier); +- if (var11 == null) { +- var11 = new Zombie.ZombieGroupData(getSpawnAsBabyOdds(random), true); ++ public GroupDataEntity finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, EnumMobSpawn reason, @Nullable GroupDataEntity spawnData, @Nullable CompoundTag dataTag) { ++ RandomSource randomsource = level.getRandom(); ++ Object object = super.finalizeSpawn(level, difficulty, reason, spawnData, dataTag); ++ float f = difficulty.getSpecialMultiplier(); ++ ++ this.setCanPickUpLoot(randomsource.nextFloat() < 0.55F * f); ++ if (object == null) { ++ object = new Zombie.ZombieGroupData(getSpawnAsBabyOdds(randomsource), true); + } + +- if (var11 instanceof Zombie.ZombieGroupData zombieGroupData) { +- if (zombieGroupData.isBaby) { ++ if (object instanceof Zombie.ZombieGroupData) { ++ Zombie.ZombieGroupData entityzombie_groupdatazombie = (Zombie.ZombieGroupData) object; ++ ++ if (entityzombie_groupdatazombie.isBaby) { + this.setBaby(true); +- if (zombieGroupData.canSpawnJockey) { +- if ((double)random.nextFloat() < 0.05) { +- List<Chicken> entitiesOfClass = level.getEntitiesOfClass( +- Chicken.class, this.getBoundingBox().inflate(5.0, 3.0, 5.0), EntitySelector.ENTITY_NOT_BEING_RIDDEN +- ); +- if (!entitiesOfClass.isEmpty()) { +- Chicken chicken = entitiesOfClass.get(0); +- chicken.setChickenJockey(true); +- this.startRiding(chicken); ++ if (entityzombie_groupdatazombie.canSpawnJockey) { ++ if ((double) randomsource.nextFloat() < 0.05D) { ++ List<Chicken> list = level.getEntitiesOfClass(Chicken.class, this.getBoundingBox().inflate(5.0D, 3.0D, 5.0D), EntitySelector.ENTITY_NOT_BEING_RIDDEN); ++ ++ if (!list.isEmpty()) { ++ Chicken entitychicken = (Chicken) list.get(0); ++ ++ entitychicken.setChickenJockey(true); ++ this.startRiding(entitychicken); + } +- } else if ((double)random.nextFloat() < 0.05) { +- Chicken chicken1 = EntityType.CHICKEN.create(this.level()); +- if (chicken1 != null) { +- chicken1.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F); +- chicken1.finalizeSpawn(level, difficulty, MobSpawnType.JOCKEY, null, null); +- chicken1.setChickenJockey(true); +- this.startRiding(chicken1); +- level.addFreshEntity(chicken1); ++ } else if ((double) randomsource.nextFloat() < 0.05D) { ++ Chicken entitychicken1 = (Chicken) EntityType.CHICKEN.create(this.level()); ++ ++ if (entitychicken1 != null) { ++ entitychicken1.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F); ++ entitychicken1.finalizeSpawn(level, difficulty, EnumMobSpawn.JOCKEY, (GroupDataEntity) null, (CompoundTag) null); ++ entitychicken1.setChickenJockey(true); ++ this.startRiding(entitychicken1); ++ level.addFreshEntity(entitychicken1, CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit + } + } + } + } + +- this.setCanBreakDoors(this.supportsBreakDoorGoal() && random.nextFloat() < specialMultiplier * 0.1F); +- this.populateDefaultEquipmentSlots(random, difficulty); +- this.populateDefaultEquipmentEnchantments(random, difficulty); ++ this.setCanBreakDoors(this.supportsBreakDoorGoal() && randomsource.nextFloat() < f * 0.1F); ++ this.populateDefaultEquipmentSlots(randomsource, difficulty); ++ this.populateDefaultEquipmentEnchantments(randomsource, difficulty); + } + + if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { +- LocalDate localDate = LocalDate.now(); +- int i = localDate.get(ChronoField.DAY_OF_MONTH); +- int i1 = localDate.get(ChronoField.MONTH_OF_YEAR); +- if (i1 == 10 && i == 31 && random.nextFloat() < 0.25F) { +- this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); ++ LocalDate localdate = LocalDate.now(); ++ int i = localdate.get(ChronoField.DAY_OF_MONTH); ++ int j = localdate.get(ChronoField.MONTH_OF_YEAR); ++ ++ if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) { ++ this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); + this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; + } + } + +- this.handleAttributes(specialMultiplier); +- return (SpawnGroupData)var11; ++ this.handleAttributes(f); ++ return (GroupDataEntity) object; + } + + public static boolean getSpawnAsBabyOdds(RandomSource random) { +@@ -509,32 +551,28 @@ + + protected void handleAttributes(float difficulty) { + this.randomizeReinforcementsChance(); +- this.getAttribute(Attributes.KNOCKBACK_RESISTANCE) +- .addPermanentModifier(new AttributeModifier("Random spawn bonus", this.random.nextDouble() * 0.05F, AttributeModifier.Operation.ADDITION)); +- double d = this.random.nextDouble() * 1.5 * (double)difficulty; +- if (d > 1.0) { +- this.getAttribute(Attributes.FOLLOW_RANGE) +- .addPermanentModifier(new AttributeModifier("Random zombie-spawn bonus", d, AttributeModifier.Operation.MULTIPLY_TOTAL)); ++ this.getAttribute(Attributes.KNOCKBACK_RESISTANCE).addPermanentModifier(new AttributeModifier("Random spawn bonus", this.random.nextDouble() * 0.05000000074505806D, AttributeModifier.Operation.ADDITION)); ++ double d0 = this.random.nextDouble() * 1.5D * (double) difficulty; ++ ++ if (d0 > 1.0D) { ++ this.getAttribute(Attributes.FOLLOW_RANGE).addPermanentModifier(new AttributeModifier("Random zombie-spawn bonus", d0, AttributeModifier.Operation.MULTIPLY_TOTAL)); + } + + if (this.random.nextFloat() < difficulty * 0.05F) { +- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE) +- .addPermanentModifier(new AttributeModifier("Leader zombie bonus", this.random.nextDouble() * 0.25 + 0.5, AttributeModifier.Operation.ADDITION)); +- this.getAttribute(Attributes.MAX_HEALTH) +- .addPermanentModifier( +- new AttributeModifier("Leader zombie bonus", this.random.nextDouble() * 3.0 + 1.0, AttributeModifier.Operation.MULTIPLY_TOTAL) +- ); ++ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).addPermanentModifier(new AttributeModifier("Leader zombie bonus", this.random.nextDouble() * 0.25D + 0.5D, AttributeModifier.Operation.ADDITION)); ++ this.getAttribute(Attributes.MAX_HEALTH).addPermanentModifier(new AttributeModifier("Leader zombie bonus", this.random.nextDouble() * 3.0D + 1.0D, AttributeModifier.Operation.MULTIPLY_TOTAL)); + this.setCanBreakDoors(this.supportsBreakDoorGoal()); + } ++ + } + + protected void randomizeReinforcementsChance() { +- this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * 0.1F); ++ this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * 0.10000000149011612D); + } + + @Override +- protected Vector3f getPassengerAttachmentPoint(Entity entity, EntityDimensions entityDimensions, float f) { +- return new Vector3f(0.0F, entityDimensions.height + 0.0625F * f, 0.0F); ++ protected Vector3f getPassengerAttachmentPoint(Entity entity, EntityDimensions entitysize, float f) { ++ return new Vector3f(0.0F, entitysize.height + 0.0625F * f, 0.0F); + } + + @Override +@@ -545,41 +583,51 @@ + @Override + protected void dropCustomDeathLoot(DamageSource source, int looting, boolean recentlyHit) { + super.dropCustomDeathLoot(source, looting, recentlyHit); +- if (source.getEntity() instanceof Creeper creeper && creeper.canDropMobsSkull()) { +- ItemStack skull = this.getSkull(); +- if (!skull.isEmpty()) { +- creeper.increaseDroppedSkulls(); +- this.spawnAtLocation(skull); ++ Entity entity = source.getEntity(); ++ ++ if (entity instanceof Creeper) { ++ Creeper entitycreeper = (Creeper) entity; ++ ++ if (entitycreeper.canDropMobsSkull()) { ++ ItemStack itemstack = this.getSkull(); ++ ++ if (!itemstack.isEmpty()) { ++ entitycreeper.increaseDroppedSkulls(); ++ this.spawnAtLocation(itemstack); ++ } + } + } ++ + } + + protected ItemStack getSkull() { + return new ItemStack(Items.ZOMBIE_HEAD); + } + +- class ZombieAttackTurtleEggGoal extends RemoveBlockGoal { +- ZombieAttackTurtleEggGoal(PathfinderMob mob, double speedModifier, int verticalSearchRange) { +- super(Blocks.TURTLE_EGG, mob, speedModifier, verticalSearchRange); ++ private class ZombieAttackTurtleEggGoal extends RemoveBlockGoal { ++ ++ ZombieAttackTurtleEggGoal(PathfinderMob mob, double speedModifier, int i) { ++ super(Blocks.TURTLE_EGG, mob, speedModifier, i); + } + + @Override + public void playDestroyProgressSound(LevelAccessor level, BlockPos pos) { +- level.playSound(null, pos, SoundEvents.ZOMBIE_DESTROY_EGG, SoundSource.HOSTILE, 0.5F, 0.9F + Zombie.this.random.nextFloat() * 0.2F); ++ level.playSound((Player) null, pos, SoundEvents.ZOMBIE_DESTROY_EGG, SoundSource.HOSTILE, 0.5F, 0.9F + Zombie.this.random.nextFloat() * 0.2F); + } + + @Override + public void playBreakSound(Level level, BlockPos pos) { +- level.playSound(null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7F, 0.9F + level.random.nextFloat() * 0.2F); ++ level.playSound((Player) null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7F, 0.9F + level.random.nextFloat() * 0.2F); + } + + @Override + public double acceptedDistance() { +- return 1.14; ++ return 1.14D; + } + } + +- public static class ZombieGroupData implements SpawnGroupData { ++ public static class ZombieGroupData implements GroupDataEntity { ++ + public final boolean isBaby; + public final boolean canSpawnJockey; + |