From a8074a4dd50793efad538be4a9ce25696247966d Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 16:00:39 +0100 Subject: [PATCH 01/26] Ambient entity patches --- .../world/entity/ambient/Bat.java.patch | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 patches/minecraft/net/minecraft/world/entity/ambient/Bat.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/ambient/Bat.java.patch b/patches/minecraft/net/minecraft/world/entity/ambient/Bat.java.patch new file mode 100644 index 0000000000..8acb0a0663 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/ambient/Bat.java.patch @@ -0,0 +1,37 @@ +--- a/net/minecraft/world/entity/ambient/Bat.java ++++ b/net/minecraft/world/entity/ambient/Bat.java +@@ -27,6 +_,7 @@ + import net.minecraft.world.level.LevelAccessor; + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; + + public class Bat extends AmbientCreature { + public static final float FLAP_DEGREES_PER_TICK = 74.48451F; +@@ -125,7 +_,7 @@ + this.yHeadRot = (float)this.random.nextInt(360); + } + +- if (this.level().getNearestPlayer(BAT_RESTING_TARGETING, this) != null) { ++ if (this.level().getNearestPlayer(Bat.BAT_RESTING_TARGETING, this) != null && CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent + this.setResting(false); + if (!flag) { + this.level().levelEvent((Player)null, 1025, blockpos, 0); +@@ -156,7 +_,7 @@ + float f1 = Mth.wrapDegrees(f - this.getYRot()); + this.zza = 0.5F; + this.setYRot(this.getYRot() + f1); +- if (this.random.nextInt(100) == 0 && this.level().getBlockState(blockpos1).isRedstoneConductor(this.level(), blockpos1)) { ++ if (this.random.nextInt(100) == 0 && this.level().getBlockState(blockpos1).isRedstoneConductor(this.level(), blockpos1) && CraftEventFactory.handleBatToggleSleepEvent(this, false)) { // CraftBukkit - Call BatToggleSleepEvent + this.setResting(true); + } + } +@@ -178,7 +_,7 @@ + if (this.isInvulnerableTo(p_27424_)) { + return false; + } else { +- if (!this.level().isClientSide && this.isResting()) { ++ if (!this.level().isClientSide && this.isResting() && CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent + this.setResting(false); + } + From 21c2b0df15f65d088d114f76973436565a573608 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 16:16:22 +0100 Subject: [PATCH 02/26] Raid entity patches --- .../world/entity/raid/Raid.java.patch | 136 ++++++++++++++++++ .../world/entity/raid/Raider.java.patch | 29 ++++ .../world/entity/raid/Raids.java.patch | 30 ++++ 3 files changed, 195 insertions(+) create mode 100644 patches/minecraft/net/minecraft/world/entity/raid/Raider.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/raid/Raids.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/raid/Raid.java.patch b/patches/minecraft/net/minecraft/world/entity/raid/Raid.java.patch index 17c1b30834..f086b959a5 100644 --- a/patches/minecraft/net/minecraft/world/entity/raid/Raid.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/raid/Raid.java.patch @@ -1,5 +1,141 @@ --- a/net/minecraft/world/entity/raid/Raid.java +++ b/net/minecraft/world/entity/raid/Raid.java +@@ -162,6 +_,12 @@ + return this.status == Raid.RaidStatus.LOSS; + } + ++ // CraftBukkit start ++ public boolean isInProgress() { ++ return this.status == RaidStatus.ONGOING; ++ } ++ // CraftBukkit end ++ + public float getTotalHealth() { + return this.totalHealth; + } +@@ -246,6 +_,7 @@ + boolean flag = this.active; + this.active = this.level.hasChunkAt(this.center); + if (this.level.getDifficulty() == Difficulty.PEACEFUL) { ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.PEACE); // CraftBukkit + this.stop(); + return; + } +@@ -265,13 +_,16 @@ + if (!this.level.isVillage(this.center)) { + if (this.groupsSpawned > 0) { + this.status = Raid.RaidStatus.LOSS; ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callRaidFinishEvent(this, new java.util.ArrayList<>()); // CraftBukkit + } else { ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.NOT_IN_VILLAGE); // CraftBukkit + this.stop(); + } + } + + ++this.ticksActive; + if (this.ticksActive >= 48000L) { ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.TIMEOUT); // CraftBukkit + this.stop(); + return; + } +@@ -342,6 +_,7 @@ + } + + if (k > 3) { ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.UNSPAWNABLE); // CraftBukkit + this.stop(); + break; + } +@@ -353,6 +_,7 @@ + } else { + this.status = Raid.RaidStatus.VICTORY; + ++ List winners = new java.util.ArrayList<>(); // CraftBukkit + for(UUID uuid : this.heroesOfTheVillage) { + Entity entity = this.level.getEntity(uuid); + if (entity instanceof LivingEntity) { +@@ -363,10 +_,12 @@ + ServerPlayer serverplayer = (ServerPlayer)livingentity; + serverplayer.awardStat(Stats.RAID_WIN); + CriteriaTriggers.RAID_WIN.trigger(serverplayer); ++ winners.add(serverplayer.getBukkitEntity()); // CraftBukkit + } + } + } + } ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callRaidFinishEvent(this, winners); // CraftBukkit + } + } + +@@ -374,6 +_,7 @@ + } else if (this.isOver()) { + ++this.celebrationTicks; + if (this.celebrationTicks >= 600) { ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callRaidStopEvent(this, org.bukkit.event.raid.RaidStopEvent.Reason.FINISHED); // CraftBukkit + this.stop(); + return; + } +@@ -496,6 +_,10 @@ + DifficultyInstance difficultyinstance = this.level.getCurrentDifficultyAt(p_37756_); + boolean flag1 = this.shouldSpawnBonusGroup(); + ++ // CraftBukkit start ++ Raider leader = null; ++ List raiders = new java.util.ArrayList<>(); ++ // CraftBukkit end + for(Raid.RaiderType raid$raidertype : Raid.RaiderType.VALUES) { + int j = this.getDefaultNumSpawns(raid$raidertype, i, flag1) + this.getPotentialBonusSpawns(raid$raidertype, this.random, i, difficultyinstance, flag1); + int k = 0; +@@ -510,9 +_,11 @@ + raider.setPatrolLeader(true); + this.setLeader(i, raider); + flag = true; ++ leader = raider; // CraftBukkit + } + + this.joinRaid(i, raider, p_37756_, false); ++ raiders.add(raider); // CraftBukkit + if (raid$raidertype.entityType == EntityType.RAVAGER) { + Raider raider1 = null; + if (i == this.getNumGroups(Difficulty.NORMAL)) { +@@ -530,6 +_,7 @@ + this.joinRaid(i, raider1, p_37756_, false); + raider1.moveTo(p_37756_, 0.0F, 0.0F); + raider1.startRiding(raider); ++ raiders.add(raider); // CraftBukkit + } + } + } +@@ -539,6 +_,7 @@ + ++this.groupsSpawned; + this.updateBossbar(); + this.setDirty(); ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callRaidSpawnWaveEvent(this, leader, raiders); // CraftBukkit + } + + public void joinRaid(int p_37714_, Raider p_37715_, @Nullable BlockPos p_37716_, boolean p_37717_) { +@@ -553,7 +_,7 @@ + p_37715_.finalizeSpawn(this.level, this.level.getCurrentDifficultyAt(p_37716_), MobSpawnType.EVENT, (SpawnGroupData)null, (CompoundTag)null); + p_37715_.applyRaidBuffs(p_37714_, false); + p_37715_.setOnGround(true); +- this.level.addFreshEntityWithPassengers(p_37715_); ++ this.level.addFreshEntityWithPassengers(p_37715_, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.RAID); // CraftBukkit + } + } + +@@ -793,6 +_,12 @@ + this.heroesOfTheVillage.add(p_37727_.getUUID()); + } + ++ // CraftBukkit start - a method to get all raiders ++ public java.util.Collection getRaiders() { ++ return this.groupRaiderMap.values().stream().flatMap(Set::stream).collect(java.util.stream.Collectors.toSet()); ++ } ++ // CraftBukkit end ++ + static enum RaidStatus { + ONGOING, + VICTORY, @@ -816,7 +_,7 @@ } } diff --git a/patches/minecraft/net/minecraft/world/entity/raid/Raider.java.patch b/patches/minecraft/net/minecraft/world/entity/raid/Raider.java.patch new file mode 100644 index 0000000000..5cad4f7751 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/raid/Raider.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/world/entity/raid/Raider.java ++++ b/net/minecraft/world/entity/raid/Raider.java +@@ -149,7 +_,7 @@ + i = Mth.clamp(i, 0, 4); + MobEffectInstance mobeffectinstance = new MobEffectInstance(MobEffects.BAD_OMEN, 120000, i, false, false, true); + if (!this.level().getGameRules().getBoolean(GameRules.RULE_DISABLE_RAIDS)) { +- player.addEffect(mobeffectinstance); ++ player.addEffect(mobeffectinstance, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN); // CraftBukkit + } + } + } +@@ -296,7 +_,7 @@ + this.mob.getNavigation().stop(); + + for(Raider raider : this.mob.level().getNearbyEntities(Raider.class, this.shoutTargeting, this.mob, this.mob.getBoundingBox().inflate(8.0D, 8.0D, 8.0D))) { +- raider.setTarget(this.mob.getTarget()); ++ raider.setTarget(this.mob.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.FOLLOW_LEADER, true); // CraftBukkit + } + + } +@@ -306,7 +_,7 @@ + LivingEntity livingentity = this.mob.getTarget(); + if (livingentity != null) { + for(Raider raider : this.mob.level().getNearbyEntities(Raider.class, this.shoutTargeting, this.mob, this.mob.getBoundingBox().inflate(8.0D, 8.0D, 8.0D))) { +- raider.setTarget(livingentity); ++ raider.setTarget(this.mob.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.FOLLOW_LEADER, true); // CraftBukkit + raider.setAggressive(true); + } + diff --git a/patches/minecraft/net/minecraft/world/entity/raid/Raids.java.patch b/patches/minecraft/net/minecraft/world/entity/raid/Raids.java.patch new file mode 100644 index 0000000000..373423cf5e --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/raid/Raids.java.patch @@ -0,0 +1,30 @@ +--- a/net/minecraft/world/entity/raid/Raids.java ++++ b/net/minecraft/world/entity/raid/Raids.java +@@ -124,14 +_,26 @@ + } + + flag = true; +- } else if (raid.getBadOmenLevel() < raid.getMaxBadOmenLevel()) { ++ // CraftBukkit start - fixed a bug with raid: players could add up Bad Omen level even when the raid had finished ++ } else if (raid.isInProgress() && raid.getBadOmenLevel() < raid.getMaxBadOmenLevel()) { + flag = true; ++ // CraftBukkit end + } else { + p_37964_.removeEffect(MobEffects.BAD_OMEN); + p_37964_.connection.send(new ClientboundEntityEventPacket(p_37964_, (byte)43)); + } + + if (flag) { ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callRaidTriggerEvent(raid, p_37964_)) { ++ p_37964_.removeEffect(MobEffects.BAD_OMEN); ++ return null; ++ } ++ ++ if (!this.raidMap.containsKey(raid.getId())) { ++ this.raidMap.put(raid.getId(), raid); ++ } ++ // CraftBukkit end + raid.absorbBadOmen(p_37964_); + p_37964_.connection.send(new ClientboundEntityEventPacket(p_37964_, (byte)43)); + if (!raid.hasFirstWaveSpawned()) { From 2067f3bd9e82809e2addc6f3c28fbba308124f16 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 17:41:35 +0100 Subject: [PATCH 03/26] Projectile entity patches --- .../projectile/AbstractArrow.java.patch | 59 +++++- .../AbstractHurtingProjectile.java.patch | 39 +++- .../world/entity/projectile/Arrow.java.patch | 17 ++ .../entity/projectile/EvokerFangs.java.patch | 21 ++ .../entity/projectile/EyeOfEnder.java.patch | 20 ++ .../entity/projectile/Fireball.java.patch | 10 + .../FireworkRocketEntity.java.patch | 85 +++++++- .../entity/projectile/FishingHook.java.patch | 148 ++++++++++++- .../projectile/LargeFireball.java.patch | 32 ++- .../entity/projectile/LlamaSpit.java.patch | 6 +- .../entity/projectile/Projectile.java.patch | 56 +++++ .../projectile/ShulkerBullet.java.patch | 49 ++++- .../projectile/SmallFireball.java.patch | 33 ++- .../projectile/SpectralArrow.java.patch | 11 + .../ThrowableItemProjectile.java.patch | 14 ++ .../projectile/ThrowableProjectile.java.patch | 6 +- .../entity/projectile/ThrownEgg.java.patch | 74 +++++++ .../projectile/ThrownEnderpearl.java.patch | 70 +++++-- .../ThrownExperienceBottle.java.patch | 22 ++ .../entity/projectile/ThrownPotion.java.patch | 197 ++++++++++++++++++ .../projectile/ThrownTrident.java.patch | 9 + .../entity/projectile/WitherSkull.java.patch | 43 ++++ 22 files changed, 986 insertions(+), 35 deletions(-) create mode 100644 patches/minecraft/net/minecraft/world/entity/projectile/Arrow.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/projectile/EvokerFangs.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/projectile/Fireball.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/projectile/SpectralArrow.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/projectile/ThrownEgg.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/projectile/ThrownPotion.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/AbstractArrow.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/AbstractArrow.java.patch index 6aeac6d13e..8c82830eca 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/AbstractArrow.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/AbstractArrow.java.patch @@ -1,5 +1,22 @@ --- a/net/minecraft/world/entity/projectile/AbstractArrow.java +++ b/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -29,6 +_,7 @@ + import net.minecraft.world.entity.MoverType; + import net.minecraft.world.entity.Pose; + import net.minecraft.world.entity.ai.attributes.Attributes; ++import net.minecraft.world.entity.item.ItemEntity; + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.enchantment.EnchantmentHelper; +@@ -43,6 +_,8 @@ + import net.minecraft.world.phys.HitResult; + import net.minecraft.world.phys.Vec3; + import net.minecraft.world.phys.shapes.VoxelShape; ++import org.bukkit.event.entity.EntityCombustByEntityEvent; ++import org.bukkit.event.player.PlayerPickupArrowEvent; + + public abstract class AbstractArrow extends Projectile { + private static final double ARROW_BASE_DAMAGE = 2.0D; @@ -66,6 +_,8 @@ @Nullable private List piercedAndKilledEntities; @@ -29,7 +46,7 @@ + switch (net.minecraftforge.event.ForgeEventFactory.onProjectileImpactResult(this, hitresult)) { + case SKIP_ENTITY: + if (hitresult.getType() != HitResult.Type.ENTITY) { // If there is no entity, we just return default behaviour -+ this.onHit(hitresult); ++ this.preOnHit(hitresult); // CraftBukkit - projectile hit event + this.hasImpulse = true; + break; + } @@ -60,6 +77,22 @@ vec3 = this.getDeltaMovement(); double d5 = vec3.x; double d6 = vec3.y; +@@ -322,7 +_,14 @@ + boolean flag = entity.getType() == EntityType.ENDERMAN; + int k = entity.getRemainingFireTicks(); + if (this.isOnFire() && !flag) { +- entity.setSecondsOnFire(5); ++ // CraftBukkit start ++ EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 5); ++ org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent); ++ if (!combustEvent.isCancelled()) { ++ entity.setSecondsOnFire(combustEvent.getDuration(), false); ++ } ++ // CraftBukkit end ++ + } + + if (entity.hurt(damagesource, (float)i)) { @@ -422,7 +_,7 @@ } @@ -69,3 +102,27 @@ } public void addAdditionalSaveData(CompoundTag p_36772_) { +@@ -475,7 +_,22 @@ + + public void playerTouch(Player p_36766_) { + if (!this.level().isClientSide && (this.inGround || this.isNoPhysics()) && this.shakeTime <= 0) { +- if (this.tryPickup(p_36766_)) { ++ // CraftBukkit start ++ ItemStack itemstack = this.getPickupItem(); ++ if (this.pickup == AbstractArrow.Pickup.ALLOWED && !itemstack.isEmpty() && p_36766_.getInventory().canHold(itemstack) > 0) { ++ ItemEntity item = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack); ++ PlayerPickupArrowEvent event = new PlayerPickupArrowEvent((org.bukkit.entity.Player) p_36766_.getBukkitEntity(), new org.bukkit.craftbukkit.v1_20_R2.entity.CraftItem(this.level().getCraftServer(), item), (org.bukkit.entity.AbstractArrow) this.getBukkitEntity()); ++ // event.setCancelled(!entityhuman.canPickUpLoot); TODO ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ itemstack = item.getItem(); ++ } ++ ++ if ((this.pickup == AbstractArrow.Pickup.ALLOWED && p_36766_.getInventory().add(itemstack)) || (this.pickup == AbstractArrow.Pickup.CREATIVE_ONLY && p_36766_.getAbilities().instabuild)) { ++ // CraftBukkit end + p_36766_.take(this, 1); + this.discard(); + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch index 6808d3f68e..a11ed6c32c 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java.patch @@ -1,11 +1,46 @@ --- a/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java +++ b/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java -@@ -65,7 +_,7 @@ +@@ -14,11 +_,14 @@ + import net.minecraft.world.level.Level; + import net.minecraft.world.phys.HitResult; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; + + public abstract class AbstractHurtingProjectile extends Projectile { + public double xPower; + public double yPower; + public double zPower; ++ public float bukkitYield = 1; // CraftBukkit ++ public boolean isIncendiary = true; // CraftBukkit + + protected AbstractHurtingProjectile(EntityType p_36833_, Level p_36834_) { + super(p_36833_, p_36834_); +@@ -65,8 +_,14 @@ } HitResult hitresult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); - if (hitresult.getType() != HitResult.Type.MISS) { +- this.onHit(hitresult); + if (hitresult.getType() != HitResult.Type.MISS && !net.minecraftforge.event.ForgeEventFactory.onProjectileImpact(this, hitresult)) { - this.onHit(hitresult); ++ this.preOnHit(hitresult); // CraftBukkit - projectile hit event ++ ++ // CraftBukkit start - Fire ProjectileHitEvent ++ if (this.isRemoved()) { ++ CraftEventFactory.callProjectileHitEvent(this, hitresult); ++ } ++ // CraftBukkit end } + this.checkInsideBlocks(); +@@ -143,6 +_,11 @@ + Entity entity = p_36839_.getEntity(); + if (entity != null) { + if (!this.level().isClientSide) { ++ // CraftBukkit start ++ if (CraftEventFactory.handleNonLivingEntityDamageEvent(this, p_36839_, p_36840_, false)) { ++ return false; ++ } ++ // CraftBukkit end + Vec3 vec3 = entity.getLookAngle(); + this.setDeltaMovement(vec3); + this.xPower = vec3.x * 0.1D; diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/Arrow.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/Arrow.java.patch new file mode 100644 index 0000000000..9935c21c8d --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/projectile/Arrow.java.patch @@ -0,0 +1,17 @@ +--- a/net/minecraft/world/entity/projectile/Arrow.java ++++ b/net/minecraft/world/entity/projectile/Arrow.java +@@ -180,12 +_,12 @@ + for(MobEffectInstance mobeffectinstance : this.potion.getEffects()) { + p_36873_.addEffect(new MobEffectInstance(mobeffectinstance.getEffect(), Math.max(mobeffectinstance.mapDuration((p_268168_) -> { + return p_268168_ / 8; +- }), 1), mobeffectinstance.getAmplifier(), mobeffectinstance.isAmbient(), mobeffectinstance.isVisible()), entity); ++ }), 1), mobeffectinstance.getAmplifier(), mobeffectinstance.isAmbient(), mobeffectinstance.isVisible()), entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit + } + + if (!this.effects.isEmpty()) { + for(MobEffectInstance mobeffectinstance1 : this.effects) { +- p_36873_.addEffect(mobeffectinstance1, entity); ++ p_36873_.addEffect(mobeffectinstance1, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit + } + } + diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/EvokerFangs.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/EvokerFangs.java.patch new file mode 100644 index 0000000000..203b5f95ef --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/projectile/EvokerFangs.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/world/entity/projectile/EvokerFangs.java ++++ b/net/minecraft/world/entity/projectile/EvokerFangs.java +@@ -16,7 +_,7 @@ + public static final int ATTACK_DURATION = 20; + public static final int LIFE_OFFSET = 2; + public static final int ATTACK_TRIGGER_TICKS = 14; +- private int warmupDelayTicks; ++ public int warmupDelayTicks; + private boolean sentSpikeEvent; + private int lifeTicks = 22; + private boolean clientSideAttackStarted; +@@ -113,7 +_,9 @@ + LivingEntity livingentity = this.getOwner(); + if (p_36945_.isAlive() && !p_36945_.isInvulnerable() && p_36945_ != livingentity) { + if (livingentity == null) { ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.entityDamage = this; // CraftBukkit + p_36945_.hurt(this.damageSources().magic(), 6.0F); ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.entityDamage = null; // CraftBukkit + } else { + if (livingentity.isAlliedTo(p_36945_)) { + return; diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch new file mode 100644 index 0000000000..c151b7d82e --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/projectile/EyeOfEnder.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/entity/projectile/EyeOfEnder.java ++++ b/net/minecraft/world/entity/projectile/EyeOfEnder.java +@@ -34,7 +_,7 @@ + } + + public void setItem(ItemStack p_36973_) { +- if (!p_36973_.is(Items.ENDER_EYE) || p_36973_.hasTag()) { ++ if (true || !p_36973_.is(Items.ENDER_EYE) || p_36973_.hasTag()) { // CraftBukkit - always allow item changing + this.getEntityData().set(DATA_ITEM_STACK, p_36973_.copyWithCount(1)); + } + +@@ -159,7 +_,7 @@ + + public void readAdditionalSaveData(CompoundTag p_36970_) { + ItemStack itemstack = ItemStack.of(p_36970_.getCompound("Item")); +- this.setItem(itemstack); ++ if (!itemstack.isEmpty()) this.setItem(itemstack); // CraftBukkit - SPIGOT-6103 summon, see also SPIGOT-5474 + } + + public float getLightLevelDependentMagicValue() { diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/Fireball.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/Fireball.java.patch new file mode 100644 index 0000000000..21914d995e --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/projectile/Fireball.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/entity/projectile/Fireball.java ++++ b/net/minecraft/world/entity/projectile/Fireball.java +@@ -57,6 +_,6 @@ + public void readAdditionalSaveData(CompoundTag p_37009_) { + super.readAdditionalSaveData(p_37009_); + ItemStack itemstack = ItemStack.of(p_37009_.getCompound("Item")); +- this.setItem(itemstack); ++ if (!itemstack.isEmpty()) this.setItem(itemstack); // CraftBukkit - SPIGOT-5474 probably came from bugged earlier versions + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch index d781853954..d174304739 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch @@ -1,16 +1,89 @@ --- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java +++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -@@ -150,6 +_,13 @@ +@@ -25,6 +_,7 @@ + import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; - } + public class FireworkRocketEntity extends Projectile implements ItemSupplier { + private static final EntityDataAccessor DATA_ID_FIREWORKS_ITEM = SynchedEntityData.defineId(FireworkRocketEntity.class, EntityDataSerializers.ITEM_STACK); +@@ -130,7 +_,7 @@ + + HitResult hitresult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); + if (!this.noPhysics) { +- this.onHit(hitresult); ++ this.preOnHit(hitresult); + this.hasImpulse = true; + } + +@@ -145,9 +_,20 @@ + } + if (!this.level().isClientSide && this.life > this.lifetime) { +- this.explode(); +- } +- ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { ++ this.explode(); ++ } ++ // CraftBukkit end ++ } ++ ++ } ++ + @Override + protected void onHit(HitResult result) { + if (result.getType() == HitResult.Type.MISS || !net.minecraftforge.event.ForgeEventFactory.onProjectileImpact(this, result)) { + super.onHit(result); + } -+ } -+ + } + private void explode() { - this.level().broadcastEntityEvent(this, (byte)17); - this.gameEvent(GameEvent.EXPLODE, this.getOwner()); +@@ -160,7 +_,11 @@ + protected void onHitEntity(EntityHitResult p_37071_) { + super.onHitEntity(p_37071_); + if (!this.level().isClientSide) { +- this.explode(); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { ++ this.explode(); ++ } ++ // CraftBukkit end + } + } + +@@ -168,7 +_,11 @@ + BlockPos blockpos = new BlockPos(p_37069_.getBlockPos()); + this.level().getBlockState(blockpos).entityInside(this.level(), blockpos, this); + if (!this.level().isClientSide() && this.hasExplosion()) { +- this.explode(); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) { ++ this.explode(); ++ } ++ // CraftBukkit end + } + + super.onHitBlock(p_37069_); +@@ -192,7 +_,9 @@ + + if (f > 0.0F) { + if (this.attachedToEntity != null) { ++ CraftEventFactory.entityDamage = this; // CraftBukkit + this.attachedToEntity.hurt(this.damageSources().fireworks(this, this.getOwner()), 5.0F + (float)(listtag.size() * 2)); ++ CraftEventFactory.entityDamage = null; // CraftBukkit + } + + double d0 = 5.0D; +@@ -213,7 +_,9 @@ + + if (flag) { + float f1 = f * (float)Math.sqrt((5.0D - (double)this.distanceTo(livingentity)) / 5.0D); ++ CraftEventFactory.entityDamage = this; // CraftBukkit + livingentity.hurt(this.damageSources().fireworks(this, this.getOwner()), f1); ++ CraftEventFactory.entityDamage = null; // CraftBukkit + } + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/FishingHook.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/FishingHook.java.patch index 6dc4d327d0..466a262686 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/FishingHook.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/FishingHook.java.patch @@ -1,5 +1,32 @@ --- a/net/minecraft/world/entity/projectile/FishingHook.java +++ b/net/minecraft/world/entity/projectile/FishingHook.java +@@ -43,6 +_,8 @@ + import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.entity.FishHook; ++import org.bukkit.event.player.PlayerFishEvent; + import org.slf4j.Logger; + + public class FishingHook extends Projectile { +@@ -64,6 +_,17 @@ + private FishingHook.FishHookState currentState = FishingHook.FishHookState.FLYING; + private final int luck; + private final int lureSpeed; ++ // CraftBukkit start - Extra variables to enable modification of fishing wait time, values are minecraft defaults ++ public int minWaitTime = 100; ++ public int maxWaitTime = 600; ++ public int minLureTime = 20; ++ public int maxLureTime = 80; ++ public float minLureAngle = 0.0F; ++ public float maxLureAngle = 360.0F; ++ public boolean applyLure = true; ++ public boolean rainInfluenced = true; ++ public boolean skyInfluenced = true; ++ // CraftBukkit end + + private FishingHook(EntityType p_150141_, Level p_150142_, int p_150143_, int p_150144_) { + super(p_150141_, p_150142_); @@ -229,8 +_,8 @@ private boolean shouldStopFishing(Player p_37137_) { ItemStack itemstack = p_37137_.getMainHandItem(); @@ -16,16 +43,84 @@ private void checkCollision() { HitResult hitresult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); - this.onHit(hitresult); -+ if (hitresult.getType() == HitResult.Type.MISS || !net.minecraftforge.event.ForgeEventFactory.onProjectileImpact(this, hitresult)) this.onHit(hitresult); ++ if (hitresult.getType() == HitResult.Type.MISS || !net.minecraftforge.event.ForgeEventFactory.onProjectileImpact(this, hitresult)) this.preOnHit(hitresult); // CraftBukkit - projectile hit event } protected boolean canHitEntity(Entity p_37135_) { -@@ -403,15 +_,22 @@ +@@ -270,11 +_,11 @@ + ServerLevel serverlevel = (ServerLevel)this.level(); + int i = 1; + BlockPos blockpos = p_37146_.above(); +- if (this.random.nextFloat() < 0.25F && this.level().isRainingAt(blockpos)) { ++ if (this.rainInfluenced && this.random.nextFloat() < 0.25F && this.level().isRainingAt(blockpos)) { // CraftBukkit + ++i; + } + +- if (this.random.nextFloat() < 0.5F && !this.level().canSeeSky(blockpos)) { ++ if (this.skyInfluenced && this.random.nextFloat() < 0.5F && !this.level().canSeeSky(blockpos)) { // CraftBukkit + --i; + } + +@@ -284,6 +_,10 @@ + this.timeUntilLured = 0; + this.timeUntilHooked = 0; + this.getEntityData().set(DATA_BITING, false); ++ // CraftBukkit start ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) this.getPlayerOwner().getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.FAILED_ATTEMPT); ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ // CraftBukkit end + } + } else if (this.timeUntilHooked > 0) { + this.timeUntilHooked -= i; +@@ -307,6 +_,13 @@ + serverlevel.sendParticles(ParticleTypes.FISHING, d0, d1, d2, 0, (double)(-f4), 0.01D, (double)f3, 1.0D); + } + } else { ++ // CraftBukkit start ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) this.getPlayerOwner().getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.BITE); ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ if (playerFishEvent.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + this.playSound(SoundEvents.FISHING_BOBBER_SPLASH, 0.25F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F); + double d3 = this.getY() + 0.5D; + serverlevel.sendParticles(ParticleTypes.BUBBLE, this.getX(), d3, this.getZ(), (int)(1.0F + this.getBbWidth() * 20.0F), (double)this.getBbWidth(), 0.0D, (double)this.getBbWidth(), (double)0.2F); +@@ -338,12 +_,16 @@ + } + + if (this.timeUntilLured <= 0) { +- this.fishAngle = Mth.nextFloat(this.random, 0.0F, 360.0F); +- this.timeUntilHooked = Mth.nextInt(this.random, 20, 80); ++ // CraftBukkit start - logic to modify fishing wait time, lure time, and lure angle ++ this.fishAngle = Mth.nextFloat(this.random, this.minLureAngle, this.maxLureAngle); ++ this.timeUntilHooked = Mth.nextInt(this.random, this.minLureTime, this.maxLureTime); ++ // CraftBukkit end + } + } else { +- this.timeUntilLured = Mth.nextInt(this.random, 100, 600); +- this.timeUntilLured -= this.lureSpeed * 20 * 5; ++ // CraftBukkit start - logic to modify fishing wait time ++ this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime); ++ this.timeUntilLured -= (this.applyLure) ? this.lureSpeed * 20 * 5 : 0; ++ // CraftBukkit end + } + + } +@@ -403,26 +_,54 @@ Player player = this.getPlayerOwner(); if (!this.level().isClientSide && player != null && !this.shouldStopFishing(player)) { int i = 0; + net.minecraftforge.event.entity.player.ItemFishedEvent event = null; if (this.hookedIn != null) { ++ // CraftBukkit start ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) player.getBukkitEntity(), this.hookedIn.getBukkitEntity(), (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_ENTITY); ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ // CraftBukkit end this.pullEntity(this.hookedIn); CriteriaTriggers.FISHING_ROD_HOOKED.trigger((ServerPlayer)player, p_37157_, this, Collections.emptyList()); this.level().broadcastEntityEvent(this, (byte)31); @@ -44,9 +139,56 @@ CriteriaTriggers.FISHING_ROD_HOOKED.trigger((ServerPlayer)player, p_37157_, this, list); for(ItemStack itemstack : list) { -@@ -436,7 +_,7 @@ + ItemEntity itementity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack); ++ // CraftBukkit start ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) player.getBukkitEntity(), itementity.getBukkitEntity(), (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_FISH); ++ playerFishEvent.setExpToDrop(this.random.nextInt(6) + 1); ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ // CraftBukkit end + double d0 = player.getX() - this.getX(); + double d1 = player.getY() - this.getY(); + double d2 = player.getZ() - this.getZ(); + double d3 = 0.1D; + itementity.setDeltaMovement(d0 * 0.1D, d1 * 0.1D + Math.sqrt(Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2)) * 0.08D, d2 * 0.1D); + this.level().addFreshEntity(itementity); +- player.level().addFreshEntity(new ExperienceOrb(player.level(), player.getX(), player.getY() + 0.5D, player.getZ() + 0.5D, this.random.nextInt(6) + 1)); ++ // CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop() ++ if (playerFishEvent.getExpToDrop() > 0) { ++ player.level().addFreshEntity(new ExperienceOrb(player.level(), player.getX(), player.getY() + 0.5D, player.getZ() + 0.5D, playerFishEvent.getExpToDrop())); ++ } ++ // CraftBukkit end + if (itemstack.is(ItemTags.FISHES)) { + player.awardStat(Stats.FISH_CAUGHT, 1); + } +@@ -432,11 +_,29 @@ } + if (this.onGround()) { ++ // CraftBukkit start ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) player.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.IN_GROUND); ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ // CraftBukkit end + i = 2; + } + ++ // CraftBukkit start ++ if (i == 0) { ++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) player.getBukkitEntity(), null, (FishHook) this.getBukkitEntity(), PlayerFishEvent.State.REEL_IN); ++ this.level().getCraftServer().getPluginManager().callEvent(playerFishEvent); ++ if (playerFishEvent.isCancelled()) { ++ return 0; ++ } ++ } ++ // CraftBukkit end ++ this.discard(); - return i; + return event == null ? i : event.getRodDamage(); diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/LargeFireball.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/LargeFireball.java.patch index bdde41d4ed..15c73d5a91 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/LargeFireball.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/LargeFireball.java.patch @@ -1,12 +1,40 @@ --- a/net/minecraft/world/entity/projectile/LargeFireball.java +++ b/net/minecraft/world/entity/projectile/LargeFireball.java -@@ -24,7 +_,8 @@ +@@ -8,6 +_,7 @@ + import net.minecraft.world.level.Level; + import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; ++import org.bukkit.event.entity.ExplosionPrimeEvent; + + public class LargeFireball extends Fireball { + private int explosionPower = 1; +@@ -24,8 +_,17 @@ protected void onHit(HitResult p_37218_) { super.onHit(p_37218_); if (!this.level().isClientSide) { - boolean flag = this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); +- this.level().explode(this, this.getX(), this.getY(), this.getZ(), (float)this.explosionPower, flag, Level.ExplosionInteraction.MOB); + // TODO 1.19.3: The creation of Level.ExplosionInteraction means this code path will fire EntityMobGriefingEvent twice. Should we try and fix it? -SS + boolean flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.level(), this.getOwner()); - this.level().explode(this, this.getX(), this.getY(), this.getZ(), (float)this.explosionPower, flag, Level.ExplosionInteraction.MOB); ++ // CraftBukkit start - fire ExplosionPrimeEvent ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ // give 'this' instead of (Entity) null so we know what causes the damage ++ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); ++ } ++ // CraftBukkit end this.discard(); } + +@@ -52,7 +_,8 @@ + public void readAdditionalSaveData(CompoundTag p_37220_) { + super.readAdditionalSaveData(p_37220_); + if (p_37220_.contains("ExplosionPower", 99)) { +- this.explosionPower = p_37220_.getByte("ExplosionPower"); ++ // CraftBukkit - set bukkitYield when setting explosionpower ++ bukkitYield = this.explosionPower = p_37220_.getByte("ExplosionPower"); + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/LlamaSpit.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/LlamaSpit.java.patch index b5c35ee4c0..c7754a8dc5 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/LlamaSpit.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/LlamaSpit.java.patch @@ -1,10 +1,12 @@ --- a/net/minecraft/world/entity/projectile/LlamaSpit.java +++ b/net/minecraft/world/entity/projectile/LlamaSpit.java -@@ -29,6 +_,7 @@ +@@ -29,7 +_,8 @@ super.tick(); Vec3 vec3 = this.getDeltaMovement(); HitResult hitresult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); +- this.onHit(hitresult); + if (hitresult.getType() != HitResult.Type.MISS && !net.minecraftforge.event.ForgeEventFactory.onProjectileImpact(this, hitresult)) - this.onHit(hitresult); ++ this.preOnHit(hitresult); // CraftBukkit - projectile hit event double d0 = this.getX() + vec3.x; double d1 = this.getY() + vec3.y; + double d2 = this.getZ() + vec3.z; diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/Projectile.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/Projectile.java.patch index 0d5b618738..6a381b2bc9 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/Projectile.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/Projectile.java.patch @@ -1,5 +1,61 @@ --- a/net/minecraft/world/entity/projectile/Projectile.java +++ b/net/minecraft/world/entity/projectile/Projectile.java +@@ -22,6 +_,7 @@ + import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.projectiles.ProjectileSource; + + public abstract class Projectile extends Entity implements TraceableEntity { + @Nullable +@@ -30,6 +_,9 @@ + private Entity cachedOwner; + private boolean leftOwner; + private boolean hasBeenShot; ++ // CraftBukkit start ++ private boolean hitCancelled = false; ++ // CraftBukkit end + + protected Projectile(EntityType p_37248_, Level p_37249_) { + super(p_37248_, p_37249_); +@@ -40,7 +_,7 @@ + this.ownerUUID = p_37263_.getUUID(); + this.cachedOwner = p_37263_; + } +- ++ this.projectileSource = (p_37263_ != null && p_37263_.getBukkitEntity() instanceof ProjectileSource) ? (ProjectileSource) p_37263_.getBukkitEntity() : null; // CraftBukkit + } + + @Nullable +@@ -132,6 +_,16 @@ + this.setDeltaMovement(this.getDeltaMovement().add(vec3.x, p_37252_.onGround() ? 0.0D : vec3.y, vec3.z)); + } + ++ // CraftBukkit start - call projectile hit event ++ protected void preOnHit(HitResult hitResult) { ++ org.bukkit.event.entity.ProjectileHitEvent event = org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callProjectileHitEvent(this, hitResult); ++ this.hitCancelled = event != null && event.isCancelled(); ++ if (hitResult.getType() == HitResult.Type.BLOCK || !this.hitCancelled) { ++ this.onHit(hitResult); ++ } ++ } ++ // CraftBukkit end ++ + protected void onHit(HitResult p_37260_) { + HitResult.Type hitresult$type = p_37260_.getType(); + if (hitresult$type == HitResult.Type.ENTITY) { +@@ -150,6 +_,11 @@ + } + + protected void onHitBlock(BlockHitResult p_37258_) { ++ // CraftBukkit start - cancellable hit event ++ if (hitCancelled) { ++ return; ++ } ++ // CraftBukkit end + BlockState blockstate = this.level().getBlockState(p_37258_.getBlockPos()); + blockstate.onProjectileHit(this.level(), blockstate, p_37258_, this); + } @@ -214,7 +_,7 @@ if (entity instanceof Player) { return entity.mayInteract(p_150167_, p_150168_); diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch index cb808aa817..2945a4f1cd 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch @@ -1,11 +1,56 @@ --- a/net/minecraft/world/entity/projectile/ShulkerBullet.java +++ b/net/minecraft/world/entity/projectile/ShulkerBullet.java -@@ -212,7 +_,7 @@ +@@ -58,7 +_,20 @@ + this.finalTarget = p_37332_; + this.currentMoveDirection = Direction.UP; + this.selectNextMoveDirection(p_37333_); +- } ++ projectileSource = (org.bukkit.entity.LivingEntity) p_37331_.getBukkitEntity(); // CraftBukkit ++ } ++ ++ // CraftBukkit start ++ public Entity getTarget() { ++ return this.finalTarget; ++ } ++ ++ public void setTarget(Entity e) { ++ this.finalTarget = e; ++ this.currentMoveDirection = Direction.UP; ++ this.selectNextMoveDirection(Direction.Axis.X); ++ } ++ // CraftBukkit end + + public SoundSource getSoundSource() { + return SoundSource.HOSTILE; +@@ -212,8 +_,8 @@ } HitResult hitresult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); - if (hitresult.getType() != HitResult.Type.MISS) { +- this.onHit(hitresult); + if (hitresult.getType() != HitResult.Type.MISS && !net.minecraftforge.event.ForgeEventFactory.onProjectileImpact(this, hitresult)) { - this.onHit(hitresult); ++ this.preOnHit(hitresult); // CraftBukkit - projectile hit event + } + } + +@@ -273,7 +_,7 @@ + this.doEnchantDamageEffects(livingentity, entity); + if (entity instanceof LivingEntity) { + LivingEntity livingentity1 = (LivingEntity)entity; +- livingentity1.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), MoreObjects.firstNonNull(entity1, this)); ++ livingentity1.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200), MoreObjects.firstNonNull(entity1, this), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit } } + +@@ -300,6 +_,11 @@ + } + + public boolean hurt(DamageSource p_37338_, float p_37339_) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, p_37338_, p_37339_, false)) { ++ return false; ++ } ++ // CraftBukkit end + if (!this.level().isClientSide) { + this.playSound(SoundEvents.SHULKER_BULLET_HURT, 1.0F, 1.0F); + ((ServerLevel)this.level()).sendParticles(ParticleTypes.CRIT, this.getX(), this.getY(), this.getZ(), 15, 0.2D, 0.2D, 0.2D, 0.0D); diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/SmallFireball.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/SmallFireball.java.patch index 986dce07ce..818a5357af 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/SmallFireball.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/SmallFireball.java.patch @@ -1,11 +1,38 @@ --- a/net/minecraft/world/entity/projectile/SmallFireball.java +++ b/net/minecraft/world/entity/projectile/SmallFireball.java -@@ -46,7 +_,7 @@ +@@ -12,6 +_,7 @@ + import net.minecraft.world.phys.BlockHitResult; + import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; ++import org.bukkit.event.entity.EntityCombustByEntityEvent; + + public class SmallFireball extends Fireball { + public SmallFireball(EntityType p_37364_, Level p_37365_) { +@@ -32,7 +_,14 @@ + Entity entity = p_37386_.getEntity(); + Entity entity1 = this.getOwner(); + int i = entity.getRemainingFireTicks(); +- entity.setSecondsOnFire(5); ++ // CraftBukkit start - Entity damage by entity event + combust event ++ EntityCombustByEntityEvent event = new EntityCombustByEntityEvent((org.bukkit.entity.Projectile) this.getBukkitEntity(), entity.getBukkitEntity(), 5); ++ entity.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ entity.setSecondsOnFire(event.getDuration(), false); ++ } ++ // CraftBukkit end + if (!entity.hurt(this.damageSources().fireball(this, entity1), 5.0F)) { + entity.setRemainingFireTicks(i); + } else if (entity1 instanceof LivingEntity) { +@@ -46,9 +_,9 @@ super.onHitBlock(p_37384_); if (!this.level().isClientSide) { Entity entity = this.getOwner(); - if (!(entity instanceof Mob) || this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { -+ if (!(entity instanceof Mob) || net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.level(), entity)) { ++ if (isIncendiary || net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.level(), entity)) { // CraftBukkit BlockPos blockpos = p_37384_.getBlockPos().relative(p_37384_.getDirection()); - if (this.level().isEmptyBlock(blockpos)) { +- if (this.level().isEmptyBlock(blockpos)) { ++ if (this.level().isEmptyBlock(blockpos) && !org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callBlockIgniteEvent(this.level(), blockpos, this).isCancelled()) { // CraftBukkit this.level().setBlockAndUpdate(blockpos, BaseFireBlock.getState(this.level(), blockpos)); + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/SpectralArrow.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/SpectralArrow.java.patch new file mode 100644 index 0000000000..36befdd4d8 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/projectile/SpectralArrow.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/projectile/SpectralArrow.java ++++ b/net/minecraft/world/entity/projectile/SpectralArrow.java +@@ -40,7 +_,7 @@ + protected void doPostHurtEffects(LivingEntity p_37422_) { + super.doPostHurtEffects(p_37422_); + MobEffectInstance mobeffectinstance = new MobEffectInstance(MobEffects.GLOWING, this.duration, 0); +- p_37422_.addEffect(mobeffectinstance, this.getEffectSource()); ++ p_37422_.addEffect(mobeffectinstance, this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ARROW); // CraftBukkit + } + + public void readAdditionalSaveData(CompoundTag p_37424_) { diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch new file mode 100644 index 0000000000..3ad982fae8 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java ++++ b/net/minecraft/world/entity/projectile/ThrowableItemProjectile.java +@@ -34,6 +_,11 @@ + + protected abstract Item getDefaultItem(); + ++ // CraftBukkit start ++ public Item getDefaultItemPublic() { ++ return getDefaultItem(); ++ } ++ // CraftBukkit end + protected ItemStack getItemRaw() { + return this.getEntityData().get(DATA_ITEM_STACK); + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch index e7fc026fa0..0582791520 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch @@ -1,11 +1,13 @@ --- a/net/minecraft/world/entity/projectile/ThrowableProjectile.java +++ b/net/minecraft/world/entity/projectile/ThrowableProjectile.java -@@ -58,7 +_,7 @@ +@@ -58,8 +_,8 @@ } } - if (hitresult.getType() != HitResult.Type.MISS && !flag) { +- this.onHit(hitresult); + if (hitresult.getType() != HitResult.Type.MISS && !flag && !net.minecraftforge.event.ForgeEventFactory.onProjectileImpact(this, hitresult)) { - this.onHit(hitresult); ++ this.preOnHit(hitresult); // CraftBukkit - projectile hit event } + this.checkInsideBlocks(); diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/ThrownEgg.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownEgg.java.patch new file mode 100644 index 0000000000..0b34200fc9 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownEgg.java.patch @@ -0,0 +1,74 @@ +--- a/net/minecraft/world/entity/projectile/ThrownEgg.java ++++ b/net/minecraft/world/entity/projectile/ThrownEgg.java +@@ -2,14 +_,18 @@ + + import net.minecraft.core.particles.ItemParticleOption; + import net.minecraft.core.particles.ParticleTypes; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityType; + import net.minecraft.world.entity.LivingEntity; +-import net.minecraft.world.entity.animal.Chicken; + import net.minecraft.world.item.Item; + import net.minecraft.world.item.Items; + import net.minecraft.world.level.Level; + import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; ++import org.bukkit.entity.Ageable; ++import org.bukkit.entity.Player; ++import org.bukkit.event.player.PlayerEggThrowEvent; + + public class ThrownEgg extends ThrowableItemProjectile { + public ThrownEgg(EntityType p_37473_, Level p_37474_) { +@@ -43,18 +_,45 @@ + protected void onHit(HitResult p_37488_) { + super.onHit(p_37488_); + if (!this.level().isClientSide) { +- if (this.random.nextInt(8) == 0) { ++ // CraftBukkit start ++ boolean hatching = this.random.nextInt(8) == 0; ++ if (true) { ++ // CraftBukkit end + int i = 1; + if (this.random.nextInt(32) == 0) { + i = 4; + } + ++ // CraftBukkit start ++ org.bukkit.entity.EntityType hatchingType = org.bukkit.entity.EntityType.CHICKEN; ++ ++ Entity shooter = this.getOwner(); ++ if (!hatching) { ++ i = 0; ++ } ++ if (shooter instanceof ServerPlayer) { ++ PlayerEggThrowEvent event = new PlayerEggThrowEvent((Player) shooter.getBukkitEntity(), (org.bukkit.entity.Egg) this.getBukkitEntity(), hatching, (byte) i, hatchingType); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ i = event.getNumHatches(); ++ hatching = event.isHatching(); ++ hatchingType = event.getHatchingType(); ++ // If hatching is set to false, ensure child count is 0 ++ if (!hatching) { ++ i = 0; ++ } ++ } ++ // CraftBukkit end ++ + for(int j = 0; j < i; ++j) { +- Chicken chicken = EntityType.CHICKEN.create(this.level()); +- if (chicken != null) { +- chicken.setAge(-24000); +- chicken.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F); +- this.level().addFreshEntity(chicken); ++ Entity entitychicken = this.level().getWorld().createEntity(new org.bukkit.Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F), hatchingType.getEntityClass()); // CraftBukkit ++ if (entitychicken != null) { ++ // CraftBukkit start ++ if (entitychicken.getBukkitEntity() instanceof Ageable) { ++ ((Ageable) entitychicken.getBukkitEntity()).setBaby(); ++ } ++ this.level().addFreshEntity(entitychicken, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EGG); ++ // CraftBukkit end + } + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch index 672ffa5082..066c4623a3 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch @@ -1,22 +1,67 @@ --- a/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +++ b/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -@@ -45,6 +_,8 @@ +@@ -14,6 +_,10 @@ + import net.minecraft.world.level.Level; + import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; ++import org.bukkit.Bukkit; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.bukkit.event.player.PlayerTeleportEvent; + + public class ThrownEnderpearl extends ThrowableItemProjectile { + public ThrownEnderpearl(EntityType p_37491_, Level p_37492_) { +@@ -45,22 +_,39 @@ if (entity instanceof ServerPlayer) { ServerPlayer serverplayer = (ServerPlayer)entity; if (serverplayer.connection.isAcceptingMessages() && serverplayer.level() == this.level() && !serverplayer.isSleeping()) { +- if (this.random.nextFloat() < 0.05F && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { +- Endermite endermite = EntityType.ENDERMITE.create(this.level()); +- if (endermite != null) { +- endermite.moveTo(entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot()); +- this.level().addFreshEntity(endermite); + net.minecraftforge.event.entity.EntityTeleportEvent.EnderPearl event = net.minecraftforge.event.ForgeEventFactory.onEnderPearlLand(serverplayer, this.getX(), this.getY(), this.getZ(), this, 5.0F, p_37504_); + if (!event.isCanceled()) { // Don't indent to lower patch size - if (this.random.nextFloat() < 0.05F && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { - Endermite endermite = EntityType.ENDERMITE.create(this.level()); - if (endermite != null) { -@@ -59,8 +_,10 @@ - entity.teleportTo(this.getX(), this.getY(), this.getZ()); - } - -+ entity.teleportTo(event.getTargetX(), event.getTargetY(), event.getTargetZ()); - entity.resetFallDistance(); ++ // CraftBukkit start - Fire PlayerTeleportEvent ++ org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer player = serverplayer.getBukkitEntity(); ++ org.bukkit.Location location = getBukkitEntity().getLocation(); ++ location.setPitch(player.getLocation().getPitch()); ++ location.setYaw(player.getLocation().getYaw()); ++ ++ PlayerTeleportEvent teleEvent = new PlayerTeleportEvent(player, player.getLocation(), location, PlayerTeleportEvent.TeleportCause.ENDER_PEARL); ++ Bukkit.getPluginManager().callEvent(teleEvent); ++ ++ if (!teleEvent.isCancelled() && serverplayer.connection.isAcceptingMessages()) { ++ if (this.random.nextFloat() < 0.05F && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { ++ Endermite entityendermite = (Endermite) EntityType.ENDERMITE.create(this.level()); ++ ++ if (entityendermite != null) { ++ entityendermite.moveTo(entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot()); ++ this.level().addFreshEntity(entityendermite, CreatureSpawnEvent.SpawnReason.ENDER_PEARL); ++ } ++ } ++ ++ if (entity.isPassenger()) { ++ entity.stopRiding(); ++ } ++ ++ serverplayer.connection.teleport(teleEvent.getTo()); ++ entity.resetFallDistance(); ++ CraftEventFactory.entityDamage = this; ++ entity.hurt(this.damageSources().fall(), 5.0F); ++ CraftEventFactory.entityDamage = null; + } +- } +- +- if (entity.isPassenger()) { +- serverplayer.dismountTo(this.getX(), this.getY(), this.getZ()); +- } else { +- entity.teleportTo(this.getX(), this.getY(), this.getZ()); +- } +- +- entity.resetFallDistance(); - entity.hurt(this.damageSources().fall(), 5.0F); -+ entity.hurt(this.damageSources().fall(), event.getAttackDamage()); ++ // CraftBukkit end + } //Forge: End } } else if (entity != null) { @@ -28,7 +73,8 @@ - public Entity changeDimension(ServerLevel p_37506_) { + public Entity changeDimension(ServerLevel p_37506_, net.minecraftforge.common.util.ITeleporter teleporter) { Entity entity = this.getOwner(); - if (entity != null && entity.level().dimension() != p_37506_.dimension()) { +- if (entity != null && entity.level().dimension() != p_37506_.dimension()) { ++ if (entity != null && p_37506_ != null && entity.level().dimension() != p_37506_.dimension()) { // CraftBukkit - SPIGOT-6113 this.setOwner((Entity)null); } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch new file mode 100644 index 0000000000..87eb8f45e6 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch @@ -0,0 +1,22 @@ +--- a/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java ++++ b/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java +@@ -35,8 +_,18 @@ + protected void onHit(HitResult p_37521_) { + super.onHit(p_37521_); + if (this.level() instanceof ServerLevel) { +- this.level().levelEvent(2002, this.blockPosition(), PotionUtils.getColor(Potions.WATER)); ++ // CraftBukkit - moved to after event ++ //this.level().levelEvent(2002, this.blockPosition(), PotionUtils.getColor(Potions.WATER)); + int i = 3 + this.level().random.nextInt(5) + this.level().random.nextInt(5); ++ ++ // CraftBukkit start ++ org.bukkit.event.entity.ExpBottleEvent event = org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callExpBottleEvent(this, p_37521_, i); ++ i = event.getExperience(); ++ if (event.getShowEffect()) { ++ this.level().levelEvent(2002, this.blockPosition(), PotionUtils.getColor(Potions.WATER)); ++ } ++ // CraftBukkit end ++ + ExperienceOrb.award((ServerLevel)this.level(), this.position(), i); + this.discard(); + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/ThrownPotion.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownPotion.java.patch new file mode 100644 index 0000000000..e0ea79ee34 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownPotion.java.patch @@ -0,0 +1,197 @@ +--- a/net/minecraft/world/entity/projectile/ThrownPotion.java ++++ b/net/minecraft/world/entity/projectile/ThrownPotion.java +@@ -1,14 +_,18 @@ + package net.minecraft.world.entity.projectile; + ++import java.util.HashMap; + import java.util.List; ++import java.util.Map; + import java.util.function.Predicate; + import javax.annotation.Nullable; + import net.minecraft.core.BlockPos; + import net.minecraft.core.Direction; + import net.minecraft.nbt.CompoundTag; ++import net.minecraft.server.level.ServerPlayer; + import net.minecraft.tags.BlockTags; + import net.minecraft.world.effect.MobEffect; + import net.minecraft.world.effect.MobEffectInstance; ++import net.minecraft.world.effect.MobEffects; + import net.minecraft.world.entity.AreaEffectCloud; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityType; +@@ -23,12 +_,16 @@ + import net.minecraft.world.item.alchemy.Potions; + import net.minecraft.world.level.Level; + import net.minecraft.world.level.block.AbstractCandleBlock; ++import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.CampfireBlock; + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.BlockHitResult; + import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; ++import org.bukkit.craftbukkit.v1_20_R2.entity.CraftLivingEntity; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityPotionEffectEvent; + + public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplier { + public static final double SPLASH_RANGE = 4.0D; +@@ -90,9 +_,9 @@ + this.applyWater(); + } else if (!list.isEmpty()) { + if (this.isLingering()) { +- this.makeAreaOfEffectCloud(itemstack, potion); ++ this.makeAreaOfEffectCloud(itemstack, potion, p_37543_); // CraftBukkit - Pass HitResult + } else { +- this.applySplash(list, p_37543_.getType() == HitResult.Type.ENTITY ? ((EntityHitResult)p_37543_).getEntity() : null); ++ this.applySplash(list, p_37543_.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) p_37543_).getEntity() : null, p_37543_); // CraftBukkit - Pass HitResult + } + } + +@@ -124,45 +_,72 @@ + + } + +- private void applySplash(List p_37548_, @Nullable Entity p_37549_) { ++ private void applySplash(List p_37548_, @Nullable Entity p_37549_, HitResult position) { // CraftBukkit - Pass MovingObjectPosition + AABB aabb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D); + List list = this.level().getEntitiesOfClass(LivingEntity.class, aabb); ++ Map affected = new HashMap(); // CraftBukkit + if (!list.isEmpty()) { + Entity entity = this.getEffectSource(); + +- for(LivingEntity livingentity : list) { ++ for (LivingEntity livingentity : list) { + if (livingentity.isAffectedByPotions()) { + double d0 = this.distanceToSqr(livingentity); + if (d0 < 16.0D) { +- double d1; ++ double d1 = 1.0D - Math.sqrt(d0) / 4.0D; + if (livingentity == p_37549_) { + d1 = 1.0D; +- } else { +- d1 = 1.0D - Math.sqrt(d0) / 4.0D; +- } +- +- for(MobEffectInstance mobeffectinstance : p_37548_) { +- MobEffect mobeffect = mobeffectinstance.getEffect(); +- if (mobeffect.isInstantenous()) { +- mobeffect.applyInstantenousEffect(this, this.getOwner(), livingentity, mobeffectinstance.getAmplifier(), d1); +- } else { +- int i = mobeffectinstance.mapDuration((p_267930_) -> { +- return (int)(d1 * (double)p_267930_ + 0.5D); +- }); +- MobEffectInstance mobeffectinstance1 = new MobEffectInstance(mobeffect, i, mobeffectinstance.getAmplifier(), mobeffectinstance.isAmbient(), mobeffectinstance.isVisible()); +- if (!mobeffectinstance1.endsWithin(20)) { +- livingentity.addEffect(mobeffectinstance1, entity); +- } +- } +- } +- } +- } +- } +- } +- ++ } ++ ++ // CraftBukkit start ++ affected.put((org.bukkit.entity.LivingEntity) livingentity.getBukkitEntity(), d1); ++ } ++ } ++ } ++ } ++ ++ ++ org.bukkit.event.entity.PotionSplashEvent event = CraftEventFactory.callPotionSplashEvent(this, position, affected); ++ if (!event.isCancelled() && list != null && !list.isEmpty()) { // do not process effects if there are no effects to process ++ Entity entity1 = this.getEffectSource(); ++ for (org.bukkit.entity.LivingEntity victim : event.getAffectedEntities()) { ++ if (!(victim instanceof CraftLivingEntity)) { ++ continue; ++ } ++ ++ LivingEntity livingentity = ((CraftLivingEntity) victim).getHandle(); ++ double intensity = event.getIntensity(victim); ++ // CraftBukkit end ++ ++ for (MobEffectInstance effectinstance : p_37548_) { ++ MobEffect mobeffectlist = effectinstance.getEffect(); ++ // CraftBukkit start - Abide by PVP settings - for players only! ++ if (!this.level().pvpMode && this.getOwner() instanceof ServerPlayer && livingentity instanceof ServerPlayer && livingentity != this.getOwner()) { ++ if (mobeffectlist == MobEffects.MOVEMENT_SLOWDOWN || mobeffectlist == MobEffects.DIG_SLOWDOWN || mobeffectlist == MobEffects.HARM || mobeffectlist == MobEffects.BLINDNESS ++ || mobeffectlist == MobEffects.HUNGER || mobeffectlist == MobEffects.WEAKNESS || mobeffectlist == MobEffects.POISON) { ++ continue; ++ } ++ } ++ // CraftBukkit end ++ ++ if (mobeffectlist.isInstantenous()) { ++ mobeffectlist.applyInstantenousEffect(this, this.getOwner(), livingentity, effectinstance.getAmplifier(), intensity); ++ } else { ++ int i = effectinstance.mapDuration((j) -> { ++ return (int) (intensity * (double) j + 0.5D); ++ }); ++ MobEffectInstance mobeffect1 = new MobEffectInstance(mobeffectlist, i, effectinstance.getAmplifier(), effectinstance.isAmbient(), effectinstance.isVisible()); ++ ++ if (!mobeffect1.endsWithin(20)) { ++ livingentity.addEffect(mobeffect1, entity1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_SPLASH); // CraftBukkit ++ } ++ } ++ } ++ } ++ } + } + +- private void makeAreaOfEffectCloud(ItemStack p_37538_, Potion p_37539_) { ++ ++ private void makeAreaOfEffectCloud(ItemStack p_37538_, Potion p_37539_, HitResult position) { // CraftBukkit - Pass MovingObjectPosition + AreaEffectCloud areaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); + Entity entity = this.getOwner(); + if (entity instanceof LivingEntity) { +@@ -184,7 +_,14 @@ + areaeffectcloud.setFixedColor(compoundtag.getInt("CustomPotionColor")); + } + +- this.level().addFreshEntity(areaeffectcloud); ++ // CraftBukkit start ++ org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callLingeringPotionSplashEvent(this, position, areaeffectcloud); ++ if (!(event.isCancelled() || areaeffectcloud.isRemoved())) { ++ this.level().addFreshEntity(areaeffectcloud); ++ } else { ++ areaeffectcloud.discard(); ++ } ++ // CraftBukkit end + } + + private boolean isLingering() { +@@ -194,13 +_,25 @@ + private void dowseFire(BlockPos p_150193_) { + BlockState blockstate = this.level().getBlockState(p_150193_); + if (blockstate.is(BlockTags.FIRE)) { +- this.level().destroyBlock(p_150193_, false, this); ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityChangeBlockEvent(this, p_150193_, Blocks.AIR.defaultBlockState())) { ++ this.level().destroyBlock(p_150193_, false, this); ++ } ++ // CraftBukkit end + } else if (AbstractCandleBlock.isLit(blockstate)) { +- AbstractCandleBlock.extinguish((Player)null, blockstate, this.level(), p_150193_); ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityChangeBlockEvent(this, p_150193_, blockstate.setValue(AbstractCandleBlock.LIT, false))) { ++ AbstractCandleBlock.extinguish((Player) null, blockstate, this.level(), p_150193_); ++ } ++ // CraftBukkit end + } else if (CampfireBlock.isLitCampfire(blockstate)) { +- this.level().levelEvent((Player)null, 1009, p_150193_, 0); +- CampfireBlock.dowse(this.getOwner(), this.level(), p_150193_, blockstate); +- this.level().setBlockAndUpdate(p_150193_, blockstate.setValue(CampfireBlock.LIT, Boolean.valueOf(false))); ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityChangeBlockEvent(this, p_150193_, blockstate.setValue(CampfireBlock.LIT, false))) { ++ this.level().levelEvent((Player) null, 1009, p_150193_, 0); ++ CampfireBlock.dowse(this.getOwner(), this.level(), p_150193_, blockstate); ++ this.level().setBlockAndUpdate(p_150193_, (BlockState) blockstate.setValue(CampfireBlock.LIT, false)); ++ } ++ // CraftBukkit end + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/ThrownTrident.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownTrident.java.patch index a20059c29b..79aa45b12e 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/ThrownTrident.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/ThrownTrident.java.patch @@ -9,3 +9,12 @@ private boolean dealtDamage; public int clientSideReturnTridentTickCount; +@@ -140,7 +_,7 @@ + if (lightningbolt != null) { + lightningbolt.moveTo(Vec3.atBottomCenterOf(blockpos)); + lightningbolt.setCause(entity1 instanceof ServerPlayer ? (ServerPlayer)entity1 : null); +- this.level().addFreshEntity(lightningbolt); ++ ((ServerLevel) this.level()).strikeLightning(lightningbolt, org.bukkit.event.weather.LightningStrikeEvent.Cause.TRIDENT); // CraftBukkit + soundevent = SoundEvents.TRIDENT_THUNDER; + f1 = 5.0F; + } diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/WitherSkull.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/WitherSkull.java.patch index bb2bac637f..9251d1fe25 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/WitherSkull.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/WitherSkull.java.patch @@ -1,5 +1,13 @@ --- a/net/minecraft/world/entity/projectile/WitherSkull.java +++ b/net/minecraft/world/entity/projectile/WitherSkull.java +@@ -19,6 +_,7 @@ + import net.minecraft.world.level.material.FluidState; + import net.minecraft.world.phys.EntityHitResult; + import net.minecraft.world.phys.HitResult; ++import org.bukkit.event.entity.ExplosionPrimeEvent; + + public class WitherSkull extends AbstractHurtingProjectile { + private static final EntityDataAccessor DATA_DANGEROUS = SynchedEntityData.defineId(WitherSkull.class, EntityDataSerializers.BOOLEAN); @@ -40,7 +_,7 @@ } @@ -9,3 +17,38 @@ } protected void onHitEntity(EntityHitResult p_37626_) { +@@ -56,7 +_,7 @@ + if (entity.isAlive()) { + this.doEnchantDamageEffects(livingentity, entity); + } else { +- livingentity.heal(5.0F); ++ livingentity.heal(5.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.WITHER); // CraftBukkit + } + } + } else { +@@ -73,7 +_,7 @@ + } + + if (i > 0) { +- livingentity1.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * i, 1), this.getEffectSource()); ++ livingentity1.addEffect(new MobEffectInstance(MobEffects.WITHER, 20 * i, 1), this.getEffectSource(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit; + } + } + +@@ -83,7 +_,15 @@ + protected void onHit(HitResult p_37628_) { + super.onHit(p_37628_); + if (!this.level().isClientSide) { +- this.level().explode(this, this.getX(), this.getY(), this.getZ(), 1.0F, false, Level.ExplosionInteraction.MOB); ++ // CraftBukkit start ++ // this.level().explode(this, this.getX(), this.getY(), this.getZ(), 1.0F, false, World.a.MOB); ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 1.0F, false); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); ++ } ++ // CraftBukkit end + this.discard(); + } + From 457477d173ca7332e19e37f481a0c19a7e28e8b7 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 17:56:40 +0100 Subject: [PATCH 04/26] NPC entity patches --- .../entity/npc/AbstractVillager.java.patch | 49 ++++++ .../entity/npc/InventoryCarrier.java.patch | 16 ++ .../world/entity/npc/Villager.java.patch | 140 +++++++++++++++++- .../entity/npc/WanderingTrader.java.patch | 38 +++++ .../npc/WanderingTraderSpawner.java.patch | 28 ++++ 5 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 patches/minecraft/net/minecraft/world/entity/npc/InventoryCarrier.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/npc/WanderingTrader.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/npc/AbstractVillager.java.patch b/patches/minecraft/net/minecraft/world/entity/npc/AbstractVillager.java.patch index f13f88863a..a375f7f2fe 100644 --- a/patches/minecraft/net/minecraft/world/entity/npc/AbstractVillager.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/npc/AbstractVillager.java.patch @@ -1,5 +1,36 @@ --- a/net/minecraft/world/entity/npc/AbstractVillager.java +++ b/net/minecraft/world/entity/npc/AbstractVillager.java +@@ -34,8 +_,19 @@ + import net.minecraft.world.level.ServerLevelAccessor; + import net.minecraft.world.level.pathfinder.BlockPathTypes; + import net.minecraft.world.phys.Vec3; +- +-public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, Npc, Merchant { ++import org.bukkit.Bukkit; ++import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftMerchant; ++import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftMerchantRecipe; ++import org.bukkit.event.entity.VillagerAcquireTradeEvent; ++ ++public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, Npc, Merchant {// CraftBukkit start ++ private CraftMerchant craftMerchant; ++ ++ @Override ++ public CraftMerchant getCraftMerchant() { ++ return (craftMerchant == null) ? craftMerchant = new CraftMerchant(this) : craftMerchant; ++ } ++ // CraftBukkit end + private static final EntityDataAccessor DATA_UNHAPPY_COUNTER = SynchedEntityData.defineId(AbstractVillager.class, EntityDataSerializers.INT); + public static final int VILLAGER_SLOT_OFFSET = 300; + private static final int VILLAGER_INVENTORY_SIZE = 8; +@@ -43,7 +_,7 @@ + private Player tradingPlayer; + @Nullable + protected MerchantOffers offers; +- private final SimpleContainer inventory = new SimpleContainer(8); ++ private final SimpleContainer inventory = new SimpleContainer(8, (org.bukkit.craftbukkit.v1_20_R2.entity.CraftAbstractVillager) this.getBukkitEntity()); // CraftBukkit add argument + + public AbstractVillager(EntityType p_35267_, Level p_35268_) { + super(p_35267_, p_35268_); @@ -116,6 +_,7 @@ CriteriaTriggers.TRADE.trigger((ServerPlayer)this.tradingPlayer, this, p_35274_.getResult()); } @@ -20,3 +51,21 @@ } protected void stopTrading() { +@@ -210,7 +_,16 @@ + while(i < p_35280_ && !arraylist.isEmpty()) { + MerchantOffer merchantoffer = arraylist.remove(this.random.nextInt(arraylist.size())).getOffer(this, this.random); + if (merchantoffer != null) { +- p_35278_.add(merchantoffer); ++ // CraftBukkit start ++ VillagerAcquireTradeEvent event = new VillagerAcquireTradeEvent((org.bukkit.entity.AbstractVillager) getBukkitEntity(), merchantoffer.asBukkit()); ++ // Suppress during worldgen ++ if (this.valid) { ++ Bukkit.getPluginManager().callEvent(event); ++ } ++ if (!event.isCancelled()) { ++ p_35278_.add(CraftMerchantRecipe.fromBukkit(event.getRecipe()).toMinecraft()); ++ } ++ // CraftBukkit end + ++i; + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/npc/InventoryCarrier.java.patch b/patches/minecraft/net/minecraft/world/entity/npc/InventoryCarrier.java.patch new file mode 100644 index 0000000000..2535343e04 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/npc/InventoryCarrier.java.patch @@ -0,0 +1,16 @@ +--- a/net/minecraft/world/entity/npc/InventoryCarrier.java ++++ b/net/minecraft/world/entity/npc/InventoryCarrier.java +@@ -20,6 +_,13 @@ + return; + } + ++ // CraftBukkit start ++ ItemStack remaining = new SimpleContainer(simplecontainer).addItem(itemstack); ++ if (org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityPickupItemEvent(p_219612_, p_219614_, remaining.getCount(), false).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end ++ + p_219612_.onItemPickup(p_219614_); + int i = itemstack.getCount(); + ItemStack itemstack1 = simplecontainer.addItem(itemstack); diff --git a/patches/minecraft/net/minecraft/world/entity/npc/Villager.java.patch b/patches/minecraft/net/minecraft/world/entity/npc/Villager.java.patch index 5b0f60783e..e52662b3bf 100644 --- a/patches/minecraft/net/minecraft/world/entity/npc/Villager.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/npc/Villager.java.patch @@ -1,5 +1,95 @@ --- a/net/minecraft/world/entity/npc/Villager.java +++ b/net/minecraft/world/entity/npc/Villager.java +@@ -9,22 +_,11 @@ + import com.mojang.serialization.DataResult; + import com.mojang.serialization.Dynamic; + import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +-import java.util.List; +-import java.util.Map; +-import java.util.Optional; +-import java.util.Set; +-import java.util.function.BiPredicate; +-import java.util.stream.Collectors; +-import javax.annotation.Nullable; + import net.minecraft.core.BlockPos; + import net.minecraft.core.GlobalPos; + import net.minecraft.core.Holder; + import net.minecraft.core.particles.ParticleTypes; +-import net.minecraft.core.registries.BuiltInRegistries; +-import net.minecraft.nbt.CompoundTag; +-import net.minecraft.nbt.ListTag; +-import net.minecraft.nbt.NbtOps; +-import net.minecraft.nbt.Tag; ++import net.minecraft.nbt.*; + import net.minecraft.network.chat.Component; + import net.minecraft.network.protocol.game.DebugPackets; + import net.minecraft.network.syncher.EntityDataAccessor; +@@ -38,24 +_,11 @@ + import net.minecraft.tags.ItemTags; + import net.minecraft.util.Mth; + import net.minecraft.util.SpawnUtil; +-import net.minecraft.world.Difficulty; +-import net.minecraft.world.DifficultyInstance; +-import net.minecraft.world.InteractionHand; +-import net.minecraft.world.InteractionResult; +-import net.minecraft.world.SimpleContainer; ++import net.minecraft.world.*; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.effect.MobEffectInstance; + import net.minecraft.world.effect.MobEffects; +-import net.minecraft.world.entity.AgeableMob; +-import net.minecraft.world.entity.Entity; +-import net.minecraft.world.entity.EntityType; +-import net.minecraft.world.entity.ExperienceOrb; +-import net.minecraft.world.entity.LightningBolt; +-import net.minecraft.world.entity.LivingEntity; +-import net.minecraft.world.entity.Mob; +-import net.minecraft.world.entity.MobSpawnType; +-import net.minecraft.world.entity.ReputationEventHandler; +-import net.minecraft.world.entity.SpawnGroupData; ++import net.minecraft.world.entity.*; + import net.minecraft.world.entity.ai.Brain; + import net.minecraft.world.entity.ai.attributes.AttributeSupplier; + import net.minecraft.world.entity.ai.attributes.Attributes; +@@ -88,8 +_,20 @@ + import net.minecraft.world.level.Level; + import net.minecraft.world.level.ServerLevelAccessor; + import net.minecraft.world.phys.AABB; ++import org.bukkit.Bukkit; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityTransformEvent; ++import org.bukkit.event.entity.VillagerReplenishTradeEvent; + import org.slf4j.Logger; + ++import javax.annotation.Nullable; ++import java.util.List; ++import java.util.Map; ++import java.util.Optional; ++import java.util.Set; ++import java.util.function.BiPredicate; ++import java.util.stream.Collectors; ++ + public class Villager extends AbstractVillager implements ReputationEventHandler, VillagerDataHolder { + private static final Logger LOGGER = LogUtils.getLogger(); + private static final EntityDataAccessor DATA_VILLAGER_DATA = SynchedEntityData.defineId(Villager.class, EntityDataSerializers.VILLAGER_DATA); +@@ -145,7 +_,7 @@ + } + + public Brain getBrain() { +- return (Brain)super.getBrain(); ++ return (Brain) super.getBrain(); // CraftBukkit - decompile error + } + + protected Brain.Provider brainProvider() { +@@ -221,7 +_,7 @@ + this.increaseProfessionLevelOnUpdate = false; + } + +- this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 200, 0)); ++ this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 200, 0), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.VILLAGER_TRADE); // CraftBukkit + } + } + @@ -256,7 +_,7 @@ public InteractionResult mobInteract(Player p_35472_, InteractionHand p_35473_) { @@ -9,6 +99,36 @@ if (this.isBaby()) { this.setUnhappy(); return InteractionResult.sidedSuccess(this.level().isClientSide); +@@ -332,7 +_,13 @@ + this.updateDemand(); + + for(MerchantOffer merchantoffer : this.getOffers()) { +- merchantoffer.resetUses(); ++ // CraftBukkit start ++ VillagerReplenishTradeEvent event = new VillagerReplenishTradeEvent((org.bukkit.entity.Villager) this.getBukkitEntity(), merchantoffer.asBukkit()); ++ Bukkit.getPluginManager().callEvent(event); ++ if (!event.isCancelled()) { ++ merchantoffer.resetUses(); ++ } ++ // CraftBukkit end + } + + this.resendOffersToTradingPlayer(); +@@ -387,7 +_,13 @@ + int i = 2 - this.numberOfRestocksToday; + if (i > 0) { + for(MerchantOffer merchantoffer : this.getOffers()) { +- merchantoffer.resetUses(); ++ // CraftBukkit start ++ VillagerReplenishTradeEvent event = new VillagerReplenishTradeEvent((org.bukkit.entity.Villager) this.getBukkitEntity(), merchantoffer.asBukkit()); ++ Bukkit.getPluginManager().callEvent(event); ++ if (!event.isCancelled()) { ++ merchantoffer.resetUses(); ++ } ++ // CraftBukkit end + } + } + @@ -670,7 +_,8 @@ } @@ -28,11 +148,27 @@ LOGGER.info("Villager {} was struck by lightning {}.", this, p_35410_); Witch witch = EntityType.WITCH.create(p_35409_); if (witch != null) { -@@ -736,6 +_,7 @@ +@@ -736,7 +_,13 @@ } witch.setPersistenceRequired(); +- p_35409_.addFreshEntityWithPassengers(witch); + net.minecraftforge.event.ForgeEventFactory.onLivingConvert(this, witch); - p_35409_.addFreshEntityWithPassengers(witch); ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityTransformEvent(this, witch, EntityTransformEvent.TransformReason.LIGHTNING).isCancelled()) { ++ return; ++ } ++ p_35409_.addFreshEntityWithPassengers(witch, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); ++ // CraftBukkit end this.releaseAllPois(); this.discard(); + } else { +@@ -824,7 +_,7 @@ + return p_186293_.wantsToSpawnGolem(p_35399_); + }).limit(5L).collect(Collectors.toList()); + if (list1.size() >= p_35400_) { +- if (!SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, MobSpawnType.MOB_SUMMONED, p_35398_, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM).isEmpty()) { ++ if (!SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, MobSpawnType.MOB_SUMMONED, p_35398_, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE).isEmpty()) { // CraftBukkit + list.forEach(GolemSensor::golemDetected); + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/npc/WanderingTrader.java.patch b/patches/minecraft/net/minecraft/world/entity/npc/WanderingTrader.java.patch new file mode 100644 index 0000000000..0782963d0a --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/npc/WanderingTrader.java.patch @@ -0,0 +1,38 @@ +--- a/net/minecraft/world/entity/npc/WanderingTrader.java ++++ b/net/minecraft/world/entity/npc/WanderingTrader.java +@@ -45,6 +_,9 @@ + import net.minecraft.world.level.Level; + import net.minecraft.world.phys.Vec3; + import org.apache.commons.lang3.tuple.Pair; ++import org.bukkit.Bukkit; ++import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftMerchantRecipe; ++import org.bukkit.event.entity.VillagerAcquireTradeEvent; + + public class WanderingTrader extends AbstractVillager { + private static final int NUMBER_OF_TRADE_OFFERS = 5; +@@ -54,6 +_,7 @@ + + public WanderingTrader(EntityType p_35843_, Level p_35844_) { + super(p_35843_, p_35844_); ++ this.setDespawnDelay(48000); // CraftBukkit - set default from MobSpawnerTrader + } + + protected void registerGoals() { +@@ -125,7 +_,16 @@ + VillagerTrades.ItemListing villagertrades$itemlisting = avillagertrades$itemlisting1[i]; + MerchantOffer merchantoffer = villagertrades$itemlisting.getOffer(this, this.random); + if (merchantoffer != null) { +- merchantoffers.add(merchantoffer); ++ // CraftBukkit start ++ VillagerAcquireTradeEvent event = new VillagerAcquireTradeEvent((org.bukkit.entity.AbstractVillager) getBukkitEntity(), merchantoffer.asBukkit()); ++ // Suppress during worldgen ++ if (this.valid) { ++ Bukkit.getPluginManager().callEvent(event); ++ } ++ if (!event.isCancelled()) { ++ merchantoffers.add(CraftMerchantRecipe.fromBukkit(event.getRecipe()).toMinecraft()); ++ } ++ // CraftBukkit end + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch b/patches/minecraft/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch new file mode 100644 index 0000000000..1ec705150d --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch @@ -0,0 +1,28 @@ +--- a/net/minecraft/world/entity/npc/WanderingTraderSpawner.java ++++ b/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +@@ -104,14 +_,14 @@ + return false; + } + +- WanderingTrader wanderingtrader = EntityType.WANDERING_TRADER.spawn(p_35916_, blockpos2, MobSpawnType.EVENT); ++ WanderingTrader wanderingtrader = EntityType.WANDERING_TRADER.spawn(p_35916_, blockpos2, MobSpawnType.EVENT, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit + if (wanderingtrader != null) { + for(int j = 0; j < 2; ++j) { + this.tryToSpawnLlamaFor(p_35916_, wanderingtrader, 4); + } + + this.serverLevelData.setWanderingTraderId(wanderingtrader.getUUID()); +- wanderingtrader.setDespawnDelay(48000); ++ //wanderingtrader.setDespawnDelay(48000); // CraftBukkit - moved to EntityVillagerTrader constructor. This lets the value be modified by plugins on CreatureSpawnEvent + wanderingtrader.setWanderTarget(blockpos1); + wanderingtrader.restrictTo(blockpos1, 16); + return true; +@@ -125,7 +_,7 @@ + private void tryToSpawnLlamaFor(ServerLevel p_35918_, WanderingTrader p_35919_, int p_35920_) { + BlockPos blockpos = this.findSpawnPositionNear(p_35918_, p_35919_.blockPosition(), p_35920_); + if (blockpos != null) { +- TraderLlama traderllama = EntityType.TRADER_LLAMA.spawn(p_35918_, blockpos, MobSpawnType.EVENT); ++ TraderLlama traderllama = EntityType.TRADER_LLAMA.spawn(p_35918_, blockpos, MobSpawnType.EVENT, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit + if (traderllama != null) { + traderllama.setLeashedTo(p_35919_, true); + } From 75d2fede5bfff7498fa70ab31afbf2d35e12f159 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 18:08:46 +0100 Subject: [PATCH 05/26] Item entity patches --- .../entity/item/FallingBlockEntity.java.patch | 52 ++++++++ .../world/entity/item/ItemEntity.java.patch | 124 +++++++++++++++++- .../world/entity/item/PrimedTnt.java.patch | 51 +++++++ 3 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 patches/minecraft/net/minecraft/world/entity/item/PrimedTnt.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/item/FallingBlockEntity.java.patch b/patches/minecraft/net/minecraft/world/entity/item/FallingBlockEntity.java.patch index a5645f111c..59b93f931c 100644 --- a/patches/minecraft/net/minecraft/world/entity/item/FallingBlockEntity.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/item/FallingBlockEntity.java.patch @@ -1,5 +1,33 @@ --- a/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/net/minecraft/world/entity/item/FallingBlockEntity.java +@@ -44,6 +_,7 @@ + import net.minecraft.world.phys.BlockHitResult; + import net.minecraft.world.phys.HitResult; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; + import org.slf4j.Logger; + + public class FallingBlockEntity extends Entity { +@@ -76,9 +_,17 @@ + } + + public static FallingBlockEntity fall(Level p_201972_, BlockPos p_201973_, BlockState p_201974_) { +- FallingBlockEntity fallingblockentity = new FallingBlockEntity(p_201972_, (double)p_201973_.getX() + 0.5D, (double)p_201973_.getY(), (double)p_201973_.getZ() + 0.5D, p_201974_.hasProperty(BlockStateProperties.WATERLOGGED) ? p_201974_.setValue(BlockStateProperties.WATERLOGGED, Boolean.valueOf(false)) : p_201974_); ++ // CraftBukkit start ++ return fall(p_201972_, p_201973_, p_201974_, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); ++ } ++ ++ public static FallingBlockEntity fall(Level p_201972_, BlockPos p_201973_, BlockState p_201974_, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { ++ // CraftBukkit end ++ FallingBlockEntity fallingblockentity = new FallingBlockEntity(p_201972_, (double) p_201973_.getX() + 0.5D, (double) p_201973_.getY(), (double) p_201973_.getZ() + 0.5D, p_201974_.hasProperty(BlockStateProperties.WATERLOGGED) ? (BlockState) p_201974_.setValue(BlockStateProperties.WATERLOGGED, false) : p_201974_); ++ if (!CraftEventFactory.callEntityChangeBlockEvent(fallingblockentity, p_201973_, p_201974_.getFluidState().createLegacyBlock())) return fallingblockentity; // CraftBukkit ++ + p_201972_.setBlock(p_201973_, p_201974_.getFluidState().createLegacyBlock(), 3); +- p_201972_.addFreshEntity(fallingblockentity); ++ p_201972_.addFreshEntity(fallingblockentity, spawnReason); // CraftBukkit + return fallingblockentity; + } + @@ -120,11 +_,11 @@ if (!this.level().isClientSide) { BlockPos blockpos = this.blockPosition(); @@ -14,3 +42,27 @@ blockpos = blockhitresult.getBlockPos(); flag1 = true; } +@@ -151,6 +_,13 @@ + this.blockState = this.blockState.setValue(BlockStateProperties.WATERLOGGED, Boolean.valueOf(true)); + } + ++ // CraftBukkit start ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockpos, this.blockState)) { ++ this.discard(); // SPIGOT-6586 called before the event in previous versions ++ return; ++ } ++ // CraftBukkit end ++ + if (this.level().setBlock(blockpos, this.blockState, 3)) { + ((ServerLevel)this.level()).getChunkSource().chunkMap.broadcast(this, new ClientboundBlockUpdatePacket(blockpos, this.level().getBlockState(blockpos))); + this.discard(); +@@ -228,7 +_,9 @@ + DamageSource damagesource = damagesource1; + float f = (float)Math.min(Mth.floor((float)i * this.fallDamagePerDistance), this.fallDamageMax); + this.level().getEntities(this, this.getBoundingBox(), predicate).forEach((p_149649_) -> { ++ CraftEventFactory.entityDamage = this; // CraftBukkit + p_149649_.hurt(damagesource, f); ++ CraftEventFactory.entityDamage = null; // CraftBukkit + }); + boolean flag = this.blockState.is(BlockTags.ANVIL); + if (flag && f > 0.0F && this.random.nextFloat() < 0.05F + (float)i * 0.05F) { diff --git a/patches/minecraft/net/minecraft/world/entity/item/ItemEntity.java.patch b/patches/minecraft/net/minecraft/world/entity/item/ItemEntity.java.patch index de6bcb6d64..fc2fbaf345 100644 --- a/patches/minecraft/net/minecraft/world/entity/item/ItemEntity.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/item/ItemEntity.java.patch @@ -1,9 +1,28 @@ --- a/net/minecraft/world/entity/item/ItemEntity.java +++ b/net/minecraft/world/entity/item/ItemEntity.java -@@ -42,6 +_,10 @@ +@@ -9,6 +_,7 @@ + import net.minecraft.network.syncher.EntityDataAccessor; + import net.minecraft.network.syncher.EntityDataSerializers; + import net.minecraft.network.syncher.SynchedEntityData; ++import net.minecraft.server.MinecraftServer; + import net.minecraft.server.level.ServerLevel; + import net.minecraft.sounds.SoundSource; + import net.minecraft.stats.Stats; +@@ -28,6 +_,9 @@ + import net.minecraft.world.level.Level; + import net.minecraft.world.level.gameevent.GameEvent; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityPickupItemEvent; ++import org.bukkit.event.player.PlayerPickupItemEvent; + + public class ItemEntity extends Entity implements TraceableEntity { + private static final EntityDataAccessor DATA_ITEM = SynchedEntityData.defineId(ItemEntity.class, EntityDataSerializers.ITEM_STACK); +@@ -42,6 +_,11 @@ @Nullable private UUID target; public final float bobOffs; ++ private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit + /** + * The maximum age of this EntityItem. The item is expired once this is reached. + */ @@ -27,7 +46,7 @@ } public boolean dampensVibrations() { -@@ -94,6 +_,7 @@ +@@ -94,19 +_,26 @@ } public void tick() { @@ -35,7 +54,19 @@ if (this.getItem().isEmpty()) { this.discard(); } else { -@@ -107,6 +_,9 @@ + super.tick(); +- if (this.pickupDelay > 0 && this.pickupDelay != 32767) { +- --this.pickupDelay; +- } ++ // CraftBukkit start - Use wall time for pickup and despawn timers ++ int elapsedTicks = MinecraftServer.currentTick - this.lastTick; ++ if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks; ++ if (this.age != -32768) this.age += elapsedTicks; ++ this.lastTick = MinecraftServer.currentTick; ++ // CraftBukkit end + + this.xo = this.getX(); + this.yo = this.getY(); this.zo = this.getZ(); Vec3 vec3 = this.getDeltaMovement(); float f = this.getEyeHeight() - 0.11111111F; @@ -55,7 +86,22 @@ } this.setDeltaMovement(this.getDeltaMovement().multiply((double)f1, 0.98D, (double)f1)); -@@ -158,7 +_,16 @@ +@@ -146,9 +_,11 @@ + this.mergeWithNeighbours(); + } + +- if (this.age != -32768) { +- ++this.age; +- } ++ /* CraftBukkit start - moved up ++ if (this.age != -32768) { ++ ++this.age; ++ } ++ // CraftBukkit end */ + + this.hasImpulse |= this.updateInWaterStateAndDoFluidPushing(); + if (!this.level().isClientSide) { +@@ -158,7 +_,22 @@ } } @@ -64,6 +110,12 @@ + if (!this.level().isClientSide && this.age >= lifespan) { + int hook = net.minecraftforge.event.ForgeEventFactory.onItemExpire(this, item); + if (hook < 0) { ++ // CraftBukkit start - fire ItemDespawnEvent ++ if (CraftEventFactory.callItemDespawnEvent(this).isCancelled()) { ++ this.age = 0; ++ return; ++ } ++ // CraftBukkit end + this.discard(); + } else { + this.lifespan += hook; @@ -82,7 +134,28 @@ } else { return !p_32028_.hasTag() || p_32028_.getTag().equals(p_32027_.getTag()); } -@@ -265,7 +_,7 @@ +@@ -238,6 +_,11 @@ + } + + private static void merge(ItemEntity p_32018_, ItemStack p_32019_, ItemEntity p_32020_, ItemStack p_32021_) { ++ // CraftBukkit start ++ if (!CraftEventFactory.callItemMergeEvent(p_32018_, p_32020_)) { ++ return; ++ } ++ // CraftBukkit end + merge(p_32018_, p_32019_, p_32021_); + p_32018_.pickupDelay = Math.max(p_32018_.pickupDelay, p_32020_.pickupDelay); + p_32018_.age = Math.min(p_32018_.age, p_32020_.age); +@@ -261,11 +_,16 @@ + } else if (this.level().isClientSide) { + return true; + } else { ++ // CraftBukkit start ++ if (CraftEventFactory.handleNonLivingEntityDamageEvent(this, p_32013_, p_32014_)) { ++ return false; ++ } ++ // CraftBukkit end + this.markHurt(); this.health = (int)((float)this.health - p_32014_); this.gameEvent(GameEvent.ENTITY_DAMAGE, p_32013_.getEntity()); if (this.health <= 0) { @@ -109,7 +182,7 @@ if (p_32034_.hasUUID("Owner")) { this.target = p_32034_.getUUID("Owner"); -@@ -316,10 +_,17 @@ +@@ -316,10 +_,56 @@ public void playerTouch(Player p_32040_) { if (!this.level().isClientSide) { @@ -120,6 +193,45 @@ - if (this.pickupDelay == 0 && (this.target == null || this.target.equals(p_32040_.getUUID())) && p_32040_.getInventory().add(itemstack)) { + int hook = net.minecraftforge.event.ForgeEventFactory.onItemPickup(this, p_32040_); + if (hook < 0) return; ++ // CraftBukkit start - fire PlayerPickupItemEvent ++ int canHold = p_32040_.getInventory().canHold(itemstack); ++ int remaining = i - canHold; ++ ++ if (this.pickupDelay <= 0 && canHold > 0) { ++ itemstack.setCount(canHold); ++ // Call legacy event ++ PlayerPickupItemEvent playerEvent = new PlayerPickupItemEvent((org.bukkit.entity.Player) p_32040_.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); ++ playerEvent.setCancelled(!playerEvent.getPlayer().getCanPickupItems()); ++ this.level().getCraftServer().getPluginManager().callEvent(playerEvent); ++ if (playerEvent.isCancelled()) { ++ itemstack.setCount(i); // SPIGOT-5294 - restore count ++ return; ++ } ++ ++ // Call newer event afterwards ++ EntityPickupItemEvent entityEvent = new EntityPickupItemEvent((org.bukkit.entity.Player) p_32040_.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining); ++ entityEvent.setCancelled(!entityEvent.getEntity().getCanPickupItems()); ++ this.level().getCraftServer().getPluginManager().callEvent(entityEvent); ++ if (entityEvent.isCancelled()) { ++ itemstack.setCount(i); // SPIGOT-5294 - restore count ++ return; ++ } ++ ++ // Update the ItemStack if it was changed in the event ++ ItemStack current = this.getItem(); ++ if (!itemstack.equals(current)) { ++ itemstack = current; ++ } else { ++ itemstack.setCount(canHold + remaining); // = i ++ } ++ ++ // Possibly < 0; fix here so we do not have to modify code below ++ this.pickupDelay = 0; ++ } else if (this.pickupDelay == 0) { ++ // ensure that the code below isn't triggered if canHold says we can't pick the items up ++ this.pickupDelay = -1; ++ } ++ // CraftBukkit end + ItemStack copy = itemstack.copy(); + if (this.pickupDelay == 0 && (this.target == null || this.target.equals(p_32040_.getUUID())) && (hook == 1 || i <= 0 || p_32040_.getInventory().add(itemstack))) { + i = copy.getCount() - itemstack.getCount(); diff --git a/patches/minecraft/net/minecraft/world/entity/item/PrimedTnt.java.patch b/patches/minecraft/net/minecraft/world/entity/item/PrimedTnt.java.patch new file mode 100644 index 0000000000..4fe7be998c --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/item/PrimedTnt.java.patch @@ -0,0 +1,51 @@ +--- a/net/minecraft/world/entity/item/PrimedTnt.java ++++ b/net/minecraft/world/entity/item/PrimedTnt.java +@@ -14,12 +_,16 @@ + import net.minecraft.world.entity.Pose; + import net.minecraft.world.entity.TraceableEntity; + import net.minecraft.world.level.Level; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.ExplosionPrimeEvent; + + public class PrimedTnt extends Entity implements TraceableEntity { + private static final EntityDataAccessor DATA_FUSE_ID = SynchedEntityData.defineId(PrimedTnt.class, EntityDataSerializers.INT); + private static final int DEFAULT_FUSE_TIME = 80; + @Nullable + private LivingEntity owner; ++ public float yield = 4; // CraftBukkit - add field ++ public boolean isIncendiary = false; // CraftBukkit - add field + + public PrimedTnt(EntityType p_32076_, Level p_32077_) { + super(p_32076_, p_32077_); +@@ -64,10 +_,13 @@ + int i = this.getFuse() - 1; + this.setFuse(i); + if (i <= 0) { +- this.discard(); ++ // CraftBukkit start - Need to reverse the order of the explosion and the entity death so we have a location for the event ++ // this.discard(); + if (!this.level().isClientSide) { + this.explode(); + } ++ this.discard(); ++ // CraftBukkit end + } else { + this.updateInWaterStateAndDoFluidPushing(); + if (this.level().isClientSide) { +@@ -78,8 +_,14 @@ + } + + protected void explode() { +- float f = 4.0F; +- this.level().explode(this, this.getX(), this.getY(0.0625D), this.getZ(), 4.0F, Level.ExplosionInteraction.TNT); ++ // CraftBukkit start ++ // float f = 4.0F; ++ ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent((org.bukkit.entity.Explosive)this.getBukkitEntity()); ++ ++ if (!event.isCancelled()) { ++ this.level().explode(this, this.getX(), this.getY(0.0625D), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.TNT); ++ } ++ // CraftBukkit end + } + + protected void addAdditionalSaveData(CompoundTag p_32097_) { From 098f999b191f9e0c418200e2b2b198feb5d3ae56 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 18:40:38 +0100 Subject: [PATCH 06/26] Player entity patches --- .../entity/animal/camel/Camel.java.patch | 9 + .../world/entity/player/Inventory.java.patch | 101 ++++ .../world/entity/player/Player.java.patch | 516 +++++++++++++++++- 3 files changed, 613 insertions(+), 13 deletions(-) diff --git a/patches/minecraft/net/minecraft/world/entity/animal/camel/Camel.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/camel/Camel.java.patch index 88ef86ceac..58ca6114a4 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/camel/Camel.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/camel/Camel.java.patch @@ -9,3 +9,12 @@ this.playSound(SoundEvents.CAMEL_STEP_SAND, 1.0F, 1.0F); } else { this.playSound(SoundEvents.CAMEL_STEP, 1.0F, 1.0F); +@@ -410,7 +_,7 @@ + + protected void actuallyHurt(DamageSource p_250410_, float p_251451_) { + this.standUpInstantly(); +- super.actuallyHurt(p_250410_, p_251451_); ++ super.damageEntity0(p_250410_, p_251451_); + } + + protected Vector3f getPassengerAttachmentPoint(Entity p_298535_, EntityDimensions p_298993_, float p_301011_) { diff --git a/patches/minecraft/net/minecraft/world/entity/player/Inventory.java.patch b/patches/minecraft/net/minecraft/world/entity/player/Inventory.java.patch index 82240ca4a3..f7647e2642 100644 --- a/patches/minecraft/net/minecraft/world/entity/player/Inventory.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/player/Inventory.java.patch @@ -1,5 +1,106 @@ --- a/net/minecraft/world/entity/player/Inventory.java +++ b/net/minecraft/world/entity/player/Inventory.java +@@ -1,6 +_,8 @@ + package net.minecraft.world.entity.player; + + import com.google.common.collect.ImmutableList; ++ ++import java.util.ArrayList; + import java.util.List; + import java.util.function.Predicate; + import net.minecraft.CrashReport; +@@ -23,6 +_,10 @@ + import net.minecraft.world.item.Item; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.level.block.state.BlockState; ++import org.bukkit.Location; ++import org.bukkit.craftbukkit.v1_20_R2.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.inventory.InventoryHolder; + + public class Inventory implements Container, Nameable { + public static final int POP_TIME_DURATION = 5; +@@ -40,10 +_,80 @@ + public final Player player; + private int timesChanged; + ++ // CraftBukkit start - add fields and methods ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ public List getContents() { ++ List combined = new ArrayList(items.size() + armor.size() + offhand.size()); ++ for (List sub : this.compartments) { ++ combined.addAll(sub); ++ } ++ ++ return combined; ++ } ++ ++ public List getArmorContents() { ++ return this.armor; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public org.bukkit.inventory.InventoryHolder getOwner() { ++ return this.player.getBukkitEntity(); ++ } ++ ++ @Override ++ public int getMaxStackSize() { ++ return maxStack; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ ++ @Override ++ public Location getLocation() { ++ return player.getBukkitEntity().getLocation(); ++ } ++ // CraftBukkit end ++ + public Inventory(Player p_35983_) { + this.player = p_35983_; + } + ++ // CraftBukkit start - Watch method above! :D ++ public int canHold(ItemStack itemstack) { ++ int remains = itemstack.getCount(); ++ for (int i = 0; i < this.items.size(); ++i) { ++ ItemStack itemstack1 = this.getItem(i); ++ if (itemstack1.isEmpty()) return itemstack.getCount(); ++ ++ if (this.hasRemainingSpaceForItem(itemstack1, itemstack)) { ++ remains -= (itemstack1.getMaxStackSize() < this.getMaxStackSize() ? itemstack1.getMaxStackSize() : this.getMaxStackSize()) - itemstack1.getCount(); ++ } ++ if (remains <= 0) return itemstack.getCount(); ++ } ++ ItemStack offhandItemStack = this.getItem(this.items.size() + this.armor.size()); ++ if (this.hasRemainingSpaceForItem(offhandItemStack, itemstack)) { ++ remains -= (offhandItemStack.getMaxStackSize() < this.getMaxStackSize() ? offhandItemStack.getMaxStackSize() : this.getMaxStackSize()) - offhandItemStack.getCount(); ++ } ++ if (remains <= 0) return itemstack.getCount(); ++ ++ return itemstack.getCount() - remains; ++ } ++ // CraftBukkit end ++ + public ItemStack getSelected() { + return isHotbarSlot(this.selected) ? this.items.get(this.selected) : ItemStack.EMPTY; + } @@ -130,7 +_,7 @@ for(int k = 0; k < 9; ++k) { diff --git a/patches/minecraft/net/minecraft/world/entity/player/Player.java.patch b/patches/minecraft/net/minecraft/world/entity/player/Player.java.patch index 4254907554..8594d2b387 100644 --- a/patches/minecraft/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/player/Player.java.patch @@ -1,7 +1,31 @@ --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java -@@ -114,7 +_,8 @@ +@@ -84,12 +_,7 @@ + import net.minecraft.world.inventory.ClickAction; + import net.minecraft.world.inventory.InventoryMenu; + import net.minecraft.world.inventory.PlayerEnderChestContainer; +-import net.minecraft.world.item.ElytraItem; +-import net.minecraft.world.item.ItemCooldowns; +-import net.minecraft.world.item.ItemStack; +-import net.minecraft.world.item.Items; +-import net.minecraft.world.item.ProjectileWeaponItem; +-import net.minecraft.world.item.SwordItem; ++import net.minecraft.world.item.*; + import net.minecraft.world.item.crafting.RecipeHolder; + import net.minecraft.world.item.enchantment.EnchantmentHelper; + import net.minecraft.world.item.trading.MerchantOffers; +@@ -112,9 +_,18 @@ + import net.minecraft.world.scores.PlayerTeam; + import net.minecraft.world.scores.Scoreboard; import net.minecraft.world.scores.Team; ++import org.bukkit.craftbukkit.v1_20_R2.entity.CraftHumanEntity; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.craftbukkit.v1_20_R2.util.CraftVector; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.bukkit.event.entity.EntityCombustByEntityEvent; ++import org.bukkit.event.entity.EntityExhaustionEvent; ++import org.bukkit.event.player.PlayerDropItemEvent; ++import org.bukkit.event.player.PlayerVelocityEvent; import org.slf4j.Logger; -public abstract class Player extends LivingEntity { @@ -10,13 +34,36 @@ private static final Logger LOGGER = LogUtils.getLogger(); public static final int MAX_NAME_LENGTH = 16; public static final HumanoidArm DEFAULT_MAIN_HAND = HumanoidArm.RIGHT; -@@ -169,6 +_,9 @@ +@@ -138,10 +_,10 @@ + protected static final EntityDataAccessor DATA_SHOULDER_RIGHT = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG); + private long timeEntitySatOnShoulder; + private final Inventory inventory = new Inventory(this); +- protected PlayerEnderChestContainer enderChestInventory = new PlayerEnderChestContainer(); ++ protected PlayerEnderChestContainer enderChestInventory = new PlayerEnderChestContainer(this); // CraftBukkit - add "this" to constructor + public final InventoryMenu inventoryMenu; + public AbstractContainerMenu containerMenu; +- protected FoodData foodData = new FoodData(); ++ protected FoodData foodData = new FoodData(this); // CraftBukkit - add "this" to constructor + protected int jumpTriggerTime; + public float oBob; + public float bob; +@@ -169,6 +_,19 @@ @Nullable public FishingHook fishing; protected float hurtDir; + private final java.util.Collection prefixes = new java.util.LinkedList<>(); + private final java.util.Collection suffixes = new java.util.LinkedList<>(); + @Nullable private Pose forcedPose; ++ ++ // CraftBukkit start ++ public boolean fauxSleeping; ++ public int oldLevel = -1; ++ ++ @Override ++ public CraftHumanEntity getBukkitEntity() { ++ return (CraftHumanEntity) super.getBukkitEntity(); ++ } ++ // CraftBukkit end public Player(Level p_250508_, BlockPos p_250289_, float p_251702_, GameProfile p_252153_) { super(EntityType.PLAYER, p_250508_); @@ -54,6 +101,15 @@ } public boolean isSecondaryUseActive() { +@@ -300,7 +_,7 @@ + private void turtleHelmetTick() { + ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); + if (itemstack.is(Items.TURTLE_HELMET) && !this.isEyeInFluid(FluidTags.WATER)) { +- this.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 200, 0, false, false, true)); ++ this.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 200, 0, false, false, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TURTLE_HELMET); // CraftBukkit + } + + } @@ -353,6 +_,10 @@ } @@ -65,6 +121,31 @@ if (this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.SWIMMING)) { Pose pose; if (this.isFallFlying()) { +@@ -458,8 +_,13 @@ + public void rideTick() { + if (!this.level().isClientSide && this.wantsToStopRiding() && this.isPassenger()) { + this.stopRiding(); +- this.setShiftKeyDown(false); ++ // CraftBukkit start - SPIGOT-7316: no longer passenger, dismount and return ++ if (!this.isPassenger()) { ++ this.setShiftKeyDown(false); ++ return; ++ } + } else { ++ // CraftBukkit end + double d0 = this.getX(); + double d1 = this.getY(); + double d2 = this.getZ(); +@@ -483,7 +_,8 @@ + + if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.level().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION)) { + if (this.getHealth() < this.getMaxHealth() && this.tickCount % 20 == 0) { +- this.heal(1.0F); ++ // CraftBukkit - added regain reason of "REGEN" for filtering purposes. ++ this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); + } + + if (this.foodData.needsFood() && this.tickCount % 10 == 0) { @@ -577,6 +_,7 @@ } @@ -73,7 +154,7 @@ super.die(p_36152_); this.reapplyPosition(); if (!this.isSpectator()) { -@@ -626,7 +_,7 @@ +@@ -626,11 +_,17 @@ @Nullable public ItemEntity drop(ItemStack p_36177_, boolean p_36178_) { @@ -82,7 +163,48 @@ } @Nullable -@@ -664,7 +_,12 @@ + public ItemEntity drop(ItemStack p_36179_, boolean p_36180_, boolean p_36181_) { ++ // CraftBukkit start - SPIGOT-2942: Add boolean to call event ++ return drop(p_36179_, p_36180_, p_36181_, true); ++ } ++ ++ @Nullable ++ public ItemEntity drop(ItemStack p_36179_, boolean p_36180_, boolean p_36181_, boolean callEvent) { + if (p_36179_.isEmpty()) { + return null; + } else { +@@ -660,11 +_,43 @@ + itementity.setDeltaMovement((double)(-f3 * f2 * 0.3F) + Math.cos((double)f5) * (double)f6, (double)(-f8 * 0.3F + 0.1F + (this.random.nextFloat() - this.random.nextFloat()) * 0.1F), (double)(f4 * f2 * 0.3F) + Math.sin((double)f5) * (double)f6); + } + ++ // CraftBukkit start - fire PlayerDropItemEvent ++ if (!callEvent) { // SPIGOT-2942: Add boolean to call event ++ return itementity; ++ } ++ org.bukkit.entity.Player player = (org.bukkit.entity.Player) this.getBukkitEntity(); ++ org.bukkit.entity.Item drop = (org.bukkit.entity.Item) itementity.getBukkitEntity(); ++ ++ PlayerDropItemEvent event = new PlayerDropItemEvent(player, drop); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ org.bukkit.inventory.ItemStack cur = player.getInventory().getItemInHand(); ++ if (p_36181_ && (cur == null || cur.getAmount() == 0)) { ++ // The complete stack was dropped ++ player.getInventory().setItemInHand(drop.getItemStack()); ++ } else if (p_36181_ && cur.isSimilar(drop.getItemStack()) && cur.getAmount() < cur.getMaxStackSize() && drop.getItemStack().getAmount() == 1) { ++ // Only one item is dropped ++ cur.setAmount(cur.getAmount() + 1); ++ player.getInventory().setItemInHand(cur); ++ } else { ++ // Fallback ++ player.getInventory().addItem(drop.getItemStack()); ++ } ++ return null; ++ } ++ // CraftBukkit end ++ + return itementity; } } @@ -117,7 +239,36 @@ if (this.isInvulnerableTo(p_36154_)) { return false; } else if (this.abilities.invulnerable && !p_36154_.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { -@@ -830,7 +_,7 @@ +@@ -806,12 +_,13 @@ + return false; + } else { + if (!this.level().isClientSide) { +- this.removeEntitiesOnShoulder(); ++ // this.removeEntitiesOnShoulder(); // CraftBukkit - moved down + } + + if (p_36154_.scalesWithDifficulty()) { + if (this.level().getDifficulty() == Difficulty.PEACEFUL) { + p_36155_ = 0.0F; ++ return false; // CraftBukkit - f = 0.0f -> return false + } + + if (this.level().getDifficulty() == Difficulty.EASY) { +@@ -823,14 +_,20 @@ + } + } + +- return p_36155_ == 0.0F ? false : super.hurt(p_36154_, p_36155_); ++ // CraftBukkit start - Don't filter out 0 damage ++ boolean damaged = super.hurt(p_36154_, p_36155_); ++ if (damaged) { ++ this.removeEntitiesOnShoulder(); ++ } ++ return damaged; ++ // CraftBukkit end + } + } + } protected void blockUsingShield(LivingEntity p_36295_) { super.blockUsingShield(p_36295_); @@ -126,6 +277,42 @@ this.disableShield(true); } +@@ -841,13 +_,29 @@ + } + + public boolean canHarmPlayer(Player p_36169_) { +- Team team = this.getTeam(); +- Team team1 = p_36169_.getTeam(); +- if (team == null) { +- return true; ++ // CraftBukkit start - Change to check OTHER player's scoreboard team according to API ++ // To summarize this method's logic, it's "Can parameter hurt this" ++ org.bukkit.scoreboard.Team team; ++ if (p_36169_ instanceof ServerPlayer) { ++ ServerPlayer thatPlayer = (ServerPlayer) p_36169_; ++ team = thatPlayer.getBukkitEntity().getScoreboard().getPlayerTeam(thatPlayer.getBukkitEntity()); ++ if (team == null || team.allowFriendlyFire()) { ++ return true; ++ } + } else { +- return !team.isAlliedTo(team1) ? true : team.isAllowFriendlyFire(); +- } ++ // This should never be called, but is implemented anyway ++ org.bukkit.OfflinePlayer thisPlayer = p_36169_.level().getCraftServer().getOfflinePlayer(p_36169_.getScoreboardName()); ++ team = p_36169_.level().getCraftServer().getScoreboardManager().getMainScoreboard().getPlayerTeam(thisPlayer); ++ if (team == null || team.allowFriendlyFire()) { ++ return true; ++ } ++ } ++ ++ if (this instanceof ServerPlayer) { ++ return !team.hasPlayer(((ServerPlayer) this).getBukkitEntity()); ++ } ++ return !team.hasPlayer(this.level().getCraftServer().getOfflinePlayer(this.getScoreboardName())); ++ // CraftBukkit end + } + + protected void hurtArmor(DamageSource p_36251_, float p_36252_) { @@ -859,7 +_,7 @@ } @@ -144,12 +331,20 @@ }); if (this.useItem.isEmpty()) { if (interactionhand == InteractionHand.MAIN_HAND) { -@@ -887,10 +_,13 @@ +@@ -885,19 +_,27 @@ + } + } - protected void actuallyHurt(DamageSource p_36312_, float p_36313_) { +- protected void actuallyHurt(DamageSource p_36312_, float p_36313_) { ++ // CraftBukkit start ++ protected boolean damageEntity0(DamageSource p_36312_, float p_36313_) { ++ if (true) { ++ return super.damageEntity0(p_36312_, p_36313_); ++ } ++ // CraftBukkit end if (!this.isInvulnerableTo(p_36312_)) { + p_36313_ = net.minecraftforge.common.ForgeHooks.onLivingHurt(this, p_36312_, p_36313_); -+ if (p_36313_ <= 0) return; ++ if (p_36313_ <= 0) return false; p_36313_ = this.getDamageAfterArmorAbsorb(p_36312_, p_36313_); p_36313_ = this.getDamageAfterMagicAbsorb(p_36312_, p_36313_); float f1 = Math.max(p_36313_ - this.getAbsorptionAmount(), 0.0F); @@ -158,6 +353,23 @@ float f = p_36313_ - f1; if (f > 0.0F && f < 3.4028235E37F) { this.awardStat(Stats.DAMAGE_ABSORBED, Math.round(f * 10.0F)); + } + + if (f1 != 0.0F) { +- this.causeFoodExhaustion(p_36312_.getFoodExhaustion()); ++ this.causeFoodExhaustion(p_36312_.getFoodExhaustion(), EntityExhaustionEvent.ExhaustionReason.DAMAGED); // CraftBukkit - EntityExhaustionEvent + this.getCombatTracker().recordDamage(p_36312_, f1); + this.setHealth(this.getHealth() - f1); + if (f1 < 3.4028235E37F) { +@@ -907,6 +_,8 @@ + this.gameEvent(GameEvent.ENTITY_DAMAGE); + } + } ++ ++ return false; // CraftBukkit + } + + protected boolean onSoulSpeedBlock() { @@ -953,6 +_,8 @@ return InteractionResult.PASS; @@ -252,18 +464,74 @@ } float f4 = 0.0F; -@@ -1125,8 +_,9 @@ +@@ -1103,8 +_,15 @@ + if (p_36347_ instanceof LivingEntity) { + f4 = ((LivingEntity)p_36347_).getHealth(); + if (j > 0 && !p_36347_.isOnFire()) { +- flag4 = true; +- p_36347_.setSecondsOnFire(1); ++ // CraftBukkit start - Call a combust event when somebody hits with a fire enchanted item ++ EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), p_36347_.getBukkitEntity(), 1); ++ org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent); ++ ++ if (!combustEvent.isCancelled()) { ++ flag4 = true; ++ p_36347_.setSecondsOnFire(combustEvent.getDuration(), false); ++ } ++ // CraftBukkit end + } + } + +@@ -1125,10 +_,15 @@ if (flag3) { float f3 = 1.0F + EnchantmentHelper.getSweepingDamageRatio(this) * f; - for(LivingEntity livingentity : this.level().getEntitiesOfClass(LivingEntity.class, p_36347_.getBoundingBox().inflate(1.0D, 0.25D, 1.0D))) { - if (livingentity != this && livingentity != p_36347_ && !this.isAlliedTo(livingentity) && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).isMarker()) && this.distanceToSqr(livingentity) < 9.0D) { +- livingentity.knockback((double)0.4F, (double)Mth.sin(this.getYRot() * ((float)Math.PI / 180F)), (double)(-Mth.cos(this.getYRot() * ((float)Math.PI / 180F)))); +- livingentity.hurt(this.damageSources().playerAttack(this), f3); + for(LivingEntity livingentity : this.level().getEntitiesOfClass(LivingEntity.class, this.getItemInHand(InteractionHand.MAIN_HAND).getSweepHitBox(this, p_36347_))) { + double entityReachSq = Mth.square(this.getEntityReach()); // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks. + if (livingentity != this && livingentity != p_36347_ && !this.isAlliedTo(livingentity) && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).isMarker()) && this.distanceToSqr(livingentity) < entityReachSq) { - livingentity.knockback((double)0.4F, (double)Mth.sin(this.getYRot() * ((float)Math.PI / 180F)), (double)(-Mth.cos(this.getYRot() * ((float)Math.PI / 180F)))); - livingentity.hurt(this.damageSources().playerAttack(this), f3); ++ // CraftBukkit start - Only apply knockback if the damage hits ++ if (livingentity.hurt(this.damageSources().playerAttack(this).sweep(), f4)) { ++ livingentity.knockback((double) 0.4F, (double) Mth.sin(this.getYRot() * ((float) Math.PI / 180F)), (double) (-Mth.cos(this.getYRot() * ((float) Math.PI / 180F)))); ++ ++ } ++ // CraftBukkit end } + } + +@@ -1137,9 +_,26 @@ + } + + if (p_36347_ instanceof ServerPlayer && p_36347_.hurtMarked) { +- ((ServerPlayer)p_36347_).connection.send(new ClientboundSetEntityMotionPacket(p_36347_)); +- p_36347_.hurtMarked = false; +- p_36347_.setDeltaMovement(vec3); ++ // CraftBukkit start - Add Velocity Event ++ boolean cancelled = false; ++ org.bukkit.entity.Player player = (org.bukkit.entity.Player) p_36347_.getBukkitEntity(); ++ org.bukkit.util.Vector velocity = CraftVector.toBukkit(vec3); ++ ++ PlayerVelocityEvent event = new PlayerVelocityEvent(player, velocity.clone()); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ cancelled = true; ++ } else if (!velocity.equals(event.getVelocity())) { ++ player.setVelocity(event.getVelocity()); ++ } ++ ++ if (!cancelled) { ++ ((ServerPlayer)p_36347_).connection.send(new ClientboundSetEntityMotionPacket(p_36347_)); ++ p_36347_.hurtMarked = false; ++ p_36347_.setDeltaMovement(vec3); ++ } ++ // CraftBukkit end + } + + if (flag2) { @@ -1167,13 +_,15 @@ EnchantmentHelper.doPostDamageEffects(this, p_36347_); ItemStack itemstack1 = this.getMainHandItem(); @@ -282,8 +550,38 @@ this.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); } } -@@ -1199,6 +_,7 @@ +@@ -1182,7 +_,14 @@ + float f5 = f4 - ((LivingEntity)p_36347_).getHealth(); + this.awardStat(Stats.DAMAGE_DEALT, Math.round(f5 * 10.0F)); + if (j > 0) { +- p_36347_.setSecondsOnFire(j * 4); ++ // CraftBukkit start - Call a combust event when somebody hits with a fire enchanted item ++ EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), j * 4); ++ org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent); ++ ++ if (!combustEvent.isCancelled()) { ++ entity.setSecondsOnFire(combustEvent.getDuration(), false); ++ } ++ // CraftBukkit end + } + + if (this.level() instanceof ServerLevel && f5 > 2.0F) { +@@ -1191,14 +_,20 @@ + } } + +- this.causeFoodExhaustion(0.1F); ++ this.causeFoodExhaustion(0.1F, EntityExhaustionEvent.ExhaustionReason.ATTACK); // CraftBukkit - EntityExhaustionEvent + } else { + this.level().playSound((Player)null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F); + if (flag4) { + p_36347_.clearFire(); + } ++ // CraftBukkit start - resync on cancelled event ++ if (this instanceof ServerPlayer) { ++ ((ServerPlayer) this).getBukkitEntity().updateInventory(); ++ } ++ // CraftBukkit end } } + this.resetAttackStrengthTicker(); // FORGE: Moved from beginning of attack() so that getAttackStrengthScale() returns an accurate value during all attack events @@ -299,7 +597,19 @@ this.stopUsingItem(); this.level().broadcastEntityEvent(this, (byte)30); } -@@ -1279,6 +_,7 @@ +@@ -1273,12 +_,19 @@ + } + + public Either startSleepInBed(BlockPos p_36203_) { ++ // CraftBukkit start ++ return this.startSleepInBed(p_36203_, false); ++ } ++ ++ public Either startSleepInBed(BlockPos p_36203_, boolean force) { ++ // CraftBukkit end + this.startSleeping(p_36203_); + this.sleepCounter = 0; + return Either.right(Unit.INSTANCE); } public void stopSleepInBed(boolean p_36226_, boolean p_36227_) { @@ -316,6 +626,71 @@ } else { boolean flag = block.isPossibleToRespawnInThis(blockstate); BlockState blockstate1 = p_36131_.getBlockState(p_36132_.above()); +@@ -1360,9 +_,9 @@ + super.jumpFromGround(); + this.awardStat(Stats.JUMP); + if (this.isSprinting()) { +- this.causeFoodExhaustion(0.2F); ++ this.causeFoodExhaustion(0.2F, EntityExhaustionEvent.ExhaustionReason.JUMP_SPRINT); // CraftBukkit - EntityExhaustionEvent + } else { +- this.causeFoodExhaustion(0.05F); ++ this.causeFoodExhaustion(0.05F, EntityExhaustionEvent.ExhaustionReason.JUMP); // CraftBukkit - EntityExhaustionEvent + } + + } +@@ -1386,7 +_,11 @@ + Vec3 vec31 = this.getDeltaMovement(); + this.setDeltaMovement(vec31.x, d5 * 0.6D, vec31.z); + this.resetFallDistance(); +- this.setSharedFlag(7, false); ++ // CraftBukkit start ++ if (getSharedFlag(7) && !org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callToggleGlideEvent(this, false).isCancelled()) { ++ this.setSharedFlag(7, false); ++ } ++ // CraftBukkit end + } else { + super.travel(p_36359_); + } +@@ -1417,19 +_,19 @@ + int i = Math.round((float)Math.sqrt(p_36379_ * p_36379_ + p_36380_ * p_36380_ + p_36381_ * p_36381_) * 100.0F); + if (i > 0) { + this.awardStat(Stats.SWIM_ONE_CM, i); +- this.causeFoodExhaustion(0.01F * (float)i * 0.01F); ++ this.causeFoodExhaustion(0.01F * (float)i * 0.01F, EntityExhaustionEvent.ExhaustionReason.SWIM); // CraftBukkit - EntityExhaustionEvent + } + } else if (this.isEyeInFluid(FluidTags.WATER)) { + int j = Math.round((float)Math.sqrt(p_36379_ * p_36379_ + p_36380_ * p_36380_ + p_36381_ * p_36381_) * 100.0F); + if (j > 0) { + this.awardStat(Stats.WALK_UNDER_WATER_ONE_CM, j); +- this.causeFoodExhaustion(0.01F * (float)j * 0.01F); ++ this.causeFoodExhaustion(0.01F * (float)j * 0.01F, EntityExhaustionEvent.ExhaustionReason.WALK_UNDERWATER); // CraftBukkit - EntityExhaustionEvent + } + } else if (this.isInWater()) { + int k = Math.round((float)Math.sqrt(p_36379_ * p_36379_ + p_36381_ * p_36381_) * 100.0F); + if (k > 0) { + this.awardStat(Stats.WALK_ON_WATER_ONE_CM, k); +- this.causeFoodExhaustion(0.01F * (float)k * 0.01F); ++ this.causeFoodExhaustion(0.01F * (float)k * 0.01F, EntityExhaustionEvent.ExhaustionReason.WALK_ON_WATER); // CraftBukkit - EntityExhaustionEvent + } + } else if (this.onClimbable()) { + if (p_36380_ > 0.0D) { +@@ -1440,13 +_,13 @@ + if (l > 0) { + if (this.isSprinting()) { + this.awardStat(Stats.SPRINT_ONE_CM, l); +- this.causeFoodExhaustion(0.1F * (float)l * 0.01F); ++ this.causeFoodExhaustion(0.1F * (float)l * 0.01F, EntityExhaustionEvent.ExhaustionReason.SPRINT); // CraftBukkit - EntityExhaustionEvent + } else if (this.isCrouching()) { + this.awardStat(Stats.CROUCH_ONE_CM, l); +- this.causeFoodExhaustion(0.0F * (float)l * 0.01F); ++ this.causeFoodExhaustion(0.0F * (float)l * 0.01F, EntityExhaustionEvent.ExhaustionReason.CROUCH); // CraftBukkit - EntityExhaustionEvent + } else { + this.awardStat(Stats.WALK_ONE_CM, l); +- this.causeFoodExhaustion(0.0F * (float)l * 0.01F); ++ this.causeFoodExhaustion(0.0F * (float)l * 0.01F, EntityExhaustionEvent.ExhaustionReason.WALK); // CraftBukkit - EntityExhaustionEvent + } + } + } else if (this.isFallFlying()) { @@ -1485,6 +_,7 @@ public boolean causeFallDamage(float p_150093_, float p_150094_, DamageSource p_150095_) { @@ -333,6 +708,34 @@ this.startFallFlying(); return true; } +@@ -1508,12 +_,24 @@ + } + + public void startFallFlying() { +- this.setSharedFlag(7, true); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callToggleGlideEvent(this, true).isCancelled()) { ++ this.setSharedFlag(7, true); ++ } else { ++ // SPIGOT-5542: must toggle like below ++ this.setSharedFlag(7, true); ++ this.setSharedFlag(7, false); ++ } ++ // CraftBukkit end + } + + public void stopFallFlying() { +- this.setSharedFlag(7, true); +- this.setSharedFlag(7, false); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callToggleGlideEvent(this, false).isCancelled()) { ++ this.setSharedFlag(7, true); ++ this.setSharedFlag(7, false); ++ } ++ // CraftBukkit end + } + + protected void doWaterSplashEffect() { @@ -1526,13 +_,13 @@ protected void playStepSound(BlockPos p_282121_, BlockState p_282194_) { if (this.isInWater()) { @@ -380,6 +783,93 @@ this.experienceLevel += p_36276_; if (this.experienceLevel < 0) { this.experienceLevel = 0; +@@ -1622,12 +_,21 @@ + } + } + ++ // CraftBukkit start + public void causeFoodExhaustion(float p_36400_) { ++ this.causeFoodExhaustion(p_36400_, EntityExhaustionEvent.ExhaustionReason.UNKNOWN); ++ } ++ ++ public void causeFoodExhaustion(float p_36400_, EntityExhaustionEvent.ExhaustionReason reason) { + if (!this.abilities.invulnerable) { + if (!this.level().isClientSide) { +- this.foodData.addExhaustion(p_36400_); ++ // CraftBukkit start ++ EntityExhaustionEvent event = CraftEventFactory.callPlayerExhaustionEvent(this, reason, p_36400_); ++ if (!event.isCancelled()) { ++ this.foodData.addExhaustion(event.getExhaustion()); ++ } ++ // CraftBukkit end + } +- + } + } + +@@ -1708,13 +_,19 @@ + } + + public void setItemSlot(EquipmentSlot p_36161_, ItemStack p_36162_) { ++ // CraftBukkit start ++ setItemSlot(p_36161_, p_36162_, false); ++ } ++ ++ public void setItemSlot(EquipmentSlot p_36161_, ItemStack p_36162_, boolean silent) { ++ // CraftBukkit end + this.verifyEquippedItem(p_36162_); + if (p_36161_ == EquipmentSlot.MAINHAND) { +- this.onEquipItem(p_36161_, this.inventory.items.set(this.inventory.selected, p_36162_), p_36162_); ++ this.onEquipItem(p_36161_, this.inventory.items.set(this.inventory.selected, p_36162_), p_36162_, silent); // CraftBukkit + } else if (p_36161_ == EquipmentSlot.OFFHAND) { +- this.onEquipItem(p_36161_, this.inventory.offhand.set(0, p_36162_), p_36162_); ++ this.onEquipItem(p_36161_, this.inventory.offhand.set(0, p_36162_), p_36162_, silent); // CraftBukkit + } else if (p_36161_.getType() == EquipmentSlot.Type.ARMOR) { +- this.onEquipItem(p_36161_, this.inventory.armor.set(p_36161_.getIndex(), p_36162_), p_36162_); ++ this.onEquipItem(p_36161_, this.inventory.armor.set(p_36161_.getIndex(), p_36162_), p_36162_, silent); // CraftBukkit + } + + } +@@ -1751,26 +_,32 @@ + + protected void removeEntitiesOnShoulder() { + if (this.timeEntitySatOnShoulder + 20L < this.level().getGameTime()) { +- this.respawnEntityOnShoulder(this.getShoulderEntityLeft()); +- this.setShoulderEntityLeft(new CompoundTag()); +- this.respawnEntityOnShoulder(this.getShoulderEntityRight()); +- this.setShoulderEntityRight(new CompoundTag()); ++ // CraftBukkit start ++ if (this.respawnEntityOnShoulder(this.getShoulderEntityLeft())) { ++ this.setShoulderEntityLeft(new CompoundTag()); ++ } ++ if (this.respawnEntityOnShoulder(this.getShoulderEntityRight())) { ++ this.setShoulderEntityRight(new CompoundTag()); ++ } ++ // CraftBukkit end + } + + } + +- private void respawnEntityOnShoulder(CompoundTag p_36371_) { ++ private boolean respawnEntityOnShoulder(CompoundTag p_36371_) { + if (!this.level().isClientSide && !p_36371_.isEmpty()) { +- EntityType.create(p_36371_, this.level()).ifPresent((p_296858_) -> { ++ return EntityType.create(p_36371_, this.level()).map((p_296858_) -> { // CraftBukkit + if (p_296858_ instanceof TamableAnimal) { + ((TamableAnimal)p_296858_).setOwnerUUID(this.uuid); + } + + p_296858_.setPos(this.getX(), this.getY() + (double)0.7F, this.getZ()); + ((ServerLevel)this.level()).addWithUUID(p_296858_); +- }); ++ return ((ServerLevel) this.level()).addWithUUID(p_296858_, CreatureSpawnEvent.SpawnReason.SHOULDER_ENTITY); // CraftBukkit ++ }).orElse(true); // CraftBukkit + } + ++ return true; // CraftBukkit + } + + public abstract boolean isSpectator(); @@ -1794,7 +_,11 @@ } From 2d931ec4aa34580cc92a4822f753f06562dfc73b Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 18:58:36 +0100 Subject: [PATCH 07/26] Boss entity patches --- .../boss/enderdragon/EndCrystal.java.patch | 48 +++++ .../boss/enderdragon/EnderDragon.java.patch | 202 +++++++++++++++++- .../phases/EnderDragonPhaseManager.java.patch | 31 +++ .../entity/boss/wither/WitherBoss.java.patch | 96 ++++++++- 4 files changed, 368 insertions(+), 9 deletions(-) create mode 100644 patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch new file mode 100644 index 0000000000..664c36fe70 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch @@ -0,0 +1,48 @@ +--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java ++++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java +@@ -19,6 +_,8 @@ + import net.minecraft.world.level.Level; + import net.minecraft.world.level.block.BaseFireBlock; + import net.minecraft.world.level.dimension.end.EndDragonFight; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.ExplosionPrimeEvent; + + public class EndCrystal extends Entity { + private static final EntityDataAccessor> DATA_BEAM_TARGET = SynchedEntityData.defineId(EndCrystal.class, EntityDataSerializers.OPTIONAL_BLOCK_POS); +@@ -50,7 +_,11 @@ + if (this.level() instanceof ServerLevel) { + BlockPos blockpos = this.blockPosition(); + if (((ServerLevel)this.level()).getDragonFight() != null && this.level().getBlockState(blockpos).isAir()) { +- this.level().setBlockAndUpdate(blockpos, BaseFireBlock.getState(this.level(), blockpos)); ++ // CraftBukkit start ++ if (!CraftEventFactory.callBlockIgniteEvent(this.level(), blockpos, this).isCancelled()) { ++ this.level().setBlockAndUpdate(blockpos, BaseFireBlock.getState(this.level(), blockpos)); ++ } ++ // CraftBukkit end + } + } + +@@ -86,10 +_,22 @@ + return false; + } else { + if (!this.isRemoved() && !this.level().isClientSide) { ++ // CraftBukkit start - All non-living entities need this ++ if (CraftEventFactory.handleNonLivingEntityDamageEvent(this, p_31050_, p_31051_, false)) { ++ return false; ++ } ++ // CraftBukkit end + this.remove(Entity.RemovalReason.KILLED); + if (!p_31050_.is(DamageTypeTags.IS_EXPLOSION)) { + DamageSource damagesource = p_31050_.getEntity() != null ? this.damageSources().explosion(this, p_31050_.getEntity()) : null; +- this.level().explode(this, damagesource, (ExplosionDamageCalculator)null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK); ++ // CraftBukkit start ++ ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false); ++ if (event.isCancelled()) { ++ this.unsetRemoved(); ++ return false; ++ } ++ this.level().explode(this, damagesource, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK); ++ // CraftBukkit end + } + + this.onDestroyedBy(p_31050_); diff --git a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch index 86a7c52007..6519a83ed6 100644 --- a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch @@ -1,5 +1,33 @@ --- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +@@ -37,8 +_,12 @@ + import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseManager; + import net.minecraft.world.entity.monster.Enemy; + import net.minecraft.world.entity.player.Player; ++import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.level.Explosion; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.Level; ++import net.minecraft.world.level.block.Block; ++import net.minecraft.world.level.block.entity.BlockEntity; + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.level.dimension.end.EndDragonFight; + import net.minecraft.world.level.gameevent.GameEvent; +@@ -47,8 +_,14 @@ + import net.minecraft.world.level.pathfinder.BinaryHeap; + import net.minecraft.world.level.pathfinder.Node; + import net.minecraft.world.level.pathfinder.Path; ++import net.minecraft.world.level.storage.loot.LootParams; ++import net.minecraft.world.level.storage.loot.parameters.LootContextParams; + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock; ++import org.bukkit.event.block.BlockEvent; ++import org.bukkit.event.entity.EntityExplodeEvent; ++import org.bukkit.event.entity.EntityRegainHealthEvent; + import org.joml.Vector3f; + import org.slf4j.Logger; + @@ -63,7 +_,7 @@ private static final String DRAGON_PHASE_KEY = "DragonPhase"; public final double[][] positions = new double[64][3]; @@ -9,11 +37,20 @@ public final EnderDragonPart head; private final EnderDragonPart neck; private final EnderDragonPart body; -@@ -104,6 +_,14 @@ +@@ -88,6 +_,7 @@ + private final Node[] nodes = new Node[24]; + private final int[] nodeAdjacency = new int[24]; + private final BinaryHeap openSet = new BinaryHeap(); ++ private final Explosion explosionSource; // CraftBukkit - reusable source for CraftTNTPrimed.getSource() + + public EnderDragon(EntityType p_31096_, Level p_31097_) { + super(EntityType.ENDER_DRAGON, p_31097_); +@@ -104,6 +_,15 @@ this.noPhysics = true; this.noCulling = true; this.phaseManager = new EnderDragonPhaseManager(this); + this.setId(ENTITY_COUNTER.getAndAdd(this.subEntities.length + 1) + 1); // Forge: Fix MC-158205: Make sure part ids are successors of parent mob id ++ this.explosionSource = new Explosion(p_31097_, this, null, null, Double.NaN, Double.NaN, Double.NaN, Float.NaN, true, Explosion.BlockInteraction.DESTROY); // CraftBukkit + } + + @Override @@ -36,35 +73,186 @@ this.processFlappingMovement(); if (this.level().isClientSide) { this.setHealth(this.getHealth()); -@@ -433,7 +_,7 @@ +@@ -232,7 +_,7 @@ + } + + Vec3 vec3 = dragonphaseinstance.getFlyTargetLocation(); +- if (vec3 != null) { ++ if (vec3 != null && dragonphaseinstance.getPhase() != EnderDragonPhase.HOVERING) { // CraftBukkit - Don't move when hovering + double d0 = vec3.x - this.getX(); + double d1 = vec3.y - this.getY(); + double d2 = vec3.z - this.getZ(); +@@ -362,7 +_,14 @@ + if (this.nearestCrystal.isRemoved()) { + this.nearestCrystal = null; + } else if (this.tickCount % 10 == 0 && this.getHealth() < this.getMaxHealth()) { +- this.setHealth(this.getHealth() + 1.0F); ++ // CraftBukkit start ++ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), 1.0F, EntityRegainHealthEvent.RegainReason.ENDER_CRYSTAL); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.setHealth((float) (this.getHealth() + event.getAmount())); ++ } ++ // CraftBukkit end + } + } + +@@ -426,6 +_,9 @@ + int j1 = Mth.floor(p_31140_.maxZ); + boolean flag = false; + boolean flag1 = false; ++ // CraftBukkit start - Create a list to hold all the destroyed blocks ++ List destroyedBlocks = new java.util.ArrayList(); ++ // CraftBukkit end + + for(int k1 = i; k1 <= l; ++k1) { + for(int l1 = j; l1 <= i1; ++l1) { +@@ -433,8 +_,12 @@ BlockPos blockpos = new BlockPos(k1, l1, i2); BlockState blockstate = this.level().getBlockState(blockpos); if (!blockstate.isAir() && !blockstate.is(BlockTags.DRAGON_TRANSPARENT)) { - if (this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && !blockstate.is(BlockTags.DRAGON_IMMUNE)) { +- flag1 = this.level().removeBlock(blockpos, false) || flag1; + if (net.minecraftforge.common.ForgeHooks.canEntityDestroy(this.level(), blockpos, this) && !blockstate.is(BlockTags.DRAGON_IMMUNE)) { - flag1 = this.level().removeBlock(blockpos, false) || flag1; ++ // CraftBukkit start - Add blocks to list rather than destroying them ++ // flag1 = this.level().removeBlock(blockpos, false) || flag1; ++ flag1 = true; ++ destroyedBlocks.add(CraftBlock.at(this.level(), blockpos)); ++ // CraftBukkit end } else { flag = true; -@@ -524,7 +_,8 @@ + } +@@ -443,6 +_,51 @@ + } + } + ++ // CraftBukkit start - Set off an EntityExplodeEvent for the dragon exploding all these blocks ++ // SPIGOT-4882: don't fire event if nothing hit ++ if (!flag1) { ++ return flag; ++ } ++ ++ org.bukkit.entity.Entity bukkitEntity = this.getBukkitEntity(); ++ EntityExplodeEvent event = new EntityExplodeEvent(bukkitEntity, bukkitEntity.getLocation(), destroyedBlocks, 0F); ++ bukkitEntity.getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ // This flag literally means 'Dragon hit something hard' (Obsidian, White Stone or Bedrock) and will cause the dragon to slow down. ++ // We should consider adding an event extension for it, or perhaps returning true if the event is cancelled. ++ return flag; ++ } else if (event.getYield() == 0F) { ++ // Yield zero ==> no drops ++ for (org.bukkit.block.Block block : event.blockList()) { ++ this.level().removeBlock(new BlockPos(block.getX(), block.getY(), block.getZ()), false); ++ } ++ } else { ++ for (org.bukkit.block.Block block : event.blockList()) { ++ org.bukkit.Material blockId = block.getType(); ++ if (blockId.isAir()) { ++ continue; ++ } ++ ++ CraftBlock craftBlock = ((CraftBlock) block); ++ BlockPos blockpos = craftBlock.getPosition(); ++ ++ Block nmsBlock = craftBlock.getNMS().getBlock(); ++ if (nmsBlock.dropFromExplosion(explosionSource)) { ++ BlockEntity blockEntity = craftBlock.getNMS().hasBlockEntity() ? this.level().getBlockEntity(blockpos) : null; ++ LootParams.Builder loottableinfo_builder = (new LootParams.Builder((ServerLevel) this.level())).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(blockpos)).withParameter(LootContextParams.TOOL, ItemStack.EMPTY).withParameter(LootContextParams.EXPLOSION_RADIUS, 1.0F / event.getYield()).withOptionalParameter(LootContextParams.BLOCK_ENTITY, blockEntity); ++ ++ craftBlock.getNMS().getDrops(loottableinfo_builder).forEach((itemstack) -> { ++ Block.popResource(this.level(), blockpos, itemstack); ++ }); ++ craftBlock.getNMS().spawnAfterBreak((ServerLevel) this.level(), blockpos, ItemStack.EMPTY, false); ++ } ++ nmsBlock.wasExploded(this.level(), blockpos, explosionSource); ++ ++ this.level().removeBlock(blockpos, false); ++ } ++ } ++ // CraftBukkit end ++ + if (flag1) { + BlockPos blockpos1 = new BlockPos(i + this.random.nextInt(l - i + 1), j + this.random.nextInt(i1 - j + 1), k + this.random.nextInt(j1 - k + 1)); + this.level().levelEvent(2008, blockpos1, 0); +@@ -503,6 +_,21 @@ + + } + ++ // CraftBukkit start - SPIGOT-2420: Special case, the ender dragon drops 12000 xp for the first kill and 500 xp for every other kill and this over time. ++ @Override ++ public int getExpReward() { ++ // CraftBukkit - Moved from #tickDeath method ++ boolean flag = this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT); ++ short short0 = 500; ++ ++ if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) { ++ short0 = 12000; ++ } ++ ++ return flag ? short0 : 0; ++ } ++ // CraftBukkit end ++ + protected void tickDeath() { + if (this.dragonFight != null) { + this.dragonFight.updateDragon(this); +@@ -516,15 +_,21 @@ + this.level().addParticle(ParticleTypes.EXPLOSION_EMITTER, this.getX() + (double)f, this.getY() + 2.0D + (double)f1, this.getZ() + (double)f2, 0.0D, 0.0D, 0.0D); + } + ++ // CraftBukkit start - SPIGOT-2420: Moved up to #getExpReward method ++ /* + boolean flag = this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT); + int i = 500; + if (this.dragonFight != null && !this.dragonFight.hasPreviouslyKilledDragon()) { + i = 12000; + } ++ */ ++ int i = expToDrop; ++ // CraftBukkit end if (this.level() instanceof ServerLevel) { - if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && flag) { +- if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && flag) { - ExperienceOrb.award((ServerLevel)this.level(), this.position(), Mth.floor((float)i * 0.08F)); ++ if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp + int award = net.minecraftforge.event.ForgeEventFactory.getExperienceDrop(this, this.unlimitedLastHurtByPlayer, Mth.floor((float)i * 0.08F)); + ExperienceOrb.award((ServerLevel) this.level(), this.position(), award); } if (this.dragonDeathTime == 1 && !this.isSilent()) { -@@ -535,7 +_,8 @@ +@@ -534,8 +_,9 @@ + this.move(MoverType.SELF, new Vec3(0.0D, (double)0.1F, 0.0D)); if (this.dragonDeathTime == 200 && this.level() instanceof ServerLevel) { - if (flag) { +- if (flag) { - ExperienceOrb.award((ServerLevel)this.level(), this.position(), Mth.floor((float)i * 0.2F)); ++ if (true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp + int award = net.minecraftforge.event.ForgeEventFactory.getExperienceDrop(this, this.unlimitedLastHurtByPlayer, Mth.floor((float)i * 0.2F)); + ExperienceOrb.award((ServerLevel) this.level(), this.position(), award); } if (this.dragonFight != null) { +@@ -724,6 +_,7 @@ + super.addAdditionalSaveData(p_31144_); + p_31144_.putInt("DragonPhase", this.phaseManager.getCurrentPhase().getPhase().getId()); + p_31144_.putInt("DragonDeathTime", this.dragonDeathTime); ++ p_31144_.putInt("Bukkit.expToDrop", expToDrop); // CraftBukkit - SPIGOT-2420: The ender dragon drops xp over time which can also happen between server starts + } + + public void readAdditionalSaveData(CompoundTag p_31134_) { +@@ -736,6 +_,11 @@ + this.dragonDeathTime = p_31134_.getInt("DragonDeathTime"); + } + ++ // CraftBukkit start - SPIGOT-2420: The ender dragon drops xp over time which can also happen between server starts ++ if (p_31134_.contains("Bukkit.expToDrop")) { ++ this.expToDrop = p_31134_.getInt("Bukkit.expToDrop"); ++ } ++ // CraftBukkit end + } + + public void checkDespawn() { @@ -858,8 +_,19 @@ return false; } diff --git a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch new file mode 100644 index 0000000000..029b49fd1f --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch @@ -0,0 +1,31 @@ +--- a/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java ++++ b/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java +@@ -3,6 +_,8 @@ + import com.mojang.logging.LogUtils; + import javax.annotation.Nullable; + import net.minecraft.world.entity.boss.enderdragon.EnderDragon; ++import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEnderDragon; ++import org.bukkit.event.entity.EnderDragonChangePhaseEvent; + import org.slf4j.Logger; + + public class EnderDragonPhaseManager { +@@ -22,6 +_,19 @@ + if (this.currentPhase != null) { + this.currentPhase.end(); + } ++ ++ // CraftBukkit start - Call EnderDragonChangePhaseEvent ++ EnderDragonChangePhaseEvent event = new EnderDragonChangePhaseEvent( ++ (CraftEnderDragon) this.dragon.getBukkitEntity(), ++ (this.currentPhase == null) ? null : CraftEnderDragon.getBukkitPhase(this.currentPhase.getPhase()), ++ CraftEnderDragon.getBukkitPhase(p_31417_) ++ ); ++ this.dragon.level().getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return; ++ } ++ p_31417_ = CraftEnderDragon.getMinecraftPhase(event.getNewPhase()); ++ // CraftBukkit end + + this.currentPhase = this.getPhase(p_31417_); + if (!this.dragon.level().isClientSide) { diff --git a/patches/minecraft/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/patches/minecraft/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch index 7dee16b661..fab1f1e105 100644 --- a/patches/minecraft/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch @@ -1,5 +1,84 @@ --- a/net/minecraft/world/entity/boss/wither/WitherBoss.java +++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java +@@ -9,10 +_,13 @@ + import net.minecraft.core.particles.ParticleTypes; + import net.minecraft.nbt.CompoundTag; + import net.minecraft.network.chat.Component; ++import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; + import net.minecraft.network.syncher.EntityDataAccessor; + import net.minecraft.network.syncher.EntityDataSerializers; + import net.minecraft.network.syncher.SynchedEntityData; ++import net.minecraft.server.MinecraftServer; + import net.minecraft.server.level.ServerBossEvent; ++import net.minecraft.server.level.ServerLevel; + import net.minecraft.server.level.ServerPlayer; + import net.minecraft.sounds.SoundEvent; + import net.minecraft.sounds.SoundEvents; +@@ -51,8 +_,13 @@ + import net.minecraft.world.item.Items; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.Level; ++import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityRegainHealthEvent; ++import org.bukkit.event.entity.EntityTargetEvent; ++import org.bukkit.event.entity.ExplosionPrimeEvent; + + public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob { + private static final EntityDataAccessor DATA_TARGET_A = SynchedEntityData.defineId(WitherBoss.class, EntityDataSerializers.INT); +@@ -219,15 +_,40 @@ + int k1 = this.getInvulnerableTicks() - 1; + this.bossEvent.setProgress(1.0F - (float)k1 / 220.0F); + if (k1 <= 0) { +- this.level().explode(this, this.getX(), this.getEyeY(), this.getZ(), 7.0F, false, Level.ExplosionInteraction.MOB); ++ // CraftBukkit start ++ // this.level().explode(this, this.getX(), this.getEyeY(), this.getZ(), 7.0F, false, Level.ExplosionInteraction.MOB); ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 7.0F, false); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ this.level().explode(this, this.getX(), this.getEyeY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); ++ } ++ // CraftBukkit end + if (!this.isSilent()) { + this.level().globalLevelEvent(1023, this.blockPosition(), 0); ++ // CraftBukkit start - Use relative location for far away sounds ++ // this.level().globalLevelEvent(1023, new BlockPosition(this), 0); ++ int viewDistance = ((ServerLevel) this.level()).getCraftServer().getViewDistance() * 16; ++ for (ServerPlayer player : (List) MinecraftServer.getServer().getPlayerList().players) { ++ double deltaX = this.getX() - player.getX(); ++ double deltaZ = this.getZ() - player.getZ(); ++ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; ++ if (distanceSquared > viewDistance * viewDistance) { ++ double deltaLength = Math.sqrt(distanceSquared); ++ double relativeX = player.getX() + (deltaX / deltaLength) * viewDistance; ++ double relativeZ = player.getZ() + (deltaZ / deltaLength) * viewDistance; ++ player.connection.send(new ClientboundLevelEventPacket(1023, new BlockPos((int) relativeX, (int) this.getY(), (int) relativeZ), 0, true)); ++ } else { ++ player.connection.send(new ClientboundLevelEventPacket(1023, this.blockPosition(), 0, true)); ++ } ++ } ++ // CraftBukkit end + } + } + + this.setInvulnerableTicks(k1); + if (this.tickCount % 10 == 0) { +- this.heal(10.0F); ++ this.heal(10.0F, EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit + } + + } else { +@@ -265,6 +_,7 @@ + List list = this.level().getNearbyEntities(LivingEntity.class, TARGETING_CONDITIONS, this, this.getBoundingBox().inflate(20.0D, 8.0D, 20.0D)); + if (!list.isEmpty()) { + LivingEntity livingentity1 = list.get(this.random.nextInt(list.size())); ++ if (CraftEventFactory.callEntityTargetLivingEvent(this, livingentity1, EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) continue; // CraftBukkit + this.setAlternativeTarget(i, livingentity1.getId()); + } + } @@ -279,7 +_,7 @@ if (this.destroyBlocksTick > 0) { @@ -9,16 +88,29 @@ int j1 = Mth.floor(this.getY()); int i2 = Mth.floor(this.getX()); int j2 = Mth.floor(this.getZ()); -@@ -293,7 +_,7 @@ +@@ -293,7 +_,12 @@ int i1 = j2 + k2; BlockPos blockpos = new BlockPos(l2, l, i1); BlockState blockstate = this.level().getBlockState(blockpos); - if (canDestroy(blockstate)) { + if (blockstate.canEntityDestroy(this.level(), blockpos, this) && net.minecraftforge.event.ForgeEventFactory.onEntityDestroyBlock(this, blockpos, blockstate)) { ++ // CraftBukkit start ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockpos, Blocks.AIR.defaultBlockState())) { ++ continue; ++ } ++ // CraftBukkit end flag = this.level().destroyBlock(blockpos, true, this) || flag; } } -@@ -314,6 +_,10 @@ +@@ -307,13 +_,17 @@ + } + + if (this.tickCount % 20 == 0) { +- this.heal(1.0F); ++ this.heal(1.0F, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit + } + + this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); } } From 33d1e378161bd2f5dc02cb2870d7b14586d71948 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 19:31:57 +0100 Subject: [PATCH 08/26] Decoration entity patches --- .../entity/decoration/ArmorStand.java.patch | 184 ++++++++++++++++++ .../decoration/HangingEntity.java.patch | 170 ++++++++++++++++ .../entity/decoration/ItemFrame.java.patch | 107 ++++++++++ .../LeashFenceKnotEntity.java.patch | 64 ++++++ 4 files changed, 525 insertions(+) create mode 100644 patches/minecraft/net/minecraft/world/entity/decoration/ItemFrame.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/decoration/ArmorStand.java.patch b/patches/minecraft/net/minecraft/world/entity/decoration/ArmorStand.java.patch index 43a3ecd2dc..5e42d22e42 100644 --- a/patches/minecraft/net/minecraft/world/entity/decoration/ArmorStand.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/decoration/ArmorStand.java.patch @@ -1,5 +1,15 @@ --- a/net/minecraft/world/entity/decoration/ArmorStand.java +++ b/net/minecraft/world/entity/decoration/ArmorStand.java +@@ -41,6 +_,9 @@ + import net.minecraft.world.level.material.PushReaction; + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.CraftEquipmentSlot; ++import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; ++import org.bukkit.event.player.PlayerArmorStandManipulateEvent; + + public class ArmorStand extends LivingEntity { + public static final int WOBBLE_TIME = 5; @@ -71,7 +_,7 @@ public static final EntityDataAccessor DATA_LEFT_LEG_POSE = SynchedEntityData.defineId(ArmorStand.class, EntityDataSerializers.ROTATIONS); public static final EntityDataAccessor DATA_RIGHT_LEG_POSE = SynchedEntityData.defineId(ArmorStand.class, EntityDataSerializers.ROTATIONS); @@ -9,3 +19,177 @@ }; private final NonNullList handItems = NonNullList.withSize(2, ItemStack.EMPTY); private final NonNullList armorItems = NonNullList.withSize(4, ItemStack.EMPTY); +@@ -103,6 +_,13 @@ + this.setPos(d0, d1, d2); + } + ++ // CraftBukkit start - SPIGOT-3607, SPIGOT-3637 ++ @Override ++ public float getBukkitYaw() { ++ return this.getYRot(); ++ } ++ // CraftBukkit end ++ + private boolean hasPhysics() { + return !this.isMarker() && !this.isNoGravity(); + } +@@ -142,13 +_,18 @@ + } + + public void setItemSlot(EquipmentSlot p_31584_, ItemStack p_31585_) { ++ // CraftBukkit start ++ this.setItemSlot(p_31584_, p_31585_, false); ++ } ++ ++ public void setItemSlot(EquipmentSlot p_31584_, ItemStack p_31585_, boolean silent) { + this.verifyEquippedItem(p_31585_); + switch (p_31584_.getType()) { + case HAND: +- this.onEquipItem(p_31584_, this.handItems.set(p_31584_.getIndex(), p_31585_), p_31585_); ++ this.onEquipItem(p_31584_, this.handItems.set(p_31584_.getIndex(), p_31585_), p_31585_, silent); // CraftBukkit + break; + case ARMOR: +- this.onEquipItem(p_31584_, this.armorItems.set(p_31584_.getIndex(), p_31585_), p_31585_); ++ this.onEquipItem(p_31584_, this.armorItems.set(p_31584_.getIndex(), p_31585_), p_31585_, silent); // CraftBukkit + } + + } +@@ -351,32 +_,61 @@ + return false; + } else if (itemstack.isEmpty() && (this.disabledSlots & 1 << p_31590_.getFilterFlag() + 16) != 0) { + return false; +- } else if (p_31589_.getAbilities().instabuild && itemstack.isEmpty() && !p_31591_.isEmpty()) { +- this.setItemSlot(p_31590_, p_31591_.copyWithCount(1)); +- return true; +- } else if (!p_31591_.isEmpty() && p_31591_.getCount() > 1) { +- if (!itemstack.isEmpty()) { +- return false; +- } else { +- this.setItemSlot(p_31590_, p_31591_.split(1)); +- return true; +- } ++ // CraftBukkit start + } else { +- this.setItemSlot(p_31590_, p_31591_); +- p_31589_.setItemInHand(p_31592_, itemstack); +- return true; +- } ++ org.bukkit.inventory.ItemStack armorStandItem = CraftItemStack.asCraftMirror(itemstack); ++ org.bukkit.inventory.ItemStack playerHeldItem = CraftItemStack.asCraftMirror(itemstack); ++ ++ org.bukkit.entity.Player player = (org.bukkit.entity.Player) p_31589_.getBukkitEntity(); ++ org.bukkit.entity.ArmorStand self = (org.bukkit.entity.ArmorStand) this.getBukkitEntity(); ++ ++ org.bukkit.inventory.EquipmentSlot slot = CraftEquipmentSlot.getSlot(p_31590_); ++ org.bukkit.inventory.EquipmentSlot hand = CraftEquipmentSlot.getHand(p_31592_); ++ PlayerArmorStandManipulateEvent armorStandManipulateEvent = new PlayerArmorStandManipulateEvent(player, self, playerHeldItem, armorStandItem, slot, hand); ++ this.level().getCraftServer().getPluginManager().callEvent(armorStandManipulateEvent); ++ ++ if (armorStandManipulateEvent.isCancelled()) { ++ return true; ++ } ++ ++ if (p_31589_.getAbilities().instabuild && itemstack.isEmpty() && !itemstack.isEmpty()) { ++ // CraftBukkit end ++ this.setItemSlot(p_31590_, p_31591_.copyWithCount(1)); ++ return true; ++ // CraftBukkit start ++ } else if (!p_31591_.isEmpty() && p_31591_.getCount() > 1) { ++ if (!itemstack.isEmpty()) { ++ return false; ++ } else { ++ this.setItemSlot(p_31590_, p_31591_.split(1)); ++ return true; ++ } ++ } else { ++ this.setItemSlot(p_31590_, p_31591_); ++ p_31589_.setItemInHand(p_31592_, itemstack); ++ return true; ++ } ++ } // CraftBukkit + } + + public boolean hurt(DamageSource p_31579_, float p_31580_) { + if (!this.level().isClientSide && !this.isRemoved()) { + if (p_31579_.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, p_31579_, p_31580_)) { ++ return false; ++ } ++ // CraftBukkit end + this.kill(); + return false; +- } else if (!this.isInvulnerableTo(p_31579_) && !this.invisible && !this.isMarker()) { ++ } else if (!this.isInvulnerableTo(p_31579_) && (true || !this.invisible) && !this.isMarker()) { // CraftBukkit ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, p_31579_, p_31580_, true, this.invisible)) { ++ return false; ++ } ++ // CraftBukkit end + if (p_31579_.is(DamageTypeTags.IS_EXPLOSION)) { + this.brokenByAnything(p_31579_); +- this.kill(); + return false; + } else if (p_31579_.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) { + if (this.isOnFire()) { +@@ -425,7 +_,7 @@ + } else { + this.brokenByPlayer(p_31579_); + this.showBreakingParticles(); +- this.kill(); ++ this.discard(); // CraftBukkit - SPIGOT-4890: remain as this.discard() since above damagesource method will call death event + } + + return true; +@@ -488,18 +_,18 @@ + itemstack.setHoverName(this.getCustomName()); + } + +- Block.popResource(this.level(), this.blockPosition(), itemstack); ++ drops.add(org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops + this.brokenByAnything(p_31647_); + } + + private void brokenByAnything(DamageSource p_31654_) { + this.playBrokenSound(); +- this.dropAllDeathLoot(p_31654_); ++ // this.dropAllDeathLoot(p_31654_); // CraftBukkit - moved down + + for(int i = 0; i < this.handItems.size(); ++i) { + ItemStack itemstack = this.handItems.get(i); + if (!itemstack.isEmpty()) { +- Block.popResource(this.level(), this.blockPosition().above(), itemstack); ++ drops.add(org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops + this.handItems.set(i, ItemStack.EMPTY); + } + } +@@ -507,11 +_,11 @@ + for(int j = 0; j < this.armorItems.size(); ++j) { + ItemStack itemstack1 = this.armorItems.get(j); + if (!itemstack1.isEmpty()) { +- Block.popResource(this.level(), this.blockPosition().above(), itemstack1); ++ drops.add(org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack.asBukkitCopy(itemstack1)); // CraftBukkit - add to drops + this.armorItems.set(j, ItemStack.EMPTY); + } + } +- ++ this.dropAllDeathLoot(p_31654_); // CraftBukkit - moved from above + } + + private void playBrokenSound() { +@@ -591,7 +_,15 @@ + return this.isSmall(); + } + ++ // CraftBukkit start ++ @Override ++ public boolean shouldDropExperience() { ++ return true; // MC-157395, SPIGOT-5193 even baby (small) armor stands should drop ++ } ++ // CraftBukkit end ++ + public void kill() { ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityDeathEvent(this, drops); // CraftBukkit - call event + this.remove(Entity.RemovalReason.KILLED); + this.gameEvent(GameEvent.ENTITY_DIE); + } diff --git a/patches/minecraft/net/minecraft/world/entity/decoration/HangingEntity.java.patch b/patches/minecraft/net/minecraft/world/entity/decoration/HangingEntity.java.patch index 78695be9a7..1db4b81dc1 100644 --- a/patches/minecraft/net/minecraft/world/entity/decoration/HangingEntity.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/decoration/HangingEntity.java.patch @@ -1,5 +1,125 @@ --- a/net/minecraft/world/entity/decoration/HangingEntity.java +++ b/net/minecraft/world/entity/decoration/HangingEntity.java +@@ -7,6 +_,7 @@ + import net.minecraft.core.Direction; + import net.minecraft.nbt.CompoundTag; + import net.minecraft.server.level.ServerLevel; ++import net.minecraft.tags.DamageTypeTags; + import net.minecraft.util.Mth; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; +@@ -24,6 +_,9 @@ + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; + import org.apache.commons.lang3.Validate; ++import org.bukkit.entity.Hanging; ++import org.bukkit.event.hanging.HangingBreakByEntityEvent; ++import org.bukkit.event.hanging.HangingBreakEvent; + import org.slf4j.Logger; + + public abstract class HangingEntity extends Entity { +@@ -58,36 +_,46 @@ + + protected void recalculateBoundingBox() { + if (this.direction != null) { +- double d0 = (double)this.pos.getX() + 0.5D; +- double d1 = (double)this.pos.getY() + 0.5D; +- double d2 = (double)this.pos.getZ() + 0.5D; +- double d3 = 0.46875D; +- double d4 = this.offs(this.getWidth()); +- double d5 = this.offs(this.getHeight()); +- d0 -= (double)this.direction.getStepX() * 0.46875D; +- d2 -= (double)this.direction.getStepZ() * 0.46875D; +- d1 += d5; +- Direction direction = this.direction.getCounterClockWise(); +- d0 += d4 * (double)direction.getStepX(); +- d2 += d4 * (double)direction.getStepZ(); +- this.setPosRaw(d0, d1, d2); +- double d6 = (double)this.getWidth(); +- double d7 = (double)this.getHeight(); +- double d8 = (double)this.getWidth(); +- if (this.direction.getAxis() == Direction.Axis.Z) { +- d8 = 1.0D; +- } else { +- d6 = 1.0D; +- } +- +- d6 /= 32.0D; +- d7 /= 32.0D; +- d8 /= 32.0D; +- this.setBoundingBox(new AABB(d0 - d6, d1 - d7, d2 - d8, d0 + d6, d1 + d7, d2 + d8)); +- } +- } +- +- private double offs(int p_31710_) { ++ // CraftBukkit start code moved in to calculateBoundingBox ++ this.setBoundingBox(calculateBoundingBox(this, this.pos, this.direction, this.getWidth(), this.getHeight())); ++ // CraftBukkit end ++ } ++ } ++ // CraftBukkit start - break out BB calc into own method ++ public static AABB calculateBoundingBox(@Nullable Entity entity, BlockPos blockPosition, Direction direction, int width, int height) { ++ ++ double d0 = (double) blockPosition.getX() + 0.5D; ++ double d1 = (double) blockPosition.getY() + 0.5D; ++ double d2 = (double) blockPosition.getZ() + 0.5D; ++ double d3 = 0.46875D; ++ double d4 = offs(width); ++ double d5 = offs(height); ++ d0 -= (double) direction.getStepX() * 0.46875D; ++ d2 -= (double) direction.getStepZ() * 0.46875D; ++ d1 += d5; ++ Direction direction1 = direction.getCounterClockWise(); ++ d0 += d4 * (double) direction.getStepX(); ++ d2 += d4 * (double) direction.getStepZ(); ++ if (entity != null) { ++ entity.setPosRaw(d0, d1, d2); ++ } ++ double d6 = (double) width; ++ double d7 = (double) height; ++ double d8 = (double) width; ++ if (direction.getAxis() == Direction.Axis.Z) { ++ d8 = 1.0D; ++ } else { ++ d6 = 1.0D; ++ } ++ ++ d6 /= 32.0D; ++ d7 /= 32.0D; ++ d8 /= 32.0D; ++ return new AABB(d0 - d6, d1 - d7, d2 - d8, d0 + d6, d1 + d7, d2 + d8); ++ } ++ // CraftBukkit end ++ ++ private static double offs(int p_31710_) { // CraftBukkit - static + return p_31710_ % 32 == 0 ? 0.5D : 0.0D; + } + +@@ -97,6 +_,24 @@ + if (this.checkInterval++ == 100) { + this.checkInterval = 0; + if (!this.isRemoved() && !this.survives()) { ++ // CraftBukkit start - fire break events ++ BlockState material = this.level().getBlockState(this.blockPosition()); ++ HangingBreakEvent.RemoveCause cause; ++ ++ if (!material.isAir()) { ++ // TODO: This feels insufficient to catch 100% of suffocation cases ++ cause = HangingBreakEvent.RemoveCause.OBSTRUCTION; ++ } else { ++ cause = HangingBreakEvent.RemoveCause.PHYSICS; ++ } ++ ++ HangingBreakEvent event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), cause); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (this.isRemoved() || event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + this.discard(); + this.dropItem((Entity)null); + } @@ -121,6 +_,8 @@ int j1 = (j - 1) / -2; blockpos$mutableblockpos.set(blockpos).move(direction, k + i1).move(Direction.UP, l + j1); @@ -9,3 +129,53 @@ if (!blockstate.isSolid() && !DiodeBlock.isDiode(blockstate)) { return false; } +@@ -152,6 +_,22 @@ + return false; + } else { + if (!this.isRemoved() && !this.level().isClientSide) { ++ // CraftBukkit start - fire break events ++ Entity damager = (p_31715_.isIndirect()) ? p_31715_.getEntity() : p_31715_.getDirectEntity(); ++ HangingBreakEvent event; ++ if (damager != null) { ++ event = new HangingBreakByEntityEvent((Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), p_31715_.is(DamageTypeTags.IS_EXPLOSION) ? HangingBreakEvent.RemoveCause.EXPLOSION : HangingBreakEvent.RemoveCause.ENTITY); ++ } else { ++ event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), p_31715_.is(DamageTypeTags.IS_EXPLOSION) ? HangingBreakEvent.RemoveCause.EXPLOSION : HangingBreakEvent.RemoveCause.DEFAULT); ++ } ++ ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (this.isRemoved() || event.isCancelled()) { ++ return true; ++ } ++ // CraftBukkit end ++ + this.kill(); + this.markHurt(); + this.dropItem(p_31715_.getEntity()); +@@ -163,6 +_,17 @@ + + public void move(MoverType p_31719_, Vec3 p_31720_) { + if (!this.level().isClientSide && !this.isRemoved() && p_31720_.lengthSqr() > 0.0D) { ++ if (this.isRemoved()) return; // CraftBukkit ++ ++ // CraftBukkit start - fire break events ++ // TODO - Does this need its own cause? Seems to only be triggered by pistons ++ HangingBreakEvent event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), HangingBreakEvent.RemoveCause.PHYSICS); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (this.isRemoved() || event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + this.kill(); + this.dropItem((Entity)null); + } +@@ -170,7 +_,7 @@ + } + + public void push(double p_31744_, double p_31745_, double p_31746_) { +- if (!this.level().isClientSide && !this.isRemoved() && p_31744_ * p_31744_ + p_31745_ * p_31745_ + p_31746_ * p_31746_ > 0.0D) { ++ if (false && !this.level().isClientSide && !this.isRemoved() && p_31744_ * p_31744_ + p_31745_ * p_31745_ + p_31746_ * p_31746_ > 0.0D) { // CraftBukkit - not needed + this.kill(); + this.dropItem((Entity)null); + } diff --git a/patches/minecraft/net/minecraft/world/entity/decoration/ItemFrame.java.patch b/patches/minecraft/net/minecraft/world/entity/decoration/ItemFrame.java.patch new file mode 100644 index 0000000000..b3e412da9e --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/decoration/ItemFrame.java.patch @@ -0,0 +1,107 @@ +--- a/net/minecraft/world/entity/decoration/ItemFrame.java ++++ b/net/minecraft/world/entity/decoration/ItemFrame.java +@@ -89,32 +_,43 @@ + + protected void recalculateBoundingBox() { + if (this.direction != null) { +- double d0 = 0.46875D; +- double d1 = (double)this.pos.getX() + 0.5D - (double)this.direction.getStepX() * 0.46875D; +- double d2 = (double)this.pos.getY() + 0.5D - (double)this.direction.getStepY() * 0.46875D; +- double d3 = (double)this.pos.getZ() + 0.5D - (double)this.direction.getStepZ() * 0.46875D; +- this.setPosRaw(d1, d2, d3); +- double d4 = (double)this.getWidth(); +- double d5 = (double)this.getHeight(); +- double d6 = (double)this.getWidth(); +- Direction.Axis direction$axis = this.direction.getAxis(); +- switch (direction$axis) { +- case X: +- d4 = 1.0D; +- break; +- case Y: +- d5 = 1.0D; +- break; +- case Z: +- d6 = 1.0D; +- } +- +- d4 /= 32.0D; +- d5 /= 32.0D; +- d6 /= 32.0D; +- this.setBoundingBox(new AABB(d1 - d4, d2 - d5, d3 - d6, d1 + d4, d2 + d5, d3 + d6)); +- } +- } ++ // CraftBukkit start code moved in to calculateBoundingBox ++ this.setBoundingBox(calculateBoundingBox(this, this.pos, this.direction, this.getWidth(), this.getHeight())); ++ // CraftBukkit end ++ } ++ } ++ ++ // CraftBukkit start - break out BB calc into own method ++ public static AABB calculateBoundingBox(@Nullable Entity entity, BlockPos blockPosition, Direction direction, int width, int height) { ++ double d0 = 0.46875D; ++ double d1 = (double) blockPosition.getX() + 0.5D - (double) direction.getStepX() * 0.46875D; ++ double d2 = (double) blockPosition.getY() + 0.5D - (double) direction.getStepY() * 0.46875D; ++ double d3 = (double) blockPosition.getZ() + 0.5D - (double) direction.getStepZ() * 0.46875D; ++ if (entity != null) { ++ entity.setPosRaw(d1, d2, d3); ++ } ++ double d4 = (double) width; ++ double d5 = (double) height; ++ double d6 = (double) width; ++ Direction.Axis enumdirection_enumaxis = direction.getAxis(); ++ ++ switch (enumdirection_enumaxis) { ++ case X: ++ d4 = 1.0D; ++ break; ++ case Y: ++ d5 = 1.0D; ++ break; ++ case Z: ++ d6 = 1.0D; ++ } ++ ++ d4 /= 32.0D; ++ d5 /= 32.0D; ++ d6 /= 32.0D; ++ return new AABB(d1 - d4, d2 - d5, d3 - d6, d1 + d4, d2 + d5, d3 + d6); ++ } ++ // CraftBukkit end + + public boolean survives() { + if (this.fixed) { +@@ -157,6 +_,11 @@ + return false; + } else if (!p_31776_.is(DamageTypeTags.IS_EXPLOSION) && !this.getItem().isEmpty()) { + if (!this.level().isClientSide) { ++ // CraftBukkit start - fire EntityDamageEvent ++ if (org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, p_31776_, p_31777_, false) || this.isRemoved()) { ++ return true; ++ } ++ // CraftBukkit end + this.dropItem(p_31776_.getEntity(), false); + this.gameEvent(GameEvent.BLOCK_CHANGE, p_31776_.getEntity()); + this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F); +@@ -274,14 +_,20 @@ + this.setItem(p_31806_, true); + } + +- public void setItem(ItemStack p_31790_, boolean p_31791_) { ++ public void setItem(ItemStack itemstack, boolean p_31791_) { ++ // CraftBukkit start ++ this.setItem(itemstack, p_31791_, true); ++ } ++ ++ public void setItem(ItemStack p_31790_, boolean p_31791_, boolean playSound) { ++ // CraftBukkit end + if (!p_31790_.isEmpty()) { + p_31790_ = p_31790_.copyWithCount(1); + } + + this.onItemChanged(p_31790_); + this.getEntityData().set(DATA_ITEM, p_31790_); +- if (!p_31790_.isEmpty()) { ++ if (!p_31790_.isEmpty() && playSound) { // CraftBukkit + this.playSound(this.getAddItemSound(), 1.0F, 1.0F); + } + diff --git a/patches/minecraft/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch b/patches/minecraft/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch new file mode 100644 index 0000000000..8885b7c8ab --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch @@ -0,0 +1,64 @@ +--- a/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java ++++ b/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java +@@ -8,6 +_,8 @@ + import net.minecraft.network.protocol.Packet; + import net.minecraft.network.protocol.game.ClientGamePacketListener; + import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; ++import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; ++import net.minecraft.server.level.ServerPlayer; + import net.minecraft.sounds.SoundEvents; + import net.minecraft.tags.BlockTags; + import net.minecraft.world.InteractionHand; +@@ -24,6 +_,7 @@ + import net.minecraft.world.level.gameevent.GameEvent; + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; + + public class LeashFenceKnotEntity extends HangingEntity { + public static final double OFFSET_Y = 0.375D; +@@ -83,6 +_,12 @@ + + for(Mob mob : list) { + if (mob.getLeashHolder() == p_31842_) { ++ // CraftBukkit start ++ if (CraftEventFactory.callPlayerLeashEntityEvent(mob, this, p_31842_, p_31843_).isCancelled()) { ++ ((ServerPlayer) p_31842_).connection.send(new ClientboundSetEntityLinkPacket(mob, mob.getLeashHolder())); ++ continue; ++ } ++ // CraftBukkit end + mob.setLeashedTo(this, true); + flag = true; + } +@@ -90,14 +_,28 @@ + + boolean flag1 = false; + if (!flag) { +- this.discard(); +- if (p_31842_.getAbilities().instabuild) { ++ // CraftBukkit start - Move below ++ // this.discard(); ++ boolean die = true; ++ // CraftBukkit end ++ if (true || p_31842_.getAbilities().instabuild) { // CraftBukkit - Process for non-creative as well + for(Mob mob1 : list) { + if (mob1.isLeashed() && mob1.getLeashHolder() == this) { +- mob1.dropLeash(true, false); ++ // CraftBukkit start ++ if (CraftEventFactory.callPlayerUnleashEntityEvent(mob1, p_31842_, p_31843_).isCancelled()) { ++ die = false; ++ continue; ++ } ++ mob1.dropLeash(true, !p_31842_.getAbilities().instabuild); // false -> survival mode boolean ++ // CraftBukkit end + flag1 = true; + } + } ++ // CraftBukkit start ++ if (die) { ++ this.discard(); ++ } ++ // CraftBukkit end + } + } + From f380d1d271dfb588e089ec818e57413241168630 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 19:49:17 +0100 Subject: [PATCH 09/26] Vehicle entity patches --- .../vehicle/AbstractMinecart.java.patch | 214 ++++++++++++++++-- .../AbstractMinecartContainer.java.patch | 69 ++++++ .../world/entity/vehicle/Boat.java.patch | 152 ++++++++++++- .../world/entity/vehicle/ChestBoat.java.patch | 63 +++++- .../vehicle/MinecartCommandBlock.java.patch | 22 ++ .../entity/vehicle/MinecartTNT.java.patch | 28 +++ 6 files changed, 529 insertions(+), 19 deletions(-) create mode 100644 patches/minecraft/net/minecraft/world/entity/vehicle/MinecartTNT.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch b/patches/minecraft/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch index 59439271b5..0a175f0e2b 100644 --- a/patches/minecraft/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch @@ -1,7 +1,16 @@ --- a/net/minecraft/world/entity/vehicle/AbstractMinecart.java +++ b/net/minecraft/world/entity/vehicle/AbstractMinecart.java -@@ -48,7 +_,7 @@ +@@ -46,9 +_,16 @@ + import net.minecraft.world.level.gameevent.GameEvent; + import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; ++import org.bukkit.Location; ++import org.bukkit.craftbukkit.v1_20_R2.util.CraftLocation; ++import org.bukkit.entity.Vehicle; ++import org.bukkit.event.vehicle.VehicleDamageEvent; ++import org.bukkit.event.vehicle.VehicleDestroyEvent; ++import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; ++import org.bukkit.util.Vector; import org.joml.Vector3f; -public abstract class AbstractMinecart extends Entity { @@ -9,12 +18,23 @@ private static final float LOWERED_PASSENGER_ATTACHMENT_Y = 0.0F; private static final float PASSENGER_ATTACHMENT_Y = 0.1875F; private static final EntityDataAccessor DATA_ID_HURT = SynchedEntityData.defineId(AbstractMinecart.class, EntityDataSerializers.INT); -@@ -88,6 +_,8 @@ +@@ -88,6 +_,19 @@ p_38135_.put(RailShape.NORTH_WEST, Pair.of(vec3i2, vec3i)); p_38135_.put(RailShape.NORTH_EAST, Pair.of(vec3i2, vec3i1)); }); + private static net.minecraftforge.common.IMinecartCollisionHandler COLLISIONS = null; + private boolean canBePushed = true; ++ ++ // CraftBukkit start ++ public boolean slowWhenEmpty = true; ++ private double derailedX = 0.5; ++ private double derailedY = 0.5; ++ private double derailedZ = 0.5; ++ private double flyingX = 0.95; ++ private double flyingY = 0.95; ++ private double flyingZ = 0.95; ++ public double maxSpeed = 0.4D; ++ // CraftBukkit end protected AbstractMinecart(EntityType p_38087_, Level p_38088_) { super(p_38087_, p_38088_); @@ -42,6 +62,66 @@ } protected Vec3 getRelativePortalPosition(Direction.Axis p_38132_, BlockUtil.FoundRectangle p_38133_) { +@@ -204,6 +_,19 @@ + if (this.isInvulnerableTo(p_38117_)) { + return false; + } else { ++ // CraftBukkit start - fire VehicleDamageEvent ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ org.bukkit.entity.Entity passenger = (p_38117_.getEntity() == null) ? null : p_38117_.getEntity().getBukkitEntity(); ++ ++ VehicleDamageEvent event = new VehicleDamageEvent(vehicle, passenger, p_38118_); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ ++ p_38118_ = (float) event.getDamage(); ++ // CraftBukkit end + this.setHurtDir(-this.getHurtDir()); + this.setHurtTime(10); + this.markHurt(); +@@ -211,6 +_,15 @@ + this.gameEvent(GameEvent.ENTITY_DAMAGE, p_38117_.getEntity()); + boolean flag = p_38117_.getEntity() instanceof Player && ((Player)p_38117_.getEntity()).getAbilities().instabuild; + if (flag || this.getDamage() > 40.0F) { ++ // CraftBukkit start ++ VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, passenger); ++ this.level().getCraftServer().getPluginManager().callEvent(destroyEvent); ++ ++ if (destroyEvent.isCancelled()) { ++ this.setDamage(40); // Maximize damage so this doesn't get triggered again right away ++ return true; ++ } ++ // CraftBukkit end + this.ejectPassengers(); + if (flag && !this.hasCustomName()) { + this.discard(); +@@ -265,6 +_,14 @@ + } + + public void tick() { ++ // CraftBukkit start ++ double prevX = this.getX(); ++ double prevY = this.getY(); ++ double prevZ = this.getZ(); ++ float prevYaw = this.getYRot(); ++ float prevPitch = this.getXRot(); ++ // CraftBukkit end ++ + if (this.getHurtTime() > 0) { + this.setHurtTime(this.getHurtTime() - 1); + } +@@ -274,7 +_,7 @@ + } + + this.checkBelowWorld(); +- this.handleNetherPortal(); ++ // this.handleNetherPortal(); // CraftBukkit - handled in postTick + if (this.level().isClientSide) { + if (this.lerpSteps > 0) { + this.lerpPositionAndRotationStep(this.lerpSteps, this.lerpX, this.lerpY, this.lerpZ, this.lerpYRot, this.lerpXRot); @@ -300,9 +_,9 @@ BlockPos blockpos = new BlockPos(k, i, j); BlockState blockstate = this.level().getBlockState(blockpos); @@ -54,7 +134,7 @@ this.activateMinecart(k, i, j, blockstate.getValue(PoweredRailBlock.POWERED)); } } else { -@@ -327,8 +_,11 @@ +@@ -327,20 +_,61 @@ } this.setRot(this.getYRot(), this.getXRot()); @@ -63,21 +143,71 @@ + AABB box; + if (getCollisionHandler() != null) box = getCollisionHandler().getMinecartCollisionBox(this); + else box = this.getBoundingBox().inflate(0.2F, 0.0D, 0.2F); ++ // CraftBukkit start ++ org.bukkit.World bworld = this.level().getWorld(); ++ Location from = new Location(bworld, prevX, prevY, prevZ, prevYaw, prevPitch); ++ Location to = CraftLocation.toBukkit(this.position(), bworld, this.getYRot(), this.getXRot()); ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ ++ this.level().getCraftServer().getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleUpdateEvent(vehicle)); ++ ++ if (!from.equals(to)) { ++ this.level().getCraftServer().getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleMoveEvent(vehicle, from, to)); ++ } ++ // CraftBukkit end + if (canBeRidden() && this.getDeltaMovement().horizontalDistanceSqr() > 0.01D) { + List list = this.level().getEntities(this, box, EntitySelector.pushableBy(this)); if (!list.isEmpty()) { for(Entity entity1 : list) { if (!(entity1 instanceof Player) && !(entity1 instanceof IronGolem) && !(entity1 instanceof AbstractMinecart) && !this.isVehicle() && !entity1.isPassenger()) { -@@ -339,7 +_,7 @@ ++ // CraftBukkit start ++ VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent(vehicle, entity1.getBukkitEntity()); ++ this.level().getCraftServer().getPluginManager().callEvent(collisionEvent); ++ ++ if (collisionEvent.isCancelled()) { ++ continue; ++ } ++ // CraftBukkit end + entity1.startRiding(this); + } else { ++ // CraftBukkit start ++ if (!this.isPassengerOfSameVehicle(entity1)) { ++ VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent(vehicle, entity1.getBukkitEntity()); ++ this.level().getCraftServer().getPluginManager().callEvent(collisionEvent); ++ ++ if (collisionEvent.isCancelled()) { ++ continue; ++ } ++ } ++ // CraftBukkit end + entity1.push(this); + } } } } else { - for(Entity entity : this.level().getEntities(this, this.getBoundingBox().inflate((double)0.2F, 0.0D, (double)0.2F))) { + for(Entity entity : this.level().getEntities(this, box)) { if (!this.hasPassenger(entity) && entity.isPushable() && entity instanceof AbstractMinecart) { ++ // CraftBukkit start ++ VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent(vehicle, entity.getBukkitEntity()); ++ this.level().getCraftServer().getPluginManager().callEvent(collisionEvent); ++ ++ if (collisionEvent.isCancelled()) { ++ continue; ++ } ++ // CraftBukkit end entity.push(this); } -@@ -364,16 +_,23 @@ + } +@@ -357,23 +_,34 @@ + } + + protected double getMaxSpeed() { +- return (this.isInWater() ? 4.0D : 8.0D) / 20.0D; ++ return (this.isInWater() ? this.maxSpeed / 2.0D: this.maxSpeed); // CraftBukkit + } + + public void activateMinecart(int p_38111_, int p_38112_, int p_38113_, boolean p_38114_) { } protected void comeOffTrack() { @@ -86,20 +216,25 @@ Vec3 vec3 = this.getDeltaMovement(); this.setDeltaMovement(Mth.clamp(vec3.x, -d0, d0), vec3.y, Mth.clamp(vec3.z, -d0, d0)); if (this.onGround()) { - this.setDeltaMovement(this.getDeltaMovement().scale(0.5D)); - } - +- this.setDeltaMovement(this.getDeltaMovement().scale(0.5D)); ++ // CraftBukkit start - replace magic numbers with our variables ++ this.setDeltaMovement(new Vec3(this.getDeltaMovement().x * this.derailedX, this.getDeltaMovement().y * this.derailedY, this.getDeltaMovement().z * this.derailedZ)); ++ // CraftBukkit end ++ } ++ + if (getMaxSpeedAirVertical() > 0 && getDeltaMovement().y > getMaxSpeedAirVertical()) { + if(Math.abs(getDeltaMovement().x) < 0.3f && Math.abs(getDeltaMovement().z) < 0.3f) + setDeltaMovement(new Vec3(getDeltaMovement().x, 0.15f, getDeltaMovement().z)); + else + setDeltaMovement(new Vec3(getDeltaMovement().x, getMaxSpeedAirVertical(), getDeltaMovement().z)); -+ } -+ + } + this.move(MoverType.SELF, this.getDeltaMovement()); if (!this.onGround()) { - this.setDeltaMovement(this.getDeltaMovement().scale(0.95D)); -+ this.setDeltaMovement(this.getDeltaMovement().scale(getDragAir())); ++ // CraftBukkit start - replace magic numbers with our variables ++ this.setDeltaMovement(new Vec3(this.getDeltaMovement().x * this.flyingX, this.getDeltaMovement().y * this.flyingY, this.getDeltaMovement().z * this.flyingZ)); ++ // CraftBukkit end } } @@ -159,6 +294,15 @@ Vec3 vec36 = this.getDeltaMovement(); double d27 = vec36.horizontalDistance(); if (d27 > 0.01D) { +@@ -547,7 +_,7 @@ + } + + protected void applyNaturalSlowdown() { +- double d0 = this.isVehicle() ? 0.997D : 0.96D; ++ double d0 = this.isVehicle() || !this.slowWhenEmpty ? 0.997D : 0.96D; // CraftBukkit - add !this.slowWhenEmpty + Vec3 vec3 = this.getDeltaMovement(); + vec3 = vec3.multiply(d0, 0.0D, d0); + if (this.isInWater()) { @@ -568,7 +_,7 @@ BlockState blockstate = this.level().getBlockState(new BlockPos(i, j, k)); @@ -177,7 +321,7 @@ Pair pair = exits(railshape); Vec3i vec3i = pair.getFirst(); Vec3i vec3i1 = pair.getSecond(); -@@ -669,6 +_,10 @@ +@@ -669,9 +_,21 @@ } public void push(Entity p_38165_) { @@ -188,6 +332,17 @@ if (!this.level().isClientSide) { if (!p_38165_.noPhysics && !this.noPhysics) { if (!this.hasPassenger(p_38165_)) { ++ // CraftBukkit start ++ VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), p_38165_.getBukkitEntity()); ++ this.level().getCraftServer().getPluginManager().callEvent(collisionEvent); ++ ++ if (collisionEvent.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + double d0 = p_38165_.getX() - this.getX(); + double d1 = p_38165_.getZ() - this.getZ(); + double d2 = d0 * d0 + d1 * d1; @@ -702,11 +_,11 @@ Vec3 vec32 = this.getDeltaMovement(); @@ -202,11 +357,10 @@ p_38165_.setDeltaMovement(vec33.multiply(0.2D, 1.0D, 0.2D)); p_38165_.push(vec32.x + d0, 0.0D, vec32.z + d1); this.setDeltaMovement(vec32.multiply(0.95D, 1.0D, 0.95D)); -@@ -823,6 +_,42 @@ - public void setCustomDisplay(boolean p_38139_) { +@@ -824,6 +_,42 @@ this.getEntityData().set(DATA_ID_CUSTOM_DISPLAY, p_38139_); } -+ + + // Forge Start + private boolean canUseRail = true; + @Override public boolean canUseRail() { return canUseRail; } @@ -242,6 +396,34 @@ + mc.move(MoverType.SELF, new Vec3(Mth.clamp(d24 * vec3d1.x, -d25, d25), 0.0D, Mth.clamp(d24 * vec3d1.z, -d25, d25))); + } + // Forge end - ++ public ItemStack getPickResult() { Item item; + switch (this.getMinecartType()) { +@@ -858,4 +_,26 @@ + HOPPER, + COMMAND_BLOCK; + } ++ ++ // CraftBukkit start - Methods for getting and setting flying and derailed velocity modifiers ++ public Vector getFlyingVelocityMod() { ++ return new Vector(flyingX, flyingY, flyingZ); ++ } ++ ++ public void setFlyingVelocityMod(Vector flying) { ++ flyingX = flying.getX(); ++ flyingY = flying.getY(); ++ flyingZ = flying.getZ(); ++ } ++ ++ public Vector getDerailedVelocityMod() { ++ return new Vector(derailedX, derailedY, derailedZ); ++ } ++ ++ public void setDerailedVelocityMod(Vector derailed) { ++ derailedX = derailed.getX(); ++ derailedY = derailed.getY(); ++ derailedZ = derailed.getZ(); ++ } ++ // CraftBukkit end + } diff --git a/patches/minecraft/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java.patch b/patches/minecraft/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java.patch index 72540b70c4..bd276f3f87 100644 --- a/patches/minecraft/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java.patch @@ -1,5 +1,74 @@ --- a/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java +++ b/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java +@@ -16,6 +_,12 @@ + import net.minecraft.world.inventory.AbstractContainerMenu; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.level.Level; ++import org.bukkit.Location; ++import org.bukkit.craftbukkit.v1_20_R2.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.inventory.InventoryHolder; ++ ++import java.util.List; + + public abstract class AbstractMinecartContainer extends AbstractMinecart implements ContainerEntity { + private NonNullList itemStacks = NonNullList.withSize(36, ItemStack.EMPTY); +@@ -23,12 +_,55 @@ + private ResourceLocation lootTable; + private long lootTableSeed; + ++ // CraftBukkit start ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ public List getContents() { ++ return this.itemStacks; ++ } ++ ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ public List getViewers() { ++ return transaction; ++ } ++ ++ public InventoryHolder getOwner() { ++ org.bukkit.entity.Entity cart = getBukkitEntity(); ++ if(cart instanceof InventoryHolder) return (InventoryHolder) cart; ++ return null; ++ } ++ ++ @Override ++ public int getMaxStackSize() { ++ return maxStack; ++ } ++ ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ ++ @Override ++ public Location getLocation() { ++ return getBukkitEntity().getLocation(); ++ } ++ // CraftBukkit end ++ + protected AbstractMinecartContainer(EntityType p_38213_, Level p_38214_) { + super(p_38213_, p_38214_); ++ this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513 + } + + protected AbstractMinecartContainer(EntityType p_38207_, double p_38208_, double p_38209_, double p_38210_, Level p_38211_) { + super(p_38207_, p_38211_, p_38208_, p_38209_, p_38210_); ++ this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); // CraftBukkit - SPIGOT-3513 + } + + public void destroy(DamageSource p_38228_) { @@ -82,6 +_,8 @@ } diff --git a/patches/minecraft/net/minecraft/world/entity/vehicle/Boat.java.patch b/patches/minecraft/net/minecraft/world/entity/vehicle/Boat.java.patch index 94dfe0cb60..9d99f01614 100644 --- a/patches/minecraft/net/minecraft/world/entity/vehicle/Boat.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/vehicle/Boat.java.patch @@ -1,7 +1,16 @@ --- a/net/minecraft/world/entity/vehicle/Boat.java +++ b/net/minecraft/world/entity/vehicle/Boat.java -@@ -52,7 +_,7 @@ +@@ -50,9 +_,16 @@ + import net.minecraft.world.phys.shapes.BooleanOp; + import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; ++import org.bukkit.Location; ++import org.bukkit.craftbukkit.v1_20_R2.util.CraftLocation; ++import org.bukkit.entity.Vehicle; ++import org.bukkit.event.vehicle.VehicleDamageEvent; ++import org.bukkit.event.vehicle.VehicleDestroyEvent; ++import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; ++import org.bukkit.event.vehicle.VehicleMoveEvent; import org.joml.Vector3f; -public class Boat extends Entity implements VariantHolder { @@ -9,6 +18,117 @@ private static final EntityDataAccessor DATA_ID_HURT = SynchedEntityData.defineId(Boat.class, EntityDataSerializers.INT); private static final EntityDataAccessor DATA_ID_HURTDIR = SynchedEntityData.defineId(Boat.class, EntityDataSerializers.INT); private static final EntityDataAccessor DATA_ID_DAMAGE = SynchedEntityData.defineId(Boat.class, EntityDataSerializers.FLOAT); +@@ -91,6 +_,14 @@ + private float bubbleAngle; + private float bubbleAngleO; + ++ // CraftBukkit start ++ // PAIL: Some of these haven't worked since a few updates, and since 1.9 they are less and less applicable. ++ public double maxSpeed = 0.4D; ++ public double occupiedDeceleration = 0.2D; ++ public double unoccupiedDeceleration = -1; ++ public boolean landBoats = false; ++ // CraftBukkit end ++ + public Boat(EntityType p_38290_, Level p_38291_) { + super(p_38290_, p_38291_); + this.blocksBuilding = true; +@@ -164,6 +_,18 @@ + if (this.isInvulnerableTo(p_38319_)) { + return false; + } else if (!this.level().isClientSide && !this.isRemoved()) { ++ // CraftBukkit start ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ org.bukkit.entity.Entity attacker = (p_38319_.getEntity() == null) ? null : p_38319_.getEntity().getBukkitEntity(); ++ ++ VehicleDamageEvent event = new VehicleDamageEvent(vehicle, attacker, (double) p_38320_); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return false; ++ } ++ // f = event.getDamage(); // TODO Why don't we do this? ++ // CraftBukkit end + this.setHurtDir(-this.getHurtDir()); + this.setHurtTime(10); + this.setDamage(this.getDamage() + p_38320_ * 10.0F); +@@ -171,6 +_,15 @@ + this.gameEvent(GameEvent.ENTITY_DAMAGE, p_38319_.getEntity()); + boolean flag = p_38319_.getEntity() instanceof Player && ((Player)p_38319_.getEntity()).getAbilities().instabuild; + if (flag || this.getDamage() > 40.0F) { ++ // CraftBukkit start ++ VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, attacker); ++ this.level().getCraftServer().getPluginManager().callEvent(destroyEvent); ++ ++ if (destroyEvent.isCancelled()) { ++ this.setDamage(40F); // Maximize damage so this doesn't get triggered again right away ++ return true; ++ } ++ // CraftBukkit end + if (!flag && this.level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { + this.destroy(p_38319_); + } +@@ -208,9 +_,29 @@ + public void push(Entity p_38373_) { + if (p_38373_ instanceof Boat) { + if (p_38373_.getBoundingBox().minY < this.getBoundingBox().maxY) { ++ // CraftBukkit start ++ if (!this.isPassengerOfSameVehicle(p_38373_)) { ++ VehicleEntityCollisionEvent event = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), p_38373_.getBukkitEntity()); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ } ++ // CraftBukkit end + super.push(p_38373_); + } + } else if (p_38373_.getBoundingBox().minY <= this.getBoundingBox().minY) { ++ // CraftBukkit start ++ if (!this.isPassengerOfSameVehicle(p_38373_)) { ++ VehicleEntityCollisionEvent event = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), p_38373_.getBukkitEntity()); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ } ++ // CraftBukkit end + super.push(p_38373_); + } + +@@ -293,6 +_,7 @@ + return this.getDirection().getClockWise(); + } + ++ private Location lastLocation; // CraftBukkit + public void tick() { + this.oldStatus = this.status; + this.status = this.getStatus(); +@@ -332,6 +_,22 @@ + this.setDeltaMovement(Vec3.ZERO); + } + ++ // CraftBukkit start ++ org.bukkit.Server server = this.level().getCraftServer(); ++ org.bukkit.World bworld = this.level().getWorld(); ++ ++ Location to = CraftLocation.toBukkit(this.position(), bworld, this.getYRot(), this.getXRot()); ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ ++ server.getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleUpdateEvent(vehicle)); ++ ++ if (lastLocation != null && !lastLocation.equals(to)) { ++ VehicleMoveEvent event = new VehicleMoveEvent(vehicle, lastLocation, to); ++ server.getPluginManager().callEvent(event); ++ } ++ lastLocation = vehicle.getLocation(); ++ // CraftBukkit end ++ + this.tickBubbleColumn(); + + for(int i = 0; i <= 1; ++i) { @@ -483,7 +_,7 @@ for(int i2 = i1; i2 < j1; ++i2) { blockpos$mutableblockpos.set(l1, k1, i2); @@ -45,7 +165,35 @@ if (!fluidstate.isSource()) { return Boat.Status.UNDER_FLOWING_WATER; } -@@ -783,7 +_,7 @@ +@@ -769,21 +_,27 @@ + + this.causeFallDamage(this.fallDistance, 1.0F, this.damageSources().fall()); + if (!this.level().isClientSide && !this.isRemoved()) { +- this.kill(); +- if (this.level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { +- for(int i = 0; i < 3; ++i) { +- this.spawnAtLocation(this.getVariant().getPlanks()); +- } ++ // CraftBukkit start ++ Vehicle vehicle = (Vehicle) this.getBukkitEntity(); ++ VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, null); ++ this.level().getCraftServer().getPluginManager().callEvent(destroyEvent); ++ if (!destroyEvent.isCancelled()) { ++ this.kill(); ++ if (this.level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { ++ for (int i = 0; i < 3; ++i) { ++ this.spawnAtLocation(this.getVariant().getPlanks()); ++ } + +- for(int j = 0; j < 2; ++j) { +- this.spawnAtLocation(Items.STICK); ++ for (int j = 0; j < 2; ++j) { ++ this.spawnAtLocation(Items.STICK); ++ } + } + } +- } ++ } // CraftBukkit end } this.resetFallDistance(); diff --git a/patches/minecraft/net/minecraft/world/entity/vehicle/ChestBoat.java.patch b/patches/minecraft/net/minecraft/world/entity/vehicle/ChestBoat.java.patch index 41f8988921..b67bdad277 100644 --- a/patches/minecraft/net/minecraft/world/entity/vehicle/ChestBoat.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/vehicle/ChestBoat.java.patch @@ -1,6 +1,19 @@ --- a/net/minecraft/world/entity/vehicle/ChestBoat.java +++ b/net/minecraft/world/entity/vehicle/ChestBoat.java -@@ -204,6 +_,28 @@ +@@ -22,6 +_,12 @@ + import net.minecraft.world.item.Items; + import net.minecraft.world.level.Level; + import net.minecraft.world.level.gameevent.GameEvent; ++import org.bukkit.Location; ++import org.bukkit.craftbukkit.v1_20_R2.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.inventory.InventoryHolder; ++ ++import java.util.List; + + public class ChestBoat extends Boat implements HasCustomInventoryScreen, ContainerEntity { + private static final int CONTAINER_SIZE = 27; +@@ -204,7 +_,76 @@ this.itemStacks = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); } @@ -29,3 +42,51 @@ public void stopOpen(Player p_270286_) { this.level().gameEvent(GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of(p_270286_)); } ++ ++ // CraftBukkit start ++ public List transaction = new java.util.ArrayList(); ++ private int maxStack = MAX_STACK; ++ ++ @Override ++ public List getContents() { ++ return this.itemStacks; ++ } ++ ++ @Override ++ public void onOpen(CraftHumanEntity who) { ++ transaction.add(who); ++ } ++ ++ @Override ++ public void onClose(CraftHumanEntity who) { ++ transaction.remove(who); ++ } ++ ++ @Override ++ public List getViewers() { ++ return transaction; ++ } ++ ++ @Override ++ public InventoryHolder getOwner() { ++ org.bukkit.entity.Entity entity = getBukkitEntity(); ++ if (entity instanceof InventoryHolder) return (InventoryHolder) entity; ++ return null; ++ } ++ ++ @Override ++ public int getMaxStackSize() { ++ return maxStack; ++ } ++ ++ @Override ++ public void setMaxStackSize(int size) { ++ maxStack = size; ++ } ++ ++ @Override ++ public Location getLocation() { ++ return getBukkitEntity().getLocation(); ++ } ++ // CraftBukkit end + } diff --git a/patches/minecraft/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java.patch b/patches/minecraft/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java.patch index af5e32889f..b07cb7e54a 100644 --- a/patches/minecraft/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java.patch @@ -1,5 +1,13 @@ --- a/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java +++ b/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java +@@ -19,6 +_,7 @@ + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.command.CommandSender; + + public class MinecartCommandBlock extends AbstractMinecart { + static final EntityDataAccessor DATA_ID_COMMAND_NAME = SynchedEntityData.defineId(MinecartCommandBlock.class, EntityDataSerializers.STRING); @@ -78,6 +_,8 @@ } @@ -9,3 +17,17 @@ return this.commandBlock.usedBy(p_38522_); } +@@ -99,6 +_,13 @@ + } + + public class MinecartCommandBase extends BaseCommandBlock { ++ // CraftBukkit start ++ @Override ++ public CommandSender getBukkitSender(CommandSourceStack wrapper) { ++ return (org.bukkit.craftbukkit.v1_20_R2.entity.CraftMinecartCommand) MinecartCommandBlock.this.getBukkitEntity(); ++ } ++ // CraftBukkit end ++ + public ServerLevel getLevel() { + return (ServerLevel)MinecartCommandBlock.this.level(); + } diff --git a/patches/minecraft/net/minecraft/world/entity/vehicle/MinecartTNT.java.patch b/patches/minecraft/net/minecraft/world/entity/vehicle/MinecartTNT.java.patch new file mode 100644 index 0000000000..c480b1d418 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/vehicle/MinecartTNT.java.patch @@ -0,0 +1,28 @@ +--- a/net/minecraft/world/entity/vehicle/MinecartTNT.java ++++ b/net/minecraft/world/entity/vehicle/MinecartTNT.java +@@ -22,6 +_,7 @@ + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.level.material.FluidState; ++import org.bukkit.event.entity.ExplosionPrimeEvent; + + public class MinecartTNT extends AbstractMinecart { + private static final byte EVENT_PRIME = 10; +@@ -101,7 +_,16 @@ + d0 = 5.0D; + } + +- this.level().explode(this, p_259539_, (ExplosionDamageCalculator)null, this.getX(), this.getY(), this.getZ(), (float)(4.0D + this.random.nextDouble() * 1.5D * d0), false, Level.ExplosionInteraction.TNT); ++ // CraftBukkit start ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), (float) (4.0D + this.random.nextDouble() * 1.5D * d0), false); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ fuse = -1; ++ return; ++ } ++ this.level().explode(this, p_259539_, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.TNT); ++ // CraftBukkit end ++ + this.discard(); + } + From 4436d37bd4bebe13c6a0102af931d8eeeb1b15d1 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 20:52:23 +0100 Subject: [PATCH 10/26] Base animal patches --- .../world/entity/animal/Animal.java.patch | 91 ++++++++++++++++++- .../world/entity/animal/Bee.java.patch | 82 ++++++++++++++++- .../world/entity/animal/Bucketable.java.patch | 44 +++++++++ .../world/entity/animal/Cat.java.patch | 28 +++++- .../world/entity/animal/Chicken.java.patch | 12 +++ .../world/entity/animal/Cow.java.patch | 29 ++++++ .../world/entity/animal/Dolphin.java.patch | 59 ++++++++++++ .../world/entity/animal/Fox.java.patch | 59 ++++++++++++ .../world/entity/animal/IronGolem.java.patch | 11 +++ .../entity/animal/MushroomCow.java.patch | 59 ++++++++++-- .../world/entity/animal/Ocelot.java.patch | 2 +- .../world/entity/animal/Panda.java.patch | 29 ++++++ .../world/entity/animal/Parrot.java.patch | 37 +++++++- .../world/entity/animal/Pig.java.patch | 20 +++- .../world/entity/animal/Pufferfish.java.patch | 20 ++++ .../world/entity/animal/Rabbit.java.patch | 36 ++++++++ .../world/entity/animal/Sheep.java.patch | 68 +++++++++++++- .../world/entity/animal/SnowGolem.java.patch | 39 ++++++-- .../world/entity/animal/Turtle.java.patch | 41 +++++++++ .../world/entity/animal/Wolf.java.patch | 56 +++++++++++- 20 files changed, 793 insertions(+), 29 deletions(-) create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/Bucketable.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/Chicken.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/Cow.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/Dolphin.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/IronGolem.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/Panda.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/Pufferfish.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/Turtle.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Animal.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Animal.java.patch index 8300932dc2..904e5465da 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Animal.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Animal.java.patch @@ -1,6 +1,55 @@ --- a/net/minecraft/world/entity/animal/Animal.java +++ b/net/minecraft/world/entity/animal/Animal.java -@@ -202,6 +_,17 @@ +@@ -29,12 +_,16 @@ + import net.minecraft.world.level.LevelReader; + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.pathfinder.BlockPathTypes; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityBreedEvent; ++import org.bukkit.event.entity.EntityEnterLoveModeEvent; + + public abstract class Animal extends AgeableMob { + protected static final int PARENT_AGE_AFTER_BREEDING = 6000; + private int inLove; + @Nullable + private UUID loveCause; ++ public ItemStack breedItem; // CraftBukkit - Add breedItem variable + + protected Animal(EntityType p_27557_, Level p_27558_) { + super(p_27557_, p_27558_); +@@ -72,8 +_,14 @@ + if (this.isInvulnerableTo(p_27567_)) { + return false; + } else { +- this.inLove = 0; +- return super.hurt(p_27567_, p_27568_); ++ // CraftBukkit start ++ boolean result = super.hurt(p_27567_, p_27568_); ++ if (result) { ++ this.inLove = 0; ++ return super.hurt(p_27567_, p_27568_); ++ } ++ return result; ++ // CraftBukkit end + } + } + +@@ -156,7 +_,13 @@ + } + + public void setInLove(@Nullable Player p_27596_) { +- this.inLove = 600; ++ // CraftBukkit start ++ EntityEnterLoveModeEvent entityEnterLoveModeEvent = CraftEventFactory.callEntityEnterLoveModeEvent(p_27596_, this, 600); ++ if (entityEnterLoveModeEvent.isCancelled()) { ++ return; ++ } ++ this.inLove = entityEnterLoveModeEvent.getTicksInLove(); ++ // CraftBukkit end + if (p_27596_ != null) { + this.loveCause = p_27596_.getUUID(); + } +@@ -202,15 +_,43 @@ public void spawnChildFromBreeding(ServerLevel p_27564_, Animal p_27565_) { AgeableMob ageablemob = this.getBreedOffspring(p_27564_, p_27565_); @@ -18,3 +67,43 @@ if (ageablemob != null) { ageablemob.setBaby(true); ageablemob.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); + this.finalizeSpawnChildFromBreeding(p_27564_, p_27565_, ageablemob); +- p_27564_.addFreshEntityWithPassengers(ageablemob); ++ // CraftBukkit start - call EntityBreedEvent ++ ServerPlayer breeder = Optional.ofNullable(this.getLoveCause()).or(() -> { ++ return Optional.ofNullable(p_27565_.getLoveCause()); ++ }).orElse(null); ++ int experience = this.getRandom().nextInt(7) + 1; ++ EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityBreedEvent(ageablemob, this, p_27565_, breeder, this.breedItem, experience); ++ if (entityBreedEvent.isCancelled()) { ++ return; ++ } ++ experience = entityBreedEvent.getExperience(); ++ this.finalizeSpawnChildFromBreeding(p_27564_, p_27565_, ageablemob, experience); ++ p_27564_.addFreshEntityWithPassengers(ageablemob, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); ++ // CraftBukkit end + } + } + + public void finalizeSpawnChildFromBreeding(ServerLevel p_277963_, Animal p_277357_, @Nullable AgeableMob p_277516_) { ++ // CraftBukkit start ++ this.finalizeSpawnChildFromBreeding(p_277963_, p_277357_, p_277516_, this.getRandom().nextInt(7) + 1); ++ } ++ ++ public void finalizeSpawnChildFromBreeding(ServerLevel p_277963_, Animal p_277357_, @Nullable AgeableMob p_277516_, int experience) { + Optional.ofNullable(this.getLoveCause()).or(() -> { + return Optional.ofNullable(p_277357_.getLoveCause()); + }).ifPresent((p_277486_) -> { +@@ -223,7 +_,11 @@ + p_277357_.resetLove(); + p_277963_.broadcastEntityEvent(this, (byte)18); + if (p_277963_.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { +- p_277963_.addFreshEntity(new ExperienceOrb(p_277963_, this.getX(), this.getY(), this.getZ(), this.getRandom().nextInt(7) + 1)); ++ // CraftBukkit start - use event experience ++ if (experience > 0) { ++ p_277963_.addFreshEntity(new ExperienceOrb(p_277963_, this.getX(), this.getY(), this.getZ(), experience)); ++ } ++ // CraftBukkit end + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Bee.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Bee.java.patch index ef5ee0a259..e08260aa2e 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Bee.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Bee.java.patch @@ -1,5 +1,24 @@ --- a/net/minecraft/world/entity/animal/Bee.java +++ b/net/minecraft/world/entity/animal/Bee.java +@@ -87,6 +_,9 @@ + import net.minecraft.world.level.pathfinder.BlockPathTypes; + import net.minecraft.world.level.pathfinder.Path; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityPotionEffectEvent; ++import org.bukkit.event.entity.EntityTargetEvent; + + public class Bee extends Animal implements NeutralMob, FlyingAnimal { + public static final float FLAP_DEGREES_PER_TICK = 120.32113F; +@@ -230,7 +_,7 @@ + } + + if (i > 0) { +- ((LivingEntity)p_27722_).addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this); ++ ((LivingEntity)p_27722_).addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this, EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + } + @@ -473,7 +_,7 @@ return false; } else { @@ -9,7 +28,24 @@ } } -@@ -612,8 +_,18 @@ +@@ -600,11 +_,14 @@ + if (this.isInvulnerableTo(p_27762_)) { + return false; + } else { +- if (!this.level().isClientSide) { ++ // CraftBukkit start - Only stop pollinating if entity was damaged ++ boolean result = super.hurt(p_27762_, p_27763_); ++ if (result && !this.level().isClientSide) { ++ // CraftBukkit end + this.beePollinateGoal.stopPollinating(); + } + +- return super.hurt(p_27762_, p_27763_); ++ return result; // CraftBukkit + } + } + +@@ -612,10 +_,20 @@ return MobType.ARTHROPOD; } @@ -20,11 +56,49 @@ + + private void jumpInLiquidInternal() { this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.01D, 0.0D)); -+ } -+ + } + + @Override + public void jumpInFluid(net.minecraftforge.fluids.FluidType type) { + this.jumpInLiquidInternal(); ++ } ++ + public Vec3 getLeashOffset() { + return new Vec3(0.0D, (double)(0.5F * this.getEyeHeight()), (double)(this.getBbWidth() * 0.2F)); } +@@ -710,7 +_,7 @@ + @VisibleForDebug + public class BeeGoToHiveGoal extends Bee.BaseBeeGoal { + public static final int MAX_TRAVELLING_TICKS = 600; +- int travellingTicks = Bee.this.level().random.nextInt(10); ++ int travellingTicks = Bee.this.random.nextInt(10); // CraftBukkit - SPIGOT-7495: Give Bees another chance and let them use their own random, avoid concurrency issues + private static final int MAX_BLACKLISTED_TARGETS = 3; + final List blacklistedTargets = Lists.newArrayList(); + @Nullable +@@ -822,7 +_,7 @@ - public Vec3 getLeashOffset() { + public class BeeGoToKnownFlowerGoal extends Bee.BaseBeeGoal { + private static final int MAX_TRAVELLING_TICKS = 600; +- int travellingTicks = Bee.this.level().random.nextInt(10); ++ int travellingTicks = Bee.this.random.nextInt(10); // CraftBukkit - SPIGOT-7495: Give Bees another chance and let them use their own random, avoid concurrency issues + + BeeGoToKnownFlowerGoal() { + this.setFlags(EnumSet.of(Goal.Flag.MOVE)); +@@ -911,7 +_,7 @@ + ((BonemealableBlock)blockstate.getBlock()).performBonemeal((ServerLevel)Bee.this.level(), Bee.this.random, blockpos, blockstate); + } + +- if (blockstate1 != null) { ++ if (blockstate1 != null && CraftEventFactory.callEntityChangeBlockEvent(Bee.this, blockpos, blockstate1)) { // CraftBukkit + Bee.this.level().levelEvent(2005, blockpos, 0); + Bee.this.level().setBlockAndUpdate(blockpos, blockstate1); + Bee.this.incrementNumCropsGrownSincePollination(); +@@ -934,7 +_,7 @@ + + protected void alertOther(Mob p_28035_, LivingEntity p_28036_) { + if (p_28035_ instanceof Bee && this.mob.hasLineOfSight(p_28036_)) { +- p_28035_.setTarget(p_28036_); ++ p_28035_.setTarget(p_28036_, EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY, true); // CraftBukkit - reason + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Bucketable.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Bucketable.java.patch new file mode 100644 index 0000000000..3d4919e93d --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/Bucketable.java.patch @@ -0,0 +1,44 @@ +--- a/net/minecraft/world/entity/animal/Bucketable.java ++++ b/net/minecraft/world/entity/animal/Bucketable.java +@@ -3,6 +_,7 @@ + import java.util.Optional; + import net.minecraft.advancements.CriteriaTriggers; + import net.minecraft.nbt.CompoundTag; ++import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; + import net.minecraft.server.level.ServerPlayer; + import net.minecraft.sounds.SoundEvent; + import net.minecraft.world.InteractionHand; +@@ -14,6 +_,9 @@ + import net.minecraft.world.item.ItemUtils; + import net.minecraft.world.item.Items; + import net.minecraft.world.level.Level; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; ++import org.bukkit.event.player.PlayerBucketEntityEvent; + + public interface Bucketable { + boolean fromBucket(); +@@ -91,9 +_,22 @@ + static Optional bucketMobPickup(Player p_148829_, InteractionHand p_148830_, T p_148831_) { + ItemStack itemstack = p_148829_.getItemInHand(p_148830_); + if (itemstack.getItem() == Items.WATER_BUCKET && p_148831_.isAlive()) { +- p_148831_.playSound(p_148831_.getPickupSound(), 1.0F, 1.0F); ++ // CraftBukkit start ++ // p_148831_.playSound(p_148831_.getPickupSound(), 1.0F, 1.0F); + ItemStack itemstack1 = p_148831_.getBucketItemStack(); + p_148831_.saveToBucketTag(itemstack1); ++ ++ PlayerBucketEntityEvent playerBucketFishEvent = CraftEventFactory.callPlayerFishBucketEvent(p_148831_, p_148829_, itemstack, itemstack1, p_148830_); ++ itemstack1 = CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket()); ++ if (playerBucketFishEvent.isCancelled()) { ++ ((ServerPlayer) p_148829_).containerMenu.sendAllDataToRemote(); // We need to update inventory to resync client's bucket ++ ((ServerPlayer) p_148829_).connection.send(new ClientboundAddEntityPacket(p_148831_)); // We need to play out these packets as the client assumes the fish is gone ++ p_148831_.getEntityData().refresh((ServerPlayer) p_148829_); // Need to send data such as the display name to client ++ return Optional.of(InteractionResult.FAIL); ++ } ++ p_148831_.playSound(((Bucketable) p_148831_).getPickupSound(), 1.0F, 1.0F); ++ // CraftBukkit end ++ + ItemStack itemstack2 = ItemUtils.createFilledResult(itemstack, p_148829_, itemstack1, false); + p_148829_.setItemInHand(p_148830_, itemstack2); + Level level = p_148831_.level(); diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Cat.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Cat.java.patch index 2b3a885a0c..b6545b2523 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Cat.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Cat.java.patch @@ -15,7 +15,33 @@ } else if (this.isFood(itemstack)) { this.usePlayerItem(p_28153_, p_28154_, itemstack); - if (this.random.nextInt(3) == 0) { -+ if (this.random.nextInt(3) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, p_28153_)) { ++ if (this.random.nextInt(3) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, p_28153_) && !org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityTameEvent(this, p_28153_).isCancelled()) { // CraftBukkit this.tame(p_28153_); this.setOrderedToSit(true); this.level().broadcastEntityEvent(this, (byte)7); +@@ -551,7 +_,15 @@ + LootParams lootparams = (new LootParams.Builder((ServerLevel)this.cat.level())).withParameter(LootContextParams.ORIGIN, this.cat.position()).withParameter(LootContextParams.THIS_ENTITY, this.cat).create(LootContextParamSets.GIFT); + + for(ItemStack itemstack : loottable.getRandomItems(lootparams)) { +- this.cat.level().addFreshEntity(new ItemEntity(this.cat.level(), (double)blockpos$mutableblockpos.getX() - (double)Mth.sin(this.cat.yBodyRot * ((float)Math.PI / 180F)), (double)blockpos$mutableblockpos.getY(), (double)blockpos$mutableblockpos.getZ() + (double)Mth.cos(this.cat.yBodyRot * ((float)Math.PI / 180F)), itemstack)); ++ // CraftBukkit start ++ ItemEntity entityitem = new ItemEntity(this.cat.level(), (double) blockpos$mutableblockpos.getX() - (double) Mth.sin(this.cat.yBodyRot * 0.017453292F), (double) blockpos$mutableblockpos.getY(), (double) blockpos$mutableblockpos.getZ() + (double) Mth.cos(this.cat.yBodyRot * 0.017453292F), itemstack); ++ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.cat.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); ++ entityitem.level().getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ continue; ++ } ++ this.cat.level().addFreshEntity(entityitem); ++ // CraftBukkit end + } + + } +@@ -579,7 +_,7 @@ + + static class CatTemptGoal extends TemptGoal { + @Nullable +- private Player selectedPlayer; ++ private LivingEntity selectedPlayer; // CraftBukkit + private final Cat cat; + + public CatTemptGoal(Cat p_28219_, double p_28220_, Ingredient p_28221_, boolean p_28222_) { diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Chicken.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Chicken.java.patch new file mode 100644 index 0000000000..ecfecb3973 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/Chicken.java.patch @@ -0,0 +1,12 @@ +--- a/net/minecraft/world/entity/animal/Chicken.java ++++ b/net/minecraft/world/entity/animal/Chicken.java +@@ -90,7 +_,9 @@ + this.flap += this.flapping * 2.0F; + if (!this.level().isClientSide && this.isAlive() && !this.isBaby() && !this.isChickenJockey() && --this.eggTime <= 0) { + this.playSound(SoundEvents.CHICKEN_EGG, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); ++ this.forceDrops = true; // CraftBukkit + this.spawnAtLocation(Items.EGG); ++ this.forceDrops = false; // CraftBukkit + this.gameEvent(GameEvent.ENTITY_PLACE); + this.eggTime = this.random.nextInt(6000) + 6000; + } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Cow.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Cow.java.patch new file mode 100644 index 0000000000..b69c8d5d0c --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/Cow.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/world/entity/animal/Cow.java ++++ b/net/minecraft/world/entity/animal/Cow.java +@@ -31,6 +_,9 @@ + import net.minecraft.world.item.crafting.Ingredient; + import net.minecraft.world.level.Level; + import net.minecraft.world.level.block.state.BlockState; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; ++import org.bukkit.event.player.PlayerBucketFillEvent; + import org.joml.Vector3f; + + public class Cow extends Animal { +@@ -76,8 +_,15 @@ + public InteractionResult mobInteract(Player p_28298_, InteractionHand p_28299_) { + ItemStack itemstack = p_28298_.getItemInHand(p_28299_); + if (itemstack.is(Items.BUCKET) && !this.isBaby()) { ++ // CraftBukkit start - Got milk? ++ PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) p_28298_.level(), p_28298_, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, p_28299_); ++ ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ // CraftBukkit end + p_28298_.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F); +- ItemStack itemstack1 = ItemUtils.createFilledResult(itemstack, p_28298_, Items.MILK_BUCKET.getDefaultInstance()); ++ ItemStack itemstack1 = ItemUtils.createFilledResult(itemstack, p_28298_, CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit + p_28298_.setItemInHand(p_28299_, itemstack1); + return InteractionResult.sidedSuccess(this.level().isClientSide); + } else { diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Dolphin.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Dolphin.java.patch new file mode 100644 index 0000000000..b4addd4d6a --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/Dolphin.java.patch @@ -0,0 +1,59 @@ +--- a/net/minecraft/world/entity/animal/Dolphin.java ++++ b/net/minecraft/world/entity/animal/Dolphin.java +@@ -60,8 +_,16 @@ + import net.minecraft.world.level.ServerLevelAccessor; + import net.minecraft.world.level.pathfinder.PathComputationType; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityPotionEffectEvent; + + public class Dolphin extends WaterAnimal { ++ // CraftBukkit start - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() ++ @Override ++ public int getDefaultMaxAirSupply() { ++ return TOTAL_AIR_SUPPLY; ++ } ++ // CraftBukkit end + private static final EntityDataAccessor TREASURE_POS = SynchedEntityData.defineId(Dolphin.class, EntityDataSerializers.BLOCK_POS); + private static final EntityDataAccessor GOT_FISH = SynchedEntityData.defineId(Dolphin.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor MOISTNESS_LEVEL = SynchedEntityData.defineId(Dolphin.class, EntityDataSerializers.INT); +@@ -178,7 +_,7 @@ + } + + public int getMaxAirSupply() { +- return 4800; ++ return maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() + } + + protected int increaseAirSupply(int p_28389_) { +@@ -214,6 +_,12 @@ + if (this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty()) { + ItemStack itemstack = p_28357_.getItem(); + if (this.canHoldItem(itemstack)) { ++ // CraftBukkit start - call EntityPickupItemEvent ++ if (CraftEventFactory.callEntityPickupItemEvent(this, p_28357_, 0, false).isCancelled()) { ++ return; ++ } ++ itemstack = p_28357_.getItem(); // CraftBukkit- update ItemStack from event ++ // CraftBukkit start + this.onItemPickup(p_28357_); + this.setItemSlot(EquipmentSlot.MAINHAND, itemstack); + this.setGuaranteedDrop(EquipmentSlot.MAINHAND); +@@ -445,7 +_,7 @@ + } + + public void start() { +- this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin); ++ this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin, EntityPotionEffectEvent.Cause.DOLPHIN); // CraftBukkit + } + + public void stop() { +@@ -462,7 +_,7 @@ + } + + if (this.player.isSwimming() && this.player.level().random.nextInt(6) == 0) { +- this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin); ++ this.player.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, 100), this.dolphin, EntityPotionEffectEvent.Cause.DOLPHIN); // CraftBukkit + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Fox.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Fox.java.patch index 05d123ad3a..bda8f7d5f5 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Fox.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Fox.java.patch @@ -1,5 +1,15 @@ --- a/net/minecraft/world/entity/animal/Fox.java +++ b/net/minecraft/world/entity/animal/Fox.java +@@ -482,7 +_,8 @@ + + protected void pickUpItem(ItemEntity p_28514_) { + ItemStack itemstack = p_28514_.getItem(); +- if (this.canHoldItem(itemstack)) { ++ if (!org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityPickupItemEvent(this, p_28514_, itemstack.getCount() - 1, !this.canHoldItem(itemstack)).isCancelled()) { // CraftBukkit - call EntityPickupItemEvent ++ itemstack = p_28514_.getItem(); // CraftBukkit - update ItemStack from event + int i = itemstack.getCount(); + if (i > 1) { + this.dropItemStack(itemstack.split(i - 1)); @@ -655,13 +_,16 @@ } @@ -36,6 +46,43 @@ if (fox != null) { ServerPlayer serverplayer = this.animal.getLoveCause(); ServerPlayer serverplayer1 = this.partner.getLoveCause(); +@@ -825,6 +_,17 @@ + serverplayer2 = serverplayer1; + } + ++ // CraftBukkit start - call EntityBreedEvent ++ fox.setAge(-24000); ++ fox.moveTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F); ++ int experience = this.animal.getRandom().nextInt(7) + 1; ++ org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityBreedEvent(fox, animal, partner, serverplayer, this.animal.breedItem, experience); ++ if (entityBreedEvent.isCancelled()) { ++ return; ++ } ++ experience = entityBreedEvent.getExperience(); ++ // CraftBukkit end ++ + if (serverplayer1 != null && serverplayer != serverplayer1) { + fox.addTrustedUUID(serverplayer1.getUUID()); + } +@@ -838,12 +_,15 @@ + this.partner.setAge(6000); + this.animal.resetLove(); + this.partner.resetLove(); +- fox.setAge(-24000); +- fox.moveTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F); +- serverlevel.addFreshEntityWithPassengers(fox); ++ serverlevel.addFreshEntityWithPassengers(fox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason + this.level.broadcastEntityEvent(this.animal, (byte)18); + if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { + this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), this.animal.getRandom().nextInt(7) + 1)); ++ // CraftBukkit start - use event experience ++ if (experience > 0) { ++ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience)); ++ } ++ // CraftBukkit end + } + + } @@ -886,7 +_,7 @@ } @@ -45,6 +92,18 @@ BlockState blockstate = Fox.this.level().getBlockState(this.blockPos); if (blockstate.is(Blocks.SWEET_BERRY_BUSH)) { this.pickSweetBerries(blockstate); +@@ -904,6 +_,11 @@ + private void pickSweetBerries(BlockState p_148929_) { + int i = p_148929_.getValue(SweetBerryBushBlock.AGE); + p_148929_.setValue(SweetBerryBushBlock.AGE, Integer.valueOf(1)); ++ // CraftBukkit start - call EntityChangeBlockEvent ++ if (!org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityChangeBlockEvent(Fox.this, this.blockPos, p_148929_.setValue(SweetBerryBushBlock.AGE, 1))) { ++ return; ++ } ++ // CraftBukkit end + int j = 1 + Fox.this.level().random.nextInt(2) + (i == 3 ? 1 : 0); + ItemStack itemstack = Fox.this.getItemBySlot(EquipmentSlot.MAINHAND); + if (itemstack.isEmpty()) { @@ -942,7 +_,7 @@ } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/IronGolem.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/IronGolem.java.patch new file mode 100644 index 0000000000..884af185ee --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/IronGolem.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/animal/IronGolem.java ++++ b/net/minecraft/world/entity/animal/IronGolem.java +@@ -96,7 +_,7 @@ + + protected void doPush(Entity p_28839_) { + if (p_28839_ instanceof Enemy && !(p_28839_ instanceof Creeper) && this.getRandom().nextInt(20) == 0) { +- this.setTarget((LivingEntity)p_28839_); ++ this.setTarget((LivingEntity)p_28839_, org.bukkit.event.entity.EntityTargetLivingEntityEvent.TargetReason.COLLISION, true); // CraftBukkit - set reason; + } + + super.doPush(p_28839_); diff --git a/patches/minecraft/net/minecraft/world/entity/animal/MushroomCow.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/MushroomCow.java.patch index 5b54a61b24..f6909f5d3e 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/MushroomCow.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/MushroomCow.java.patch @@ -1,24 +1,41 @@ --- a/net/minecraft/world/entity/animal/MushroomCow.java +++ b/net/minecraft/world/entity/animal/MushroomCow.java -@@ -41,7 +_,7 @@ +@@ -1,5 +_,6 @@ + package net.minecraft.world.entity.animal; + ++import java.util.Collections; + import java.util.List; + import java.util.Optional; + import java.util.UUID; +@@ -40,8 +_,12 @@ + import net.minecraft.world.level.block.SuspiciousEffectHolder; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.gameevent.GameEvent; ++import org.bukkit.Bukkit; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityDropItemEvent; ++import org.bukkit.event.entity.EntityTransformEvent; -public class MushroomCow extends Cow implements Shearable, VariantHolder { +public class MushroomCow extends Cow implements Shearable, net.minecraftforge.common.IForgeShearable { private static final EntityDataAccessor DATA_TYPE = SynchedEntityData.defineId(MushroomCow.class, EntityDataSerializers.STRING); private static final int MUTATE_CHANCE = 1024; private static final String TAG_STEW_EFFECTS = "stew_effects"; -@@ -102,7 +_,7 @@ +@@ -102,7 +_,12 @@ this.playSound(soundevent, 1.0F, 1.0F); return InteractionResult.sidedSuccess(this.level().isClientSide); - } else if (itemstack.is(Items.SHEARS) && this.readyForShearing()) { + } else if (false && itemstack.getItem() == Items.SHEARS && this.readyForShearing()) { //Forge: Moved to onSheared ++ // CraftBukkit start ++ if (!CraftEventFactory.handlePlayerShearEntityEvent(p_28941_, this, itemstack, p_28942_)) { ++ return InteractionResult.PASS; ++ } ++ // CraftBukkit end this.shear(SoundSource.PLAYERS); this.gameEvent(GameEvent.SHEAR, p_28941_); if (!this.level().isClientSide) { -@@ -141,7 +_,17 @@ +@@ -141,13 +_,33 @@ } } @@ -29,17 +46,45 @@ + } + public void shear(SoundSource p_28924_) { -+ shearInternal(p_28924_).forEach(s -> this.level().addFreshEntity(new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), s))); ++ for (ItemStack itemStack : shearInternal(p_28924_)) { ++ // CraftBukkit start ++ ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), itemStack); ++ EntityDropItemEvent event = new EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); ++ Bukkit.getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ continue; ++ } ++ this.level().addFreshEntity(itemEntity); ++ // CraftBukkit end ++ } + } + + private java.util.List shearInternal(SoundSource p_28924_) { this.level().playSound((Player)null, this, SoundEvents.MOOSHROOM_SHEAR, p_28924_, 1.0F, 1.0F); if (!this.level().isClientSide()) { Cow cow = EntityType.COW.create(this.level()); -@@ -163,11 +_,14 @@ - cow.setInvulnerable(this.isInvulnerable()); - this.level().addFreshEntity(cow); + if (cow != null) { + ((ServerLevel)this.level()).sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(0.5D), this.getZ(), 1, 0.0D, 0.0D, 0.0D, 0.0D); +- this.discard(); ++ // this.discard(); // CraftBukkit - moved down + cow.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); + cow.setHealth(this.getHealth()); + cow.yBodyRot = this.yBodyRot; +@@ -161,13 +_,23 @@ + } + cow.setInvulnerable(this.isInvulnerable()); +- this.level().addFreshEntity(cow); +- ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityTransformEvent(this, cow, EntityTransformEvent.TransformReason.SHEARED).isCancelled()) { ++ return Collections.emptyList(); ++ } ++ this.level().addFreshEntity(cow, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SHEARED); ++ ++ this.discard(); // CraftBukkit - from above ++ // CraftBukkit end ++ + java.util.List items = new java.util.ArrayList<>(); for(int i = 0; i < 5; ++i) { - this.level().addFreshEntity(new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), new ItemStack(this.getVariant().blockState.getBlock()))); diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Ocelot.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Ocelot.java.patch index 757464f26f..405dec7c25 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Ocelot.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Ocelot.java.patch @@ -5,7 +5,7 @@ this.usePlayerItem(p_29021_, p_29022_, itemstack); if (!this.level().isClientSide) { - if (this.random.nextInt(3) == 0) { -+ if (this.random.nextInt(3) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, p_29021_)) { ++ if (this.random.nextInt(3) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, p_29021_) && !org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityTameEvent(this, p_29021_).isCancelled()) { // CraftBukkit - added event call and isCancelled check this.setTrusting(true); this.spawnTrustingParticles(true); this.level().broadcastEntityEvent(this, (byte)41); diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Panda.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Panda.java.patch new file mode 100644 index 0000000000..f97a5d739e --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/Panda.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/world/entity/animal/Panda.java ++++ b/net/minecraft/world/entity/animal/Panda.java +@@ -62,6 +_,8 @@ + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.level.gameevent.GameEvent; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityTargetEvent; + import org.joml.Vector3f; + + public class Panda extends Animal { +@@ -508,7 +_,7 @@ + } + + protected void pickUpItem(ItemEntity p_29121_) { +- if (this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty() && PANDA_ITEMS.test(p_29121_)) { ++ if (!CraftEventFactory.callEntityPickupItemEvent(this, p_29121_, 0, !(this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty() && Panda.PANDA_ITEMS.test(p_29121_))).isCancelled()) { // CraftBukkit + this.onItemPickup(p_29121_); + ItemStack itemstack = p_29121_.getItem(); + this.setItemSlot(EquipmentSlot.MAINHAND, itemstack); +@@ -834,7 +_,7 @@ + + protected void alertOther(Mob p_29295_, LivingEntity p_29296_) { + if (p_29295_ instanceof Panda && p_29295_.isAggressive()) { +- p_29295_.setTarget(p_29296_); ++ p_29295_.setTarget(p_29296_, EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY, true); // CraftBukkit + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Parrot.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Parrot.java.patch index b66a54c1fe..a2162bf679 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Parrot.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Parrot.java.patch @@ -5,7 +5,42 @@ if (!this.level().isClientSide) { - if (this.random.nextInt(10) == 0) { -+ if (this.random.nextInt(10) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, p_29414_)) { ++ if (this.random.nextInt(10) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, p_29414_) && !org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityTameEvent(this, p_29414_).isCancelled()) { // CraftBukkit this.tame(p_29414_); this.level().broadcastEntityEvent(this, (byte)7); } else { +@@ -260,7 +_,7 @@ + itemstack.shrink(1); + } + +- this.addEffect(new MobEffectInstance(MobEffects.POISON, 900)); ++ this.addEffect(new MobEffectInstance(MobEffects.POISON, 900), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD); // CraftBukkit + if (p_29414_.isCreative() || !this.isInvulnerable()) { + this.hurt(this.damageSources().playerAttack(p_29414_), Float.MAX_VALUE); + } +@@ -353,7 +_,7 @@ + } + + public boolean isPushable() { +- return true; ++ return super.isPushable(); // CraftBukkit - collidable API + } + + protected void doPush(Entity p_29367_) { +@@ -366,11 +_,14 @@ + if (this.isInvulnerableTo(p_29378_)) { + return false; + } else { +- if (!this.level().isClientSide) { ++ // CraftBukkit start ++ boolean result = super.hurt(p_29378_, p_29379_); ++ if (!this.level().isClientSide && result) { ++ // CraftBukkit end + this.setOrderedToSit(false); + } + +- return super.hurt(p_29378_, p_29379_); ++ return result; // CraftBukkit + } + } + diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Pig.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Pig.java.patch index b48a196d7f..305f63b3da 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Pig.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Pig.java.patch @@ -1,5 +1,13 @@ --- a/net/minecraft/world/entity/animal/Pig.java +++ b/net/minecraft/world/entity/animal/Pig.java +@@ -47,6 +_,7 @@ + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; + import org.joml.Vector3f; + + public class Pig extends Animal implements ItemSteerable, Saddleable { @@ -203,7 +_,7 @@ } @@ -9,11 +17,19 @@ ZombifiedPiglin zombifiedpiglin = EntityType.ZOMBIFIED_PIGLIN.create(p_29473_); if (zombifiedpiglin != null) { zombifiedpiglin.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.GOLDEN_SWORD)); -@@ -216,6 +_,7 @@ +@@ -216,7 +_,14 @@ } zombifiedpiglin.setPersistenceRequired(); +- p_29473_.addFreshEntity(zombifiedpiglin); + net.minecraftforge.event.ForgeEventFactory.onLivingConvert(this, zombifiedpiglin); - p_29473_.addFreshEntity(zombifiedpiglin); ++ // CraftBukkit start ++ if (CraftEventFactory.callPigZapEvent(this, p_29474_, zombifiedpiglin).isCancelled()) { ++ return; ++ } ++ // CraftBukkit - added a reason for spawning this creature ++ p_29473_.addFreshEntity(zombifiedpiglin, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); ++ // CraftBukkit end this.discard(); } else { + super.thunderHit(p_29473_, p_29474_); diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Pufferfish.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Pufferfish.java.patch new file mode 100644 index 0000000000..23137844c7 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/Pufferfish.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/entity/animal/Pufferfish.java ++++ b/net/minecraft/world/entity/animal/Pufferfish.java +@@ -132,7 +_,7 @@ + private void touch(Mob p_29606_) { + int i = this.getPuffState(); + if (p_29606_.hurt(this.damageSources().mobAttack(this), (float)(1 + i))) { +- p_29606_.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * i, 0), this); ++ p_29606_.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * i, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + this.playSound(SoundEvents.PUFFER_FISH_STING, 1.0F, 1.0F); + } + +@@ -145,7 +_,7 @@ + ((ServerPlayer)p_29617_).connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.PUFFER_FISH_STING, 0.0F)); + } + +- p_29617_.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * i, 0), this); ++ p_29617_.addEffect(new MobEffectInstance(MobEffects.POISON, 60 * i, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Rabbit.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Rabbit.java.patch index 835b778c32..e6868fdbc9 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Rabbit.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Rabbit.java.patch @@ -1,5 +1,21 @@ --- a/net/minecraft/world/entity/animal/Rabbit.java +++ b/net/minecraft/world/entity/animal/Rabbit.java +@@ -66,6 +_,7 @@ + import net.minecraft.world.level.gameevent.GameEvent; + import net.minecraft.world.level.pathfinder.Path; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; + + public class Rabbit extends Animal implements VariantHolder { + public static final double STROLL_SPEED_MOD = 0.6D; +@@ -88,7 +_,6 @@ + super(p_29656_, p_29657_); + this.jumpControl = new Rabbit.RabbitJumpControl(this); + this.moveControl = new Rabbit.RabbitMoveControl(this); +- this.setSpeedModifier(0.0D); + } + + protected void registerGoals() { @@ -515,7 +_,7 @@ public boolean canUse() { @@ -9,3 +25,23 @@ return false; } +@@ -541,9 +_,19 @@ + if (this.canRaid && block instanceof CarrotBlock) { + int i = blockstate.getValue(CarrotBlock.AGE); + if (i == 0) { ++ // CraftBukkit start ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockpos, Blocks.AIR.defaultBlockState())) { ++ return; ++ } ++ // CraftBukkit end + level.setBlock(blockpos, Blocks.AIR.defaultBlockState(), 2); + level.destroyBlock(blockpos, true, this.rabbit); + } else { ++ // CraftBukkit start ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockpos, blockstate.setValue(CarrotBlock.AGE, i - 1))) { ++ return; ++ } ++ // CraftBukkit end + level.setBlock(blockpos, blockstate.setValue(CarrotBlock.AGE, Integer.valueOf(i - 1)), 2); + level.gameEvent(GameEvent.BLOCK_CHANGE, blockpos, GameEvent.Context.of(this.rabbit)); + level.levelEvent(2001, blockpos, Block.getId(blockstate)); diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Sheep.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Sheep.java.patch index da4dddc8f2..99759b4860 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Sheep.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Sheep.java.patch @@ -1,7 +1,24 @@ --- a/net/minecraft/world/entity/animal/Sheep.java +++ b/net/minecraft/world/entity/animal/Sheep.java -@@ -63,7 +_,7 @@ +@@ -44,10 +_,7 @@ + import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; + import net.minecraft.world.entity.item.ItemEntity; + import net.minecraft.world.entity.player.Player; +-import net.minecraft.world.inventory.AbstractContainerMenu; +-import net.minecraft.world.inventory.CraftingContainer; +-import net.minecraft.world.inventory.MenuType; +-import net.minecraft.world.inventory.TransientCraftingContainer; ++import net.minecraft.world.inventory.*; + import net.minecraft.world.item.DyeColor; + import net.minecraft.world.item.DyeItem; + import net.minecraft.world.item.ItemStack; +@@ -61,9 +_,12 @@ + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.storage.loot.BuiltInLootTables; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.SheepRegrowWoolEvent; ++import org.bukkit.inventory.InventoryView; import org.joml.Vector3f; -public class Sheep extends Animal implements Shearable { @@ -9,15 +26,62 @@ private static final int EAT_ANIMATION_TICKS = 40; private static final EntityDataAccessor DATA_WOOL_ID = SynchedEntityData.defineId(Sheep.class, EntityDataSerializers.BYTE); private static final Map ITEM_BY_DYE = Util.make(Maps.newEnumMap(DyeColor.class), (p_29841_) -> { -@@ -235,7 +_,7 @@ +@@ -235,8 +_,13 @@ public InteractionResult mobInteract(Player p_29853_, InteractionHand p_29854_) { ItemStack itemstack = p_29853_.getItemInHand(p_29854_); - if (itemstack.is(Items.SHEARS)) { + if (false && itemstack.getItem() == Items.SHEARS) { //Forge: Moved to onSheared if (!this.level().isClientSide && this.readyForShearing()) { ++ // CraftBukkit start ++ if (!CraftEventFactory.handlePlayerShearEntityEvent(p_29853_, this, itemstack, p_29854_)) { ++ return InteractionResult.PASS; ++ } ++ // CraftBukkit end this.shear(SoundSource.PLAYERS); this.gameEvent(GameEvent.SHEAR, p_29853_); + itemstack.hurtAndBreak(1, p_29853_, (p_29822_) -> { +@@ -257,7 +_,9 @@ + int i = 1 + this.random.nextInt(3); + + for(int j = 0; j < i; ++j) { ++ this.forceDrops = true; // CraftBukkit + ItemEntity itementity = this.spawnAtLocation(ITEM_BY_DYE.get(this.getColor()), 1); ++ this.forceDrops = false; // CraftBukkit + if (itementity != null) { + itementity.setDeltaMovement(itementity.getDeltaMovement().add((double)((this.random.nextFloat() - this.random.nextFloat()) * 0.1F), (double)(this.random.nextFloat() * 0.05F), (double)((this.random.nextFloat() - this.random.nextFloat()) * 0.1F))); + } +@@ -346,6 +_,12 @@ + } + + public void ate() { ++ // CraftBukkit start ++ SheepRegrowWoolEvent event = new SheepRegrowWoolEvent((org.bukkit.entity.Sheep) this.getBukkitEntity()); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) return; ++ // CraftBukkit end + super.ate(); + this.setSheared(false); + if (this.isBaby()) { +@@ -380,9 +_,17 @@ + public boolean stillValid(Player p_29888_) { + return false; + } ++ ++ // CraftBukkit start ++ @Override ++ public InventoryView getBukkitView() { ++ return null; // TODO: O.O ++ } ++ // CraftBukkit end + }, 2, 1); + craftingcontainer.setItem(0, new ItemStack(DyeItem.byColor(p_29832_))); + craftingcontainer.setItem(1, new ItemStack(DyeItem.byColor(p_29833_))); ++ ((TransientCraftingContainer) craftingcontainer).resultInventory = new ResultContainer(); // CraftBukkit - add result slot for event + return craftingcontainer; + } + @@ -392,5 +_,27 @@ protected Vector3f getPassengerAttachmentPoint(Entity p_297780_, EntityDimensions p_298437_, float p_300315_) { diff --git a/patches/minecraft/net/minecraft/world/entity/animal/SnowGolem.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/SnowGolem.java.patch index 8dc7847ec7..7cd60873e4 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/SnowGolem.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/SnowGolem.java.patch @@ -1,16 +1,22 @@ --- a/net/minecraft/world/entity/animal/SnowGolem.java +++ b/net/minecraft/world/entity/animal/SnowGolem.java -@@ -40,7 +_,7 @@ +@@ -39,8 +_,9 @@ + import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; -public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackMob { +public class SnowGolem extends AbstractGolem implements Shearable, RangedAttackMob, net.minecraftforge.common.IForgeShearable { private static final EntityDataAccessor DATA_PUMPKIN_ID = SynchedEntityData.defineId(SnowGolem.class, EntityDataSerializers.BYTE); private static final byte PUMPKIN_FLAG = 16; private static final float EYE_HEIGHT = 1.7F; -@@ -92,7 +_,7 @@ - this.hurt(this.damageSources().onFire(), 1.0F); +@@ -89,10 +_,10 @@ + super.aiStep(); + if (!this.level().isClientSide) { + if (this.level().getBiome(this.blockPosition()).is(BiomeTags.SNOW_GOLEM_MELTS)) { +- this.hurt(this.damageSources().onFire(), 1.0F); ++ this.hurt(this.damageSources().melting, 1.0F); // CraftBukkit - DamageSource.BURN -> CraftEventFactory.MELTING } - if (!this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { @@ -18,24 +24,45 @@ return; } -@@ -103,7 +_,7 @@ +@@ -103,8 +_,12 @@ int k = Mth.floor(this.getY()); int l = Mth.floor(this.getZ() + (double)((float)(i / 2 % 2 * 2 - 1) * 0.25F)); BlockPos blockpos = new BlockPos(j, k, l); - if (this.level().getBlockState(blockpos).isAir() && blockstate.canSurvive(this.level(), blockpos)) { +- this.level().setBlockAndUpdate(blockpos, blockstate); + if (this.level().isEmptyBlock(blockpos) && blockstate.canSurvive(this.level(), blockpos)) { - this.level().setBlockAndUpdate(blockpos, blockstate); ++ // CraftBukkit start ++ if (!CraftEventFactory.handleBlockFormEvent(this.level(), blockpos, blockstate, this)) { ++ continue; ++ } ++ // CraftBukkit end this.level().gameEvent(GameEvent.BLOCK_PLACE, blockpos, GameEvent.Context.of(this, blockstate)); } -@@ -130,7 +_,7 @@ + } +@@ -130,7 +_,12 @@ protected InteractionResult mobInteract(Player p_29920_, InteractionHand p_29921_) { ItemStack itemstack = p_29920_.getItemInHand(p_29921_); - if (itemstack.is(Items.SHEARS) && this.readyForShearing()) { + if (false && itemstack.getItem() == Items.SHEARS && this.readyForShearing()) { //Forge: Moved to onSheared ++ // CraftBukkit start ++ if (!CraftEventFactory.handlePlayerShearEntityEvent(p_29920_, this, itemstack, p_29921_)) { ++ return InteractionResult.PASS; ++ } ++ // CraftBukkit end this.shear(SoundSource.PLAYERS); this.gameEvent(GameEvent.SHEAR, p_29920_); if (!this.level().isClientSide) { +@@ -149,7 +_,9 @@ + this.level().playSound((Player)null, this, SoundEvents.SNOW_GOLEM_SHEAR, p_29907_, 1.0F, 1.0F); + if (!this.level().isClientSide()) { + this.setPumpkin(false); ++ this.forceDrops = true; // CraftBukkit + this.spawnAtLocation(new ItemStack(Items.CARVED_PUMPKIN), 1.7F); ++ this.forceDrops = false; // CraftBukkit + } + + } @@ -189,5 +_,22 @@ public Vec3 getLeashOffset() { diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Turtle.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Turtle.java.patch new file mode 100644 index 0000000000..3f52909c35 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/Turtle.java.patch @@ -0,0 +1,41 @@ +--- a/net/minecraft/world/entity/animal/Turtle.java ++++ b/net/minecraft/world/entity/animal/Turtle.java +@@ -287,7 +_,9 @@ + protected void ageBoundaryReached() { + super.ageBoundaryReached(); + if (!this.isBaby() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { ++ this.forceDrops = true; // CraftBukkit + this.spawnAtLocation(Items.SCUTE, 1); ++ this.forceDrops = false; // CraftBukkit + } + + } +@@ -311,7 +_,9 @@ + } + + public void thunderHit(ServerLevel p_30140_, LightningBolt p_30141_) { ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.entityDamage = p_30141_; // CraftBukkit + this.hurt(this.damageSources().lightningBolt(), Float.MAX_VALUE); ++ org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.entityDamage = null; // CraftBukkit + } + + protected Vector3f getPassengerAttachmentPoint(Entity p_297922_, EntityDimensions p_299342_, float p_297986_) { +@@ -476,11 +_,13 @@ + this.turtle.setLayingEgg(true); + } else if (this.turtle.layEggCounter > this.adjustedTickDelay(200)) { + Level level = this.turtle.level(); +- level.playSound((Player)null, blockpos, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + level.random.nextFloat() * 0.2F); +- BlockPos blockpos1 = this.blockPos.above(); +- BlockState blockstate = Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, Integer.valueOf(this.turtle.random.nextInt(4) + 1)); +- level.setBlock(blockpos1, blockstate, 3); +- level.gameEvent(GameEvent.BLOCK_PLACE, blockpos1, GameEvent.Context.of(this.turtle, blockstate)); ++ if (org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1))) { // CraftBukkit ++ level.playSound((Player) null, blockpos, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + level.random.nextFloat() * 0.2F); ++ BlockPos blockpos1 = this.blockPos.above(); ++ BlockState blockstate = Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, Integer.valueOf(this.turtle.random.nextInt(4) + 1)); ++ level.setBlock(blockpos1, blockstate, 3); ++ level.gameEvent(GameEvent.BLOCK_PLACE, blockpos1, GameEvent.Context.of(this.turtle, blockstate)); ++ } // CraftBukkit + this.turtle.setHasEgg(false); + this.turtle.setLayingEgg(false); + this.turtle.setInLoveTime(600); diff --git a/patches/minecraft/net/minecraft/world/entity/animal/Wolf.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/Wolf.java.patch index 242e2bfa40..eb4be8c988 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/Wolf.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/Wolf.java.patch @@ -1,10 +1,53 @@ --- a/net/minecraft/world/entity/animal/Wolf.java +++ b/net/minecraft/world/entity/animal/Wolf.java +@@ -68,6 +_,9 @@ + import net.minecraft.world.level.gameevent.GameEvent; + import net.minecraft.world.level.pathfinder.BlockPathTypes; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityRegainHealthEvent; ++import org.bukkit.event.entity.EntityTargetEvent; + import org.joml.Vector3f; + + public class Wolf extends TamableAnimal implements NeutralMob { +@@ -284,15 +_,19 @@ + return false; + } else { + Entity entity = p_30386_.getEntity(); +- if (!this.level().isClientSide) { +- this.setOrderedToSit(false); +- } ++ // CraftBukkit - move diff down + + if (entity != null && !(entity instanceof Player) && !(entity instanceof AbstractArrow)) { + p_30387_ = (p_30387_ + 1.0F) / 2.0F; + } + +- return super.hurt(p_30386_, p_30387_); ++ // CraftBukkit start ++ boolean result = super.hurt(p_30386_, p_30387_); ++ if (!this.level().isClientSide && result) { ++ this.setOrderedToSit(false); ++ } ++ return result; ++ // CraftBukkit end + } + } + +@@ -309,7 +_,7 @@ + super.setTame(p_30443_); + if (p_30443_) { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(20.0D); +- this.setHealth(20.0F); ++ this.setHealth(this.getMaxHealth()); // CraftBukkit - 20.0 -> getMaxHealth() + } else { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(8.0D); + } @@ -325,11 +_,12 @@ return flag ? InteractionResult.CONSUME : InteractionResult.PASS; } else if (this.isTame()) { if (this.isFood(itemstack) && this.getHealth() < this.getMaxHealth()) { -+ this.heal((float)itemstack.getFoodProperties(this).getNutrition()); ++ this.heal((float) item.getFoodProperties().getNutrition(), EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit if (!p_30412_.getAbilities().instabuild) { itemstack.shrink(1); } @@ -14,15 +57,20 @@ return InteractionResult.SUCCESS; } else { if (item instanceof DyeItem) { -@@ -365,7 +_,7 @@ +@@ -365,10 +_,11 @@ itemstack.shrink(1); } - if (this.random.nextInt(3) == 0) { -+ if (this.random.nextInt(3) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, p_30412_)) { ++ // CraftBukkit - added event call and isCancelled check. ++ if (this.random.nextInt(3) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, p_30412_) && !CraftEventFactory.callEntityTameEvent(this, p_30412_).isCancelled()) { this.tame(p_30412_); this.navigation.stop(); - this.setTarget((LivingEntity)null); +- this.setTarget((LivingEntity)null); ++ this.setTarget((LivingEntity) null, EntityTargetEvent.TargetReason.FORGOT_TARGET, true); // CraftBukkit - reason + this.setOrderedToSit(true); + this.level().broadcastEntityEvent(this, (byte)7); + } else { @@ -404,7 +_,7 @@ public boolean isFood(ItemStack p_30440_) { From 4121a37ccb5f82a79d964c209d3d0683ba05d847 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 20:57:35 +0100 Subject: [PATCH 11/26] Sniffer animal patches --- .../entity/animal/sniffer/Sniffer.java.patch | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/patches/minecraft/net/minecraft/world/entity/animal/sniffer/Sniffer.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/sniffer/Sniffer.java.patch index abcd572d7d..b932e10791 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/sniffer/Sniffer.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/sniffer/Sniffer.java.patch @@ -1,5 +1,46 @@ --- a/net/minecraft/world/entity/animal/sniffer/Sniffer.java +++ b/net/minecraft/world/entity/animal/sniffer/Sniffer.java +@@ -81,14 +_,23 @@ + + public Sniffer(EntityType p_273717_, Level p_273562_) { + super(p_273717_, p_273562_); +- this.entityData.define(DATA_STATE, Sniffer.State.IDLING); +- this.entityData.define(DATA_DROP_SEED_AT_TICK, 0); ++ //this.entityData.define(DATA_STATE, Sniffer.State.IDLING); // CraftBukkit - moved down to appropriate location ++ //this.entityData.define(DATA_DROP_SEED_AT_TICK, 0); // CraftBukkit - moved down to appropriate location + this.getNavigation().setCanFloat(true); + this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F); + this.setPathfindingMalus(BlockPathTypes.DANGER_POWDER_SNOW, -1.0F); + this.setPathfindingMalus(BlockPathTypes.DAMAGE_CAUTIOUS, -1.0F); + } + ++ // CraftBukkit start - SPIGOT-7295: moved from constructor to appropriate location ++ @Override ++ protected void defineSynchedData() { ++ super.defineSynchedData(); ++ this.entityData.define(Sniffer.DATA_STATE, Sniffer.State.IDLING); ++ this.entityData.define(Sniffer.DATA_DROP_SEED_AT_TICK, 0); ++ } ++ // CraftBukkit end ++ + protected float getStandingEyeHeight(Pose p_272721_, EntityDimensions p_273353_) { + return this.getDimensions(p_272721_).height * 0.6F; + } +@@ -255,6 +_,14 @@ + + for(ItemStack itemstack : list) { + ItemEntity itementity = new ItemEntity(serverlevel, (double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ(), itemstack); ++ // CraftBukkit start - handle EntityDropItemEvent ++ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) itementity.getBukkitEntity()); ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ continue; ++ } ++ // CraftBukkit end ++ + itementity.setDefaultPickUpDelay(); + serverlevel.addFreshEntity(itementity); + } @@ -275,7 +_,7 @@ } From 6c1d9d6cc0c69ba0317948da019594d0b86b5af4 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 21:01:16 +0100 Subject: [PATCH 12/26] Horse animal patches --- .../animal/horse/AbstractHorse.java.patch | 93 +++++++++++++++++++ .../entity/animal/horse/Llama.java.patch | 12 +++ .../animal/horse/SkeletonTrapGoal.java.patch | 24 ++++- .../animal/horse/TraderLlama.java.patch | 11 +++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/horse/TraderLlama.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/animal/horse/AbstractHorse.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/horse/AbstractHorse.java.patch index 08cee1f715..919333696c 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/horse/AbstractHorse.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/horse/AbstractHorse.java.patch @@ -1,5 +1,22 @@ --- a/net/minecraft/world/entity/animal/horse/AbstractHorse.java +++ b/net/minecraft/world/entity/animal/horse/AbstractHorse.java +@@ -75,6 +_,8 @@ + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec2; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityRegainHealthEvent; + import org.joml.Vector3f; + + public abstract class AbstractHorse extends Animal implements ContainerListener, HasCustomInventoryScreen, OwnableEntity, PlayerRideableJumping, Saddleable { +@@ -137,6 +_,7 @@ + protected int gallopSoundCounter; + @Nullable + private UUID owner; ++ public int maxDomestication = 100; // CraftBukkit - store max domestication value + + protected AbstractHorse(EntityType p_30531_, Level p_30532_) { + super(p_30531_, p_30532_); @@ -283,6 +_,11 @@ } @@ -12,6 +29,15 @@ if (p_149499_ > 1.0F) { this.playSound(SoundEvents.HORSE_LAND, 0.4F, 1.0F); } +@@ -313,7 +_,7 @@ + + protected void createInventory() { + SimpleContainer simplecontainer = this.inventory; +- this.inventory = new SimpleContainer(this.getInventorySize()); ++ this.inventory = new SimpleContainer(this.getInventorySize(), (org.bukkit.entity.AbstractHorse) this.getBukkitEntity()); // CraftBukkit + if (simplecontainer != null) { + simplecontainer.removeListener(this); + int i = Math.min(simplecontainer.getContainerSize(), this.inventory.getContainerSize()); @@ -328,6 +_,7 @@ this.inventory.addListener(this); @@ -32,6 +58,33 @@ } if (this.isVehicle() && this.canGallop) { +@@ -413,7 +_,7 @@ + } + + public int getMaxTemper() { +- return 100; ++ return this.maxDomestication; // CraftBukkit - return stored max domestication instead of 100 + } + + protected float getSoundVolume() { +@@ -483,7 +_,7 @@ + } + + if (this.getHealth() < this.getMaxHealth() && f > 0.0F) { +- this.heal(f); ++ this.heal(f, EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit + flag = true; + } + +@@ -555,7 +_,7 @@ + super.aiStep(); + if (!this.level().isClientSide && this.isAlive()) { + if (this.random.nextInt(900) == 0 && this.deathTime == 0) { +- this.heal(1.0F); ++ this.heal(1.0F, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit + } + + if (this.canEatGrass()) { @@ -787,6 +_,7 @@ this.setDeltaMovement(vec3.x, d1, vec3.z); this.setIsJumping(true); @@ -40,6 +93,46 @@ if (p_275435_.z > 0.0D) { float f = Mth.sin(this.getYRot() * ((float)Math.PI / 180F)); float f1 = Mth.cos(this.getYRot() * ((float)Math.PI / 180F)); +@@ -809,6 +_,8 @@ + p_30589_.putUUID("Owner", this.getOwnerUUID()); + } + ++ p_30589_.putInt("Bukkit.MaxDomestication", this.maxDomestication); // CraftBukkit ++ + if (!this.inventory.getItem(0).isEmpty()) { + p_30589_.put("SaddleItem", this.inventory.getItem(0).save(new CompoundTag())); + } +@@ -833,6 +_,12 @@ + this.setOwnerUUID(uuid); + } + ++ // CraftBukkit start ++ if (p_30565_.contains("Bukkit.MaxDomestication")) { ++ this.maxDomestication = p_30565_.getInt("Bukkit.MaxDomestication"); ++ } ++ // CraftBukkit end ++ + if (p_30565_.contains("SaddleItem", 10)) { + ItemStack itemstack = ItemStack.of(p_30565_.getCompound("SaddleItem")); + if (itemstack.is(Items.SADDLE)) { +@@ -925,6 +_,17 @@ + } + + public void handleStartJump(int p_30574_) { ++ // CraftBukkit start ++ float power; ++ if (p_30574_ >= 90) { ++ power = 1.0F; ++ } else { ++ power = 0.4F + 0.4F * (float) p_30574_ / 90.0F; ++ } ++ if (!CraftEventFactory.callHorseJumpEvent(this, power)) { ++ return; ++ } ++ // CraftBukkit end + this.allowStandSliding = true; + this.standIfPossible(); + this.playJumpSound(); @@ -1109,6 +_,25 @@ this.randomizeAttributes(p_30555_.getRandom()); diff --git a/patches/minecraft/net/minecraft/world/entity/animal/horse/Llama.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/horse/Llama.java.patch index 1b0c1a6a66..4dc66f99ed 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/horse/Llama.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/horse/Llama.java.patch @@ -1,5 +1,17 @@ --- a/net/minecraft/world/entity/animal/horse/Llama.java +++ b/net/minecraft/world/entity/animal/horse/Llama.java +@@ -82,6 +_,11 @@ + return false; + } + ++ // CraftBukkit start ++ public void setStrengthPublic(int i) { ++ this.setStrength(i); ++ } ++ // CraftBukkit end + private void setStrength(int p_30841_) { + this.entityData.set(DATA_STRENGTH_ID, Math.max(1, Math.min(5, p_30841_))); + } @@ -366,6 +_,10 @@ } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java.patch index e92585e302..f024b03cd3 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java.patch @@ -11,7 +11,29 @@ DifficultyInstance difficultyinstance = serverlevel.getCurrentDifficultyAt(this.horse.blockPosition()); this.horse.setTrap(false); this.horse.setTamed(true); -@@ -56,6 +_,7 @@ +@@ -36,11 +_,11 @@ + if (lightningbolt != null) { + lightningbolt.moveTo(this.horse.getX(), this.horse.getY(), this.horse.getZ()); + lightningbolt.setVisualOnly(true); +- serverlevel.addFreshEntity(lightningbolt); ++ serverlevel.strikeLightning(lightningbolt, org.bukkit.event.weather.LightningStrikeEvent.Cause.TRAP); // CraftBukkit + Skeleton skeleton = this.createSkeleton(difficultyinstance, this.horse); + if (skeleton != null) { + skeleton.startRiding(this.horse); +- serverlevel.addFreshEntityWithPassengers(skeleton); ++ serverlevel.addFreshEntityWithPassengers(skeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.TRAP); // CraftBukkit + + for(int i = 0; i < 3; ++i) { + AbstractHorse abstracthorse = this.createHorse(difficultyinstance); +@@ -49,13 +_,14 @@ + if (skeleton1 != null) { + skeleton1.startRiding(abstracthorse); + abstracthorse.push(this.horse.getRandom().triangle(0.0D, 1.1485D), 0.0D, this.horse.getRandom().triangle(0.0D, 1.1485D)); +- serverlevel.addFreshEntityWithPassengers(abstracthorse); ++ serverlevel.addFreshEntityWithPassengers(abstracthorse, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.JOCKEY); // CraftBukkit + } + } + } } } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/horse/TraderLlama.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/horse/TraderLlama.java.patch new file mode 100644 index 0000000000..1ab1ee62bc --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/horse/TraderLlama.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/animal/horse/TraderLlama.java ++++ b/net/minecraft/world/entity/animal/horse/TraderLlama.java +@@ -137,7 +_,7 @@ + } + + public void start() { +- this.mob.setTarget(this.ownerLastHurtBy); ++ this.mob.setTarget(this.ownerLastHurtBy, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_OWNER, true); // CraftBukkit + Entity entity = this.llama.getLeashHolder(); + if (entity instanceof WanderingTrader) { + this.timestamp = ((WanderingTrader)entity).getLastHurtByMobTimestamp(); From 8206bcacbdd9fa6dc782e2473a95ad9b1bf80e40 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 21:22:18 +0100 Subject: [PATCH 13/26] Allay, Axolotl, Goat and Frog animal patches --- .../entity/animal/allay/Allay.java.patch | 72 +++++++++++++++++++ .../entity/animal/axolotl/Axolotl.java.patch | 33 +++++++++ .../entity/animal/frog/Tadpole.java.patch | 18 +++++ .../world/entity/animal/goat/Goat.java.patch | 29 ++++++++ 4 files changed, 152 insertions(+) create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/frog/Tadpole.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/animal/goat/Goat.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/animal/allay/Allay.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/allay/Allay.java.patch index c429103e16..10ad24e128 100644 --- a/patches/minecraft/net/minecraft/world/entity/animal/allay/Allay.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/animal/allay/Allay.java.patch @@ -1,5 +1,49 @@ --- a/net/minecraft/world/entity/animal/allay/Allay.java +++ b/net/minecraft/world/entity/animal/allay/Allay.java +@@ -95,6 +_,7 @@ + private float dancingAnimationTicks; + private float spinningAnimationTicks; + private float spinningAnimationTicks0; ++ public boolean forceDancing = false; // CraftBukkit + + public Allay(EntityType p_218310_, Level p_218311_) { + super(p_218310_, p_218311_); +@@ -106,6 +_,12 @@ + this.dynamicJukeboxListener = new DynamicGameEventListener<>(new Allay.JukeboxListener(this.vibrationUser.getPositionSource(), GameEvent.JUKEBOX_PLAY.getNotificationRadius())); + } + ++ // CraftBukkit start ++ public void setCanDuplicate(boolean canDuplicate) { ++ this.entityData.set(Allay.DATA_CAN_DUPLICATE, canDuplicate); ++ } ++ // CraftBukkit end ++ + protected Brain.Provider brainProvider() { + return Brain.provider(MEMORY_TYPES, SENSOR_TYPES); + } +@@ -207,7 +_,7 @@ + public void aiStep() { + super.aiStep(); + if (!this.level().isClientSide && this.isAlive() && this.tickCount % 10 == 0) { +- this.heal(1.0F); ++ this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit + } + + if (this.isDancing() && this.shouldStopDancing() && this.tickCount % 20 == 0) { +@@ -272,7 +_,12 @@ + ItemStack itemstack = p_218361_.getItemInHand(p_218362_); + ItemStack itemstack1 = this.getItemInHand(InteractionHand.MAIN_HAND); + if (this.isDancing() && this.isDuplicationItem(itemstack) && this.canDuplicate()) { +- this.duplicateAllay(); ++ // CraftBukkit start - handle cancel duplication ++ Allay allay = this.duplicateAllay(); ++ if (allay == null) { ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + this.level().broadcastEntityEvent(this, (byte)18); + this.level().playSound(p_218361_, this, SoundEvents.AMETHYST_BLOCK_CHIME, SoundSource.NEUTRAL, 2.0F, 1.0F); + this.removeInteractionItem(p_218361_, itemstack); @@ -324,7 +_,7 @@ public boolean wantsToPickUp(ItemStack p_218387_) { @@ -9,3 +53,31 @@ } private boolean allayConsidersItemEqual(ItemStack p_252278_, ItemStack p_250405_) { +@@ -382,6 +_,7 @@ + } + + private boolean shouldStopDancing() { ++ if (this.forceDancing) {return false;} // CraftBukkit + return this.jukeboxPos == null || !this.jukeboxPos.closerToCenterThan(this.position(), (double)GameEvent.JUKEBOX_PLAY.getNotificationRadius()) || !this.level().getBlockState(this.jukeboxPos).is(Blocks.JUKEBOX); + } + +@@ -459,16 +_,16 @@ + return DUPLICATION_ITEM.test(p_239736_); + } + +- private void duplicateAllay() { ++ private Allay duplicateAllay() { // CraftBukkit - return allay + Allay allay = EntityType.ALLAY.create(this.level()); + if (allay != null) { + allay.moveTo(this.position()); + allay.setPersistenceRequired(); + allay.resetDuplicationCooldown(); + this.resetDuplicationCooldown(); +- this.level().addFreshEntity(allay); ++ this.level().addFreshEntity(allay, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DUPLICATION); // CraftBukkit - reason for duplicated allay + } +- ++ return allay; // CraftBukkit + } + + private void resetDuplicationCooldown() { diff --git a/patches/minecraft/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch new file mode 100644 index 0000000000..2fd41da8c4 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch @@ -0,0 +1,33 @@ +--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java ++++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java +@@ -67,6 +_,12 @@ + import org.joml.Vector3f; + + public class Axolotl extends Animal implements LerpingModel, VariantHolder, Bucketable { ++ // CraftBukkit start - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() ++ @Override ++ public int getDefaultMaxAirSupply() { ++ return AXOLOTL_TOTAL_AIR_SUPPLY; ++ } ++ // CraftBukkit end + public static final int TOTAL_PLAYDEAD_TIME = 200; + protected static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_ADULT, SensorType.HURT_BY, SensorType.AXOLOTL_ATTACKABLES, SensorType.AXOLOTL_TEMPTATIONS); + protected static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.BREED_TARGET, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_VISIBLE_ADULT, MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.PLAY_DEAD_TICKS, MemoryModuleType.NEAREST_ATTACKABLE, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.HAS_HUNTING_COOLDOWN, MemoryModuleType.IS_PANICKING); +@@ -174,7 +_,7 @@ + } + + public int getMaxAirSupply() { +- return 6000; ++ return maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() + } + + public Axolotl.Variant getVariant() { +@@ -364,7 +_,7 @@ + if (mobeffectinstance == null || mobeffectinstance.endsWithin(2399)) { + int i = mobeffectinstance != null ? mobeffectinstance.getDuration() : 0; + int j = Math.min(2400, 100 + i); +- p_149174_.addEffect(new MobEffectInstance(MobEffects.REGENERATION, j, 0), this); ++ p_149174_.addEffect(new MobEffectInstance(MobEffects.REGENERATION, j, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // CraftBukkit + } + + p_149174_.removeEffect(MobEffects.DIG_SLOWDOWN); diff --git a/patches/minecraft/net/minecraft/world/entity/animal/frog/Tadpole.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/frog/Tadpole.java.patch new file mode 100644 index 0000000000..f0919e8012 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/frog/Tadpole.java.patch @@ -0,0 +1,18 @@ +--- a/net/minecraft/world/entity/animal/frog/Tadpole.java ++++ b/net/minecraft/world/entity/animal/frog/Tadpole.java +@@ -208,8 +_,14 @@ + } + + frog.setPersistenceRequired(); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityTransformEvent(this, frog, org.bukkit.event.entity.EntityTransformEvent.TransformReason.METAMORPHOSIS).isCancelled()) { ++ this.setAge(0); // Sets the age to 0 for avoid a loop if the event is canceled ++ return; ++ } ++ // CraftBukkit end + this.playSound(SoundEvents.TADPOLE_GROW_UP, 0.15F, 1.0F); +- serverlevel.addFreshEntityWithPassengers(frog); ++ serverlevel.addFreshEntityWithPassengers(frog, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.METAMORPHOSIS); // CraftBukkit - add SpawnReason + this.discard(); + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/animal/goat/Goat.java.patch b/patches/minecraft/net/minecraft/world/entity/animal/goat/Goat.java.patch new file mode 100644 index 0000000000..2567e4a02e --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/animal/goat/Goat.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/world/entity/animal/goat/Goat.java ++++ b/net/minecraft/world/entity/animal/goat/Goat.java +@@ -52,6 +_,9 @@ + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.level.pathfinder.BlockPathTypes; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; ++import org.bukkit.event.player.PlayerBucketFillEvent; + import org.joml.Vector3f; + + public class Goat extends Animal { +@@ -194,8 +_,15 @@ + public InteractionResult mobInteract(Player p_149379_, InteractionHand p_149380_) { + ItemStack itemstack = p_149379_.getItemInHand(p_149380_); + if (itemstack.is(Items.BUCKET) && !this.isBaby()) { ++ // CraftBukkit start - Got milk? ++ PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) p_149379_.level(), p_149379_, this.blockPosition(), this.blockPosition(), null, itemstack, Items.MILK_BUCKET, p_149380_); ++ ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ // CraftBukkit end + p_149379_.playSound(this.getMilkingSound(), 1.0F, 1.0F); +- ItemStack itemstack1 = ItemUtils.createFilledResult(itemstack, p_149379_, Items.MILK_BUCKET.getDefaultInstance()); ++ ItemStack itemstack1 = ItemUtils.createFilledResult(itemstack, p_149379_, CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit + p_149379_.setItemInHand(p_149380_, itemstack1); + return InteractionResult.sidedSuccess(this.level().isClientSide); + } else { From 98f651aa50db49ce5e548df764484071f8bf8371 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 22:09:08 +0100 Subject: [PATCH 14/26] Base monster patches --- .../net/minecraft/world/entity/Mob.java.patch | 8 + .../world/entity/NeutralMob.java.patch | 10 +- .../monster/AbstractSkeleton.java.patch | 29 +++- .../entity/monster/CaveSpider.java.patch | 11 ++ .../world/entity/monster/Creeper.java.patch | 74 ++++++++ .../world/entity/monster/Drowned.java.patch | 11 ++ .../entity/monster/ElderGuardian.java.patch | 11 ++ .../world/entity/monster/EnderMan.java.patch | 59 ++++++- .../world/entity/monster/Evoker.java.patch | 9 + .../world/entity/monster/Ghast.java.patch | 11 ++ .../world/entity/monster/Guardian.java.patch | 19 +++ .../world/entity/monster/Husk.java.patch | 11 ++ .../entity/monster/Illusioner.java.patch | 18 ++ .../world/entity/monster/Phantom.java.patch | 11 ++ .../world/entity/monster/Ravager.java.patch | 20 +++ .../world/entity/monster/Shulker.java.patch | 29 +++- .../entity/monster/Silverfish.java.patch | 27 ++- .../world/entity/monster/Skeleton.java.patch | 11 ++ .../world/entity/monster/Slime.java.patch | 62 +++++++ .../monster/SpellcasterIllager.java.patch | 22 +++ .../world/entity/monster/Spider.java.patch | 9 + .../world/entity/monster/Strider.java.patch | 18 ++ .../world/entity/monster/Vex.java.patch | 11 ++ .../world/entity/monster/Witch.java.patch | 11 ++ .../entity/monster/WitherSkeleton.java.patch | 11 ++ .../world/entity/monster/Zombie.java.patch | 158 ++++++++++++++++-- .../entity/monster/ZombieVillager.java.patch | 77 ++++++++- .../entity/monster/ZombifiedPiglin.java.patch | 51 ++++++ .../projectile/LargeFireball.java.patch | 8 +- 29 files changed, 787 insertions(+), 30 deletions(-) create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/CaveSpider.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Creeper.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Drowned.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/ElderGuardian.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Ghast.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Guardian.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Husk.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Phantom.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Skeleton.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Strider.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Vex.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/Witch.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/WitherSkeleton.java.patch create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/Mob.java.patch b/patches/minecraft/net/minecraft/world/entity/Mob.java.patch index 64ffd598e3..8134bd740b 100644 --- a/patches/minecraft/net/minecraft/world/entity/Mob.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/Mob.java.patch @@ -8,6 +8,14 @@ import net.minecraft.sounds.SoundEvent; import net.minecraft.tags.TagKey; import net.minecraft.util.Mth; +@@ -62,7 +_,6 @@ + import net.minecraft.world.item.SpawnEggItem; + import net.minecraft.world.item.SwordItem; + import net.minecraft.world.item.enchantment.EnchantmentHelper; +-import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.Level; + import net.minecraft.world.level.LevelAccessor; + import net.minecraft.world.level.LevelReader; @@ -71,6 +_,9 @@ import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.pathfinder.BlockPathTypes; diff --git a/patches/minecraft/net/minecraft/world/entity/NeutralMob.java.patch b/patches/minecraft/net/minecraft/world/entity/NeutralMob.java.patch index 2f20127034..f1bb9885ae 100644 --- a/patches/minecraft/net/minecraft/world/entity/NeutralMob.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/NeutralMob.java.patch @@ -1,5 +1,13 @@ --- a/net/minecraft/world/entity/NeutralMob.java +++ b/net/minecraft/world/entity/NeutralMob.java +@@ -8,6 +_,7 @@ + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.Level; ++import org.bukkit.event.entity.EntityTargetEvent; + + public interface NeutralMob { + String TAG_ANGER_TIME = "AngerTime"; @@ -108,7 +_,7 @@ default void stopBeingAngry() { this.setLastHurtByMob((LivingEntity)null); @@ -14,7 +22,7 @@ void setLastHurtByPlayer(@Nullable Player p_21680_); - void setTarget(@Nullable LivingEntity p_21681_); -+ void setTarget(@Nullable LivingEntity p_21681_, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent); // CraftBukkit ++ boolean setTarget(@Nullable LivingEntity p_21681_, EntityTargetEvent.TargetReason reason, boolean fireEvent); // CraftBukkit boolean canAttack(LivingEntity p_181126_); diff --git a/patches/minecraft/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch index a4b4313700..ba8cc33f3e 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch @@ -1,5 +1,13 @@ --- a/net/minecraft/world/entity/monster/AbstractSkeleton.java +++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -10,6 +_,7 @@ + import net.minecraft.util.RandomSource; + import net.minecraft.world.Difficulty; + import net.minecraft.world.DifficultyInstance; ++import net.minecraft.world.InteractionHand; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityDimensions; + import net.minecraft.world.entity.EntityType; @@ -155,7 +_,7 @@ if (this.level() != null && !this.level().isClientSide) { this.goalSelector.removeGoal(this.meleeGoal); @@ -9,7 +17,7 @@ if (itemstack.is(Items.BOW)) { int i = 20; if (this.level().getDifficulty() != Difficulty.HARD) { -@@ -172,8 +_,10 @@ +@@ -172,15 +_,28 @@ } public void performRangedAttack(LivingEntity p_32141_, float p_32142_) { @@ -21,3 +29,22 @@ double d0 = p_32141_.getX() - this.getX(); double d1 = p_32141_.getY(0.3333333333333333D) - abstractarrow.getY(); double d2 = p_32141_.getZ() - this.getZ(); + double d3 = Math.sqrt(d0 * d0 + d2 * d2); + abstractarrow.shoot(d0, d1 + d3 * (double)0.2F, d2, 1.6F, (float)(14 - this.level().getDifficulty().getId() * 4)); ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), null, abstractarrow, InteractionHand.MAIN_HAND, 0.8F, true); ++ if (event.isCancelled()) { ++ event.getProjectile().remove(); ++ return; ++ } ++ ++ if (event.getProjectile() == abstractarrow.getBukkitEntity()) { ++ this.level().addFreshEntity(abstractarrow); ++ } ++ // CraftBukkit end + this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F)); +- this.level().addFreshEntity(abstractarrow); ++ // this.level().addFreshEntity(abstractarrow); // CraftBukkit - moved up + } + + protected AbstractArrow getArrow(ItemStack p_32156_, float p_32157_) { diff --git a/patches/minecraft/net/minecraft/world/entity/monster/CaveSpider.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/CaveSpider.java.patch new file mode 100644 index 0000000000..e983ccfd3a --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/CaveSpider.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/CaveSpider.java ++++ b/net/minecraft/world/entity/monster/CaveSpider.java +@@ -39,7 +_,7 @@ + } + + if (i > 0) { +- ((LivingEntity)p_32257_).addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this); ++ ((LivingEntity)p_32257_).addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + } + diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Creeper.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Creeper.java.patch new file mode 100644 index 0000000000..d15da00ae4 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Creeper.java.patch @@ -0,0 +1,74 @@ +--- a/net/minecraft/world/entity/monster/Creeper.java ++++ b/net/minecraft/world/entity/monster/Creeper.java +@@ -40,6 +_,9 @@ + import net.minecraft.world.item.Items; + import net.minecraft.world.level.Level; + import net.minecraft.world.level.gameevent.GameEvent; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.bukkit.event.entity.ExplosionPrimeEvent; + + public class Creeper extends Monster implements PowerableMob { + private static final EntityDataAccessor DATA_SWELL_DIR = SynchedEntityData.defineId(Creeper.class, EntityDataSerializers.INT); +@@ -196,9 +_,20 @@ + + public void thunderHit(ServerLevel p_32286_, LightningBolt p_32287_) { + super.thunderHit(p_32286_, p_32287_); ++ // CraftBukkit start ++ if (CraftEventFactory.callCreeperPowerEvent(this, p_32287_, org.bukkit.event.entity.CreeperPowerEvent.PowerCause.LIGHTNING).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + this.entityData.set(DATA_IS_POWERED, true); + } + ++ // CraftBukkit start ++ public void setPowered(boolean powered) { ++ this.entityData.set(Creeper.DATA_IS_POWERED, powered); ++ } ++ // CraftBukkit end ++ + protected InteractionResult mobInteract(Player p_32301_, InteractionHand p_32302_) { + ItemStack itemstack = p_32301_.getItemInHand(p_32302_); + if (itemstack.is(ItemTags.CREEPER_IGNITERS)) { +@@ -224,10 +_,19 @@ + private void explodeCreeper() { + if (!this.level().isClientSide) { + float f = this.isPowered() ? 2.0F : 1.0F; +- this.dead = true; +- this.level().explode(this, this.getX(), this.getY(), this.getZ(), (float)this.explosionRadius * f, Level.ExplosionInteraction.MOB); +- this.discard(); +- this.spawnLingeringCloud(); ++ // CraftBukkit start ++ ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, this.explosionRadius * f, false); ++ if (!event.isCancelled()) { ++ // CraftBukkit end ++ this.dead = true; ++ this.level().explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit ++ this.discard(); ++ this.spawnLingeringCloud(); ++ // CraftBukkit start ++ } else { ++ swell = 0; ++ } ++ // CraftBukkit end + } + + } +@@ -236,6 +_,7 @@ + Collection collection = this.getActiveEffects(); + if (!collection.isEmpty()) { + AreaEffectCloud areaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); ++ areaeffectcloud.setOwner(this); // CraftBukkit + areaeffectcloud.setRadius(2.5F); + areaeffectcloud.setRadiusOnUse(-0.5F); + areaeffectcloud.setWaitTime(10); +@@ -246,7 +_,7 @@ + areaeffectcloud.addEffect(new MobEffectInstance(mobeffectinstance)); + } + +- this.level().addFreshEntity(areaeffectcloud); ++ this.level().addFreshEntity(areaeffectcloud, CreatureSpawnEvent.SpawnReason.EXPLOSION); // CraftBukkit + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Drowned.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Drowned.java.patch new file mode 100644 index 0000000000..12aaae78c0 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Drowned.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Drowned.java ++++ b/net/minecraft/world/entity/monster/Drowned.java +@@ -237,7 +_,7 @@ + } + + public void performRangedAttack(LivingEntity p_32356_, float p_32357_) { +- ThrownTrident throwntrident = new ThrownTrident(this.level(), this, new ItemStack(Items.TRIDENT)); ++ ThrownTrident throwntrident = new ThrownTrident(this.level(), this, this.getItemInHand(net.minecraft.world.entity.projectile.ProjectileUtil.getWeaponHoldingHand(this, Items.TRIDENT))); // CraftBukkit - Use Trident in hand like skeletons (SPIGOT-7025) + double d0 = p_32356_.getX() - this.getX(); + double d1 = p_32356_.getY(0.3333333333333333D) - throwntrident.getY(); + double d2 = p_32356_.getZ() - this.getZ(); diff --git a/patches/minecraft/net/minecraft/world/entity/monster/ElderGuardian.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/ElderGuardian.java.patch new file mode 100644 index 0000000000..4b6b723193 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/ElderGuardian.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/ElderGuardian.java ++++ b/net/minecraft/world/entity/monster/ElderGuardian.java +@@ -63,7 +_,7 @@ + super.customServerAiStep(); + if ((this.tickCount + this.getId()) % 1200 == 0) { + MobEffectInstance mobeffectinstance = new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 6000, 2); +- List list = MobEffectUtil.addEffectToPlayersAround((ServerLevel)this.level(), this, this.position(), 50.0D, mobeffectinstance, 1200); ++ List list = MobEffectUtil.addEffectToPlayersAround((ServerLevel)this.level(), this, this.position(), 50.0D, mobeffectinstance, 1200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + list.forEach((p_296822_) -> { + p_296822_.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, this.isSilent() ? 0.0F : 1.0F)); + }); diff --git a/patches/minecraft/net/minecraft/world/entity/monster/EnderMan.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/EnderMan.java.patch index 9b39268032..b93acccb9d 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/EnderMan.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/EnderMan.java.patch @@ -1,10 +1,33 @@ --- a/net/minecraft/world/entity/monster/EnderMan.java +++ b/net/minecraft/world/entity/monster/EnderMan.java -@@ -111,7 +_,6 @@ +@@ -68,6 +_,8 @@ + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.BlockHitResult; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityTargetEvent; + import org.joml.Vector3f; + + public class EnderMan extends Monster implements NeutralMob { +@@ -110,8 +_,20 @@ + return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 40.0D).add(Attributes.MOVEMENT_SPEED, (double)0.3F).add(Attributes.ATTACK_DAMAGE, 7.0D).add(Attributes.FOLLOW_RANGE, 64.0D); } ++ @Override public void setTarget(@Nullable LivingEntity p_32537_) { - super.setTarget(p_32537_); ++ // CraftBukkit start - fire event ++ setTarget(p_32537_, EntityTargetEvent.TargetReason.UNKNOWN, true); ++ } ++ ++ @Override ++ public boolean setTarget(LivingEntity p_32537_, EntityTargetEvent.TargetReason reason, boolean fireEvent) { ++ if (!super.setTarget(p_32537_, reason, fireEvent)) { ++ return false; ++ } ++ p_32537_ = getTarget(); ++ // CraftBukkit end ++ AttributeInstance attributeinstance = this.getAttribute(Attributes.MOVEMENT_SPEED); if (p_32537_ == null) { this.targetChangeTime = 0; @@ -12,7 +35,7 @@ } } -+ super.setTarget(p_32537_); //Forge: Moved down to allow event handlers to write data manager values. ++ return true; } protected void defineSynchedData() { @@ -46,16 +69,23 @@ return false; } else { return this.enderman.getRandom().nextInt(reducedTickDelay(2000)) == 0; -@@ -444,7 +_,7 @@ +@@ -444,17 +_,19 @@ BlockState blockstate2 = this.enderman.getCarriedBlock(); if (blockstate2 != null) { blockstate2 = Block.updateFromNeighbourShapes(blockstate2, this.enderman.level(), blockpos); - if (this.canPlaceBlock(level, blockpos, blockstate2, blockstate, blockstate1, blockpos1)) { +- level.setBlock(blockpos, blockstate2, 3); +- level.gameEvent(GameEvent.BLOCK_PLACE, blockpos, GameEvent.Context.of(this.enderman, blockstate2)); +- this.enderman.setCarriedBlock((BlockState)null); + if (this.canPlaceBlock(level, blockpos, blockstate2, blockstate, blockstate1, blockpos1) && !net.minecraftforge.event.ForgeEventFactory.onBlockPlace(enderman, net.minecraftforge.common.util.BlockSnapshot.create(level.dimension(), level, blockpos1), net.minecraft.core.Direction.UP)) { - level.setBlock(blockpos, blockstate2, 3); - level.gameEvent(GameEvent.BLOCK_PLACE, blockpos, GameEvent.Context.of(this.enderman, blockstate2)); - this.enderman.setCarriedBlock((BlockState)null); -@@ -454,7 +_,7 @@ ++ if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockpos, blockstate2)) { // CraftBukkit - Place event ++ level.setBlock(blockpos, blockstate2, 3); ++ level.gameEvent(GameEvent.BLOCK_PLACE, blockpos, GameEvent.Context.of(this.enderman, blockstate2)); ++ this.enderman.setCarriedBlock((BlockState) null); ++ } // CraftBukkit + } + + } } private boolean canPlaceBlock(Level p_32559_, BlockPos p_32560_, BlockState p_32561_, BlockState p_32562_, BlockState p_32563_, BlockPos p_32564_) { @@ -73,3 +103,18 @@ return false; } else { return this.enderman.getRandom().nextInt(reducedTickDelay(20)) == 0; +@@ -576,9 +_,11 @@ + BlockHitResult blockhitresult = level.clip(new ClipContext(vec3, vec31, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this.enderman)); + boolean flag = blockhitresult.getBlockPos().equals(blockpos); + if (blockstate.is(BlockTags.ENDERMAN_HOLDABLE) && flag) { +- level.removeBlock(blockpos, false); +- level.gameEvent(GameEvent.BLOCK_DESTROY, blockpos, GameEvent.Context.of(this.enderman, blockstate)); +- this.enderman.setCarriedBlock(blockstate.getBlock().defaultBlockState()); ++ if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockpos, Blocks.AIR.defaultBlockState())) { // CraftBukkit - Place event ++ level.removeBlock(blockpos, false); ++ level.gameEvent(GameEvent.BLOCK_DESTROY, blockpos, GameEvent.Context.of(this.enderman, blockstate)); ++ this.enderman.setCarriedBlock(blockstate.getBlock().defaultBlockState()); ++ } // CraftBukkit + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Evoker.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Evoker.java.patch index 26221a1b89..f23c2860bb 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/Evoker.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/Evoker.java.patch @@ -1,5 +1,14 @@ --- a/net/minecraft/world/entity/monster/Evoker.java +++ b/net/minecraft/world/entity/monster/Evoker.java +@@ -251,7 +_,7 @@ + vex.setOwner(Evoker.this); + vex.setBoundOrigin(blockpos); + vex.setLimitedLife(20 * (30 + Evoker.this.random.nextInt(90))); +- serverlevel.addFreshEntityWithPassengers(vex); ++ serverlevel.addFreshEntityWithPassengers(vex, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPELL); // CraftBukkit - Add SpawnReason + serverlevel.gameEvent(GameEvent.ENTITY_PLACE, blockpos, GameEvent.Context.of(Evoker.this)); + } + } @@ -279,7 +_,7 @@ return false; } else if (Evoker.this.tickCount < this.nextAttackTickCount) { diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Ghast.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Ghast.java.patch new file mode 100644 index 0000000000..8fd8e37198 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Ghast.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Ghast.java ++++ b/net/minecraft/world/entity/monster/Ghast.java +@@ -269,6 +_,8 @@ + } + + LargeFireball largefireball = new LargeFireball(level, this.ghast, d2, d3, d4, this.ghast.getExplosionPower()); ++ // CraftBukkit - set bukkitYield when setting explosionpower ++ largefireball.bukkitYield = largefireball.explosionPower = this.ghast.getExplosionPower(); + largefireball.setPos(this.ghast.getX() + vec3.x * 4.0D, this.ghast.getY(0.5D) + 0.5D, largefireball.getZ() + vec3.z * 4.0D); + level.addFreshEntity(largefireball); + this.chargeTime = -40; diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Guardian.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Guardian.java.patch new file mode 100644 index 0000000000..2163f88dbe --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Guardian.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/entity/monster/Guardian.java ++++ b/net/minecraft/world/entity/monster/Guardian.java +@@ -62,6 +_,7 @@ + private boolean clientSideTouchedGround; + @Nullable + protected RandomStrollGoal randomStrollGoal; ++ public Guardian.GuardianAttackGoal guardianAttackGoal; // CraftBukkit - add field + + public Guardian(EntityType p_32810_, Level p_32811_) { + super(p_32810_, p_32811_); +@@ -75,7 +_,7 @@ + protected void registerGoals() { + MoveTowardsRestrictionGoal movetowardsrestrictiongoal = new MoveTowardsRestrictionGoal(this, 1.0D); + this.randomStrollGoal = new RandomStrollGoal(this, 1.0D, 80); +- this.goalSelector.addGoal(4, new Guardian.GuardianAttackGoal(this)); ++ this.goalSelector.addGoal(4, guardianAttackGoal = new Guardian.GuardianAttackGoal(this)); // CraftBukkit - assign field + this.goalSelector.addGoal(5, movetowardsrestrictiongoal); + this.goalSelector.addGoal(7, this.randomStrollGoal); + this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Husk.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Husk.java.patch new file mode 100644 index 0000000000..125b5cbf8b --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Husk.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Husk.java ++++ b/net/minecraft/world/entity/monster/Husk.java +@@ -51,7 +_,7 @@ + boolean flag = super.doHurtTarget(p_32892_); + if (flag && this.getMainHandItem().isEmpty() && p_32892_ instanceof LivingEntity) { + float f = this.level().getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); +- ((LivingEntity)p_32892_).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int)f), this); ++ ((LivingEntity)p_32892_).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int)f), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + + return flag; diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Illusioner.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Illusioner.java.patch index 25d63eb3d5..0d5da93a44 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/Illusioner.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/Illusioner.java.patch @@ -12,3 +12,21 @@ double d0 = p_32918_.getX() - this.getX(); double d1 = p_32918_.getY(0.3333333333333333D) - abstractarrow.getY(); double d2 = p_32918_.getZ() - this.getZ(); +@@ -230,7 +_,7 @@ + } + + protected void performSpellCasting() { +- Illusioner.this.getTarget().addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 400), Illusioner.this); ++ Illusioner.this.getTarget().addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 400), Illusioner.this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ILLUSION); // CraftBukkit + } + + protected SoundEvent getSpellPrepareSound() { +@@ -260,7 +_,7 @@ + } + + protected void performSpellCasting() { +- Illusioner.this.addEffect(new MobEffectInstance(MobEffects.INVISIBILITY, 1200)); ++ Illusioner.this.addEffect(new MobEffectInstance(MobEffects.INVISIBILITY, 1200), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + + @Nullable diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Phantom.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Phantom.java.patch new file mode 100644 index 0000000000..5014b84d13 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Phantom.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -230,7 +_,7 @@ + + for(Player player : list) { + if (Phantom.this.canAttack(player, TargetingConditions.DEFAULT)) { +- Phantom.this.setTarget(player); ++ Phantom.this.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason + return true; + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Ravager.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Ravager.java.patch index 6a2964e622..02e32a96a1 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/Ravager.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/Ravager.java.patch @@ -1,5 +1,13 @@ --- a/net/minecraft/world/entity/monster/Ravager.java +++ b/net/minecraft/world/entity/monster/Ravager.java +@@ -39,6 +_,7 @@ + import net.minecraft.world.level.pathfinder.BlockPathTypes; + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; + import org.joml.Vector3f; + + public class Ravager extends Raider { @@ -129,7 +_,7 @@ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(Mth.lerp(0.1D, d1, d0)); } @@ -9,3 +17,15 @@ boolean flag = false; AABB aabb = this.getBoundingBox().inflate(0.2D); +@@ -137,6 +_,11 @@ + BlockState blockstate = this.level().getBlockState(blockpos); + Block block = blockstate.getBlock(); + if (block instanceof LeavesBlock) { ++ // CraftBukkit start ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockpos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) { ++ continue; ++ } ++ // CraftBukkit end + flag = this.level().destroyBlock(blockpos, true, this) || flag; + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Shulker.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Shulker.java.patch index f5a574f204..79c2d579db 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/Shulker.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/Shulker.java.patch @@ -1,6 +1,16 @@ --- a/net/minecraft/world/entity/monster/Shulker.java +++ b/net/minecraft/world/entity/monster/Shulker.java -@@ -354,6 +_,12 @@ +@@ -54,6 +_,9 @@ + import net.minecraft.world.level.gameevent.GameEvent; + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.craftbukkit.v1_20_R2.util.CraftLocation; ++import org.bukkit.event.entity.EntityTeleportEvent; + import org.joml.Vector3f; + import org.joml.Vector3fc; + +@@ -354,6 +_,20 @@ if (blockpos1.getY() > this.level().getMinBuildHeight() && this.level().isEmptyBlock(blockpos1) && this.level().getWorldBorder().isWithinBounds(blockpos1) && this.level().noCollision(this, (new AABB(blockpos1)).deflate(1.0E-6D))) { Direction direction = this.findAttachableSurface(blockpos1); if (direction != null) { @@ -10,6 +20,23 @@ + } + + if (direction != null) { ++ // CraftBukkit start ++ EntityTeleportEvent teleportEvent = CraftEventFactory.callEntityTeleportEvent(this, blockpos1.getX(), blockpos1.getY(), blockpos1.getZ()); ++ if (teleportEvent.isCancelled()) { ++ return false; ++ } else { ++ blockpos1 = CraftLocation.toBlockPosition(teleportEvent.getTo()); ++ } ++ // CraftBukkit end this.unRide(); this.setAttachFace(direction); this.playSound(SoundEvents.SHULKER_TELEPORT, 1.0F, 1.0F); +@@ -417,7 +_,7 @@ + if (shulker != null) { + shulker.setVariant(this.getVariant()); + shulker.moveTo(vec3); +- this.level().addFreshEntity(shulker); ++ this.level().addFreshEntity(shulker, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - the mysteries of life + } + + } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Silverfish.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Silverfish.java.patch index ef0b32456a..593f289c24 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/Silverfish.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/Silverfish.java.patch @@ -1,5 +1,13 @@ --- a/net/minecraft/world/entity/monster/Silverfish.java +++ b/net/minecraft/world/entity/monster/Silverfish.java +@@ -32,6 +_,7 @@ + import net.minecraft.world.level.block.Block; + import net.minecraft.world.level.block.InfestedBlock; + import net.minecraft.world.level.block.state.BlockState; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; + import org.joml.Vector3f; + + public class Silverfish extends Monster { @@ -141,7 +_,7 @@ return false; } else { @@ -9,11 +17,28 @@ this.selectedDirection = Direction.getRandom(randomsource); BlockPos blockpos = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5D, this.mob.getZ()).relative(this.selectedDirection); BlockState blockstate = this.mob.level().getBlockState(blockpos); -@@ -210,7 +_,7 @@ +@@ -168,6 +_,11 @@ + BlockPos blockpos = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5D, this.mob.getZ()).relative(this.selectedDirection); + BlockState blockstate = levelaccessor.getBlockState(blockpos); + if (InfestedBlock.isCompatibleHostBlock(blockstate)) { ++ // CraftBukkit start ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockpos, InfestedBlock.infestedStateByHost(blockstate))) { ++ return; ++ } ++ // CraftBukkit end + levelaccessor.setBlock(blockpos, InfestedBlock.infestedStateByHost(blockstate), 3); + this.mob.spawnAnim(); + this.mob.discard(); +@@ -210,7 +_,12 @@ BlockState blockstate = level.getBlockState(blockpos1); Block block = blockstate.getBlock(); if (block instanceof InfestedBlock) { - if (level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { ++ // CraftBukkit start ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockpos1, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) { ++ continue; ++ } ++ // CraftBukkit end + if (net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(level, this.silverfish)) { level.destroyBlock(blockpos1, true, this.silverfish); } else { diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Skeleton.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Skeleton.java.patch new file mode 100644 index 0000000000..98f7a4656d --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Skeleton.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Skeleton.java ++++ b/net/minecraft/world/entity/monster/Skeleton.java +@@ -83,7 +_,7 @@ + } + + protected void doFreezeConversion() { +- this.convertTo(EntityType.STRAY, true); ++ this.convertTo(EntityType.STRAY, true, org.bukkit.event.entity.EntityTransformEvent.TransformReason.FROZEN, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.FROZEN); // CraftBukkit - add spawn and transform reasons + if (!this.isSilent()) { + this.level().levelEvent((Player)null, 1048, this.blockPosition(), 0); + } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Slime.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Slime.java.patch index 70199973c8..1b987500b7 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/Slime.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/Slime.java.patch @@ -1,5 +1,26 @@ --- a/net/minecraft/world/entity/monster/Slime.java +++ b/net/minecraft/world/entity/monster/Slime.java +@@ -1,7 +_,10 @@ + package net.minecraft.world.entity.monster; + + import com.google.common.annotations.VisibleForTesting; ++ ++import java.util.ArrayList; + import java.util.EnumSet; ++import java.util.List; + import javax.annotation.Nullable; + import net.minecraft.core.BlockPos; + import net.minecraft.core.particles.ParticleOptions; +@@ -42,6 +_,9 @@ + import net.minecraft.world.level.WorldGenLevel; + import net.minecraft.world.level.levelgen.WorldgenRandom; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.event.entity.EntityTransformEvent; ++import org.bukkit.event.entity.SlimeSplitEvent; + import org.joml.Vector3f; + + public class Slime extends Mob implements Enemy { @@ -130,6 +_,8 @@ if (this.onGround() && !this.wasOnGround) { int i = this.getSize(); @@ -9,6 +30,47 @@ for(int j = 0; j < i * 8; ++j) { float f = this.random.nextFloat() * ((float)Math.PI * 2F); float f1 = this.random.nextFloat() * 0.5F + 0.5F; +@@ -190,6 +_,19 @@ + int j = i / 2; + int k = 2 + this.random.nextInt(3); + ++ // CraftBukkit start ++ SlimeSplitEvent event = new SlimeSplitEvent((org.bukkit.entity.Slime) this.getBukkitEntity(), k); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled() && event.getCount() > 0) { ++ k = event.getCount(); ++ } else { ++ super.remove(p_149847_); ++ return; ++ } ++ List slimes = new ArrayList<>(j); ++ // CraftBukkit end ++ + for(int l = 0; l < k; ++l) { + float f1 = ((float)(l % 2) - 0.5F) * f; + float f2 = ((float)(l / 2) - 0.5F) * f; +@@ -204,9 +_,19 @@ + slime.setInvulnerable(this.isInvulnerable()); + slime.setSize(j, true); + slime.moveTo(this.getX() + (double)f1, this.getY() + 0.5D, this.getZ() + (double)f2, this.random.nextFloat() * 360.0F, 0.0F); +- this.level().addFreshEntity(slime); ++ slimes.add(slime); // CraftBukkit + } + } ++ ++ // CraftBukkit start ++ if (CraftEventFactory.callEntityTransformEvent(this, slimes, EntityTransformEvent.TransformReason.SPLIT).isCancelled()) { ++ super.remove(p_149847_); ++ return; ++ } ++ for (LivingEntity living : slimes) { ++ this.level().addFreshEntity(living, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SLIME_SPLIT); // CraftBukkit - SpawnReason ++ } ++ // CraftBukkit end + } + + super.remove(p_149847_); @@ -329,6 +_,12 @@ public EntityDimensions getDimensions(Pose p_33597_) { return super.getDimensions(p_33597_).scale(0.255F * (float)this.getSize()); diff --git a/patches/minecraft/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch new file mode 100644 index 0000000000..7bd4e9f4ed --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch @@ -0,0 +1,22 @@ +--- a/net/minecraft/world/entity/monster/SpellcasterIllager.java ++++ b/net/minecraft/world/entity/monster/SpellcasterIllager.java +@@ -15,6 +_,7 @@ + import net.minecraft.world.entity.LivingEntity; + import net.minecraft.world.entity.ai.goal.Goal; + import net.minecraft.world.level.Level; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; + + public abstract class SpellcasterIllager extends AbstractIllager { + private static final EntityDataAccessor DATA_SPELL_CASTING_ID = SynchedEntityData.defineId(SpellcasterIllager.class, EntityDataSerializers.BYTE); +@@ -183,6 +_,11 @@ + public void tick() { + --this.attackWarmupDelay; + if (this.attackWarmupDelay == 0) { ++ // CraftBukkit start ++ if (!CraftEventFactory.handleEntitySpellCastEvent(SpellcasterIllager.this, this.getSpell())) { ++ return; ++ } ++ // CraftBukkit end + this.performSpellCasting(); + SpellcasterIllager.this.playSound(SpellcasterIllager.this.getCastingSoundEvent(), 1.0F, 1.0F); + } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Spider.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Spider.java.patch index 7ec902f510..abd6291e5d 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/Spider.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/Spider.java.patch @@ -14,3 +14,12 @@ } public boolean isClimbing() { +@@ -162,7 +_,7 @@ + if (p_33793_ instanceof Spider.SpiderEffectsGroupData spider$spidereffectsgroupdata) { + MobEffect mobeffect = spider$spidereffectsgroupdata.effect; + if (mobeffect != null) { +- this.addEffect(new MobEffectInstance(mobeffect, -1)); ++ this.addEffect(new MobEffectInstance(mobeffect, -1), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.SPIDER_SPAWN); // CraftBukkit + } + } + diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Strider.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Strider.java.patch new file mode 100644 index 0000000000..046833db43 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Strider.java.patch @@ -0,0 +1,18 @@ +--- a/net/minecraft/world/entity/monster/Strider.java ++++ b/net/minecraft/world/entity/monster/Strider.java +@@ -304,7 +_,14 @@ + } + + boolean flag1 = flag2; +- this.setSuffocating(!flag || flag1); ++ // CraftBukkit start ++ boolean suffocating = !flag || flag2; ++ if (suffocating ^ this.isSuffocating()) { ++ if (org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callStriderTemperatureChangeEvent(this, suffocating)) { ++ this.setSuffocating(suffocating); ++ } ++ } ++ // CraftBukkit end + } + + super.tick(); diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Vex.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Vex.java.patch new file mode 100644 index 0000000000..f0f423f327 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Vex.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Vex.java ++++ b/net/minecraft/world/entity/monster/Vex.java +@@ -285,7 +_,7 @@ + } + + public void start() { +- Vex.this.setTarget(Vex.this.owner.getTarget()); ++ Vex.this.setTarget(Vex.this.owner.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.OWNER_ATTACKED_TARGET, true); // CraftBukkit + super.start(); + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Witch.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Witch.java.patch new file mode 100644 index 0000000000..d6f72fbeef --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/Witch.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Witch.java ++++ b/net/minecraft/world/entity/monster/Witch.java +@@ -120,7 +_,7 @@ + List list = PotionUtils.getMobEffects(itemstack); + if (list != null) { + for(MobEffectInstance mobeffectinstance : list) { +- this.addEffect(new MobEffectInstance(mobeffectinstance)); ++ this.addEffect(new MobEffectInstance(mobeffectinstance), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + } + } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/WitherSkeleton.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/WitherSkeleton.java.patch new file mode 100644 index 0000000000..c479b3d7e7 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/WitherSkeleton.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/WitherSkeleton.java ++++ b/net/minecraft/world/entity/monster/WitherSkeleton.java +@@ -94,7 +_,7 @@ + return false; + } else { + if (p_34169_ instanceof LivingEntity) { +- ((LivingEntity)p_34169_).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this); ++ ((LivingEntity)p_34169_).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + + return true; diff --git a/patches/minecraft/net/minecraft/world/entity/monster/Zombie.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/Zombie.java.patch index bd01b153e8..c217dda1a8 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/Zombie.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/Zombie.java.patch @@ -1,22 +1,81 @@ --- a/net/minecraft/world/entity/monster/Zombie.java +++ b/net/minecraft/world/entity/monster/Zombie.java -@@ -193,7 +_,7 @@ +@@ -12,6 +_,7 @@ + import net.minecraft.network.syncher.EntityDataAccessor; + import net.minecraft.network.syncher.EntityDataSerializers; + import net.minecraft.network.syncher.SynchedEntityData; ++import net.minecraft.server.MinecraftServer; + import net.minecraft.server.level.ServerLevel; + import net.minecraft.sounds.SoundEvent; + import net.minecraft.sounds.SoundEvents; +@@ -64,6 +_,10 @@ + import net.minecraft.world.level.ServerLevelAccessor; + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.BlockState; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.bukkit.event.entity.EntityCombustByEntityEvent; ++import org.bukkit.event.entity.EntityTargetEvent; ++import org.bukkit.event.entity.EntityTransformEvent; + import org.joml.Vector3f; + + public class Zombie extends Monster { +@@ -85,6 +_,7 @@ + private boolean canBreakDoors; + private int inWaterTime; + private int conversionTime; ++ private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field + + public Zombie(EntityType p_34271_, Level p_34272_) { + super(p_34271_, p_34272_); +@@ -192,8 +_,11 @@ + public void tick() { if (!this.level().isClientSide && this.isAlive() && !this.isNoAi()) { if (this.isUnderWaterConverting()) { - --this.conversionTime; +- --this.conversionTime; - if (this.conversionTime < 0) { ++ // 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 && net.minecraftforge.event.ForgeEventFactory.canLivingConvert(this, EntityType.DROWNED, (timer) -> this.conversionTime = timer)) { this.doUnderWaterConversion(); } } else if (this.convertsInWater()) { -@@ -255,6 +_,7 @@ +@@ -209,6 +_,7 @@ + } + + super.tick(); ++ this.lastTick = MinecraftServer.currentTick; // CraftBukkit + } + + public void aiStep() { +@@ -238,6 +_,7 @@ + } + + private void startUnderWaterConversion(int p_34279_) { ++ this.lastTick = MinecraftServer.currentTick; // CraftBukkit + this.conversionTime = p_34279_; + this.getEntityData().set(DATA_DROWNED_CONVERSION_ID, true); + } +@@ -251,12 +_,16 @@ + } + + protected void convertToZombieType(EntityType p_34311_) { +- Zombie zombie = this.convertTo(p_34311_, true); ++ Zombie zombie = this.convertTo(p_34311_, true, EntityTransformEvent.TransformReason.DROWNED, CreatureSpawnEvent.SpawnReason.DROWNED); if (zombie != null) { zombie.handleAttributes(zombie.level().getCurrentDifficultyAt(zombie.blockPosition()).getSpecialMultiplier()); zombie.setCanBreakDoors(zombie.supportsBreakDoorGoal() && this.canBreakDoors()); + net.minecraftforge.event.ForgeEventFactory.onLivingConvert(this, zombie); ++ // CraftBukkit start - SPIGOT-5208: End conversion to stop event spam ++ } else { ++ ((org.bukkit.entity.Zombie) getBukkitEntity()).setConversionTime(-1); ++ // CraftBukkit end } - +- } + + protected boolean isSunSensitive() { @@ -275,11 +_,15 @@ livingentity = (LivingEntity)p_34288_.getEntity(); } @@ -35,16 +94,40 @@ for(int l = 0; l < 50; ++l) { int i1 = i + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1); -@@ -291,6 +_,7 @@ +@@ -291,9 +_,10 @@ if (NaturalSpawner.isSpawnPositionOk(spawnplacements$type, this.level(), blockpos, entitytype) && SpawnPlacements.checkSpawnRules(entitytype, serverlevel, MobSpawnType.REINFORCEMENT, blockpos, this.level().random)) { zombie.setPos((double)i1, (double)j1, (double)k1); if (!this.level().hasNearbyAlivePlayer((double)i1, (double)j1, (double)k1, 7.0D) && this.level().isUnobstructed(zombie) && this.level().noCollision(zombie) && !this.level().containsAnyLiquid(zombie.getBoundingBox())) { +- zombie.setTarget(livingentity); + if (livingentity != null) - zombie.setTarget(livingentity); ++ zombie.setTarget(livingentity, EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET, true); // CraftBukkit zombie.finalizeSpawn(serverlevel, this.level().getCurrentDifficultyAt(zombie.blockPosition()), MobSpawnType.REINFORCEMENT, (SpawnGroupData)null, (CompoundTag)null); - serverlevel.addFreshEntityWithPassengers(zombie); -@@ -376,7 +_,7 @@ +- serverlevel.addFreshEntityWithPassengers(zombie); ++ serverlevel.addFreshEntityWithPassengers(zombie, CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit + this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).addPermanentModifier(new AttributeModifier("Zombie reinforcement caller charge", (double)-0.05F, AttributeModifier.Operation.ADDITION)); + zombie.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).addPermanentModifier(new AttributeModifier("Zombie reinforcement callee charge", (double)-0.05F, AttributeModifier.Operation.ADDITION)); + break; +@@ -311,7 +_,14 @@ + if (flag) { + float f = this.level().getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); + if (this.getMainHandItem().isEmpty() && this.isOnFire() && this.random.nextFloat() < f * 0.3F) { +- p_34276_.setSecondsOnFire(2 * (int)f); ++ // CraftBukkit start ++ EntityCombustByEntityEvent event = new EntityCombustByEntityEvent(this.getBukkitEntity(), p_34276_.getBukkitEntity(), 2 * (int) f); // PAIL: fixme ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ p_34276_.setSecondsOnFire(event.getDuration(), false); ++ } ++ // CraftBukkit end + } + } + +@@ -373,30 +_,38 @@ + } + } +- public boolean killedEntity(ServerLevel p_219160_, LivingEntity p_219161_) { boolean flag = super.killedEntity(p_219160_, p_219161_); - if ((p_219160_.getDifficulty() == Difficulty.NORMAL || p_219160_.getDifficulty() == Difficulty.HARD) && p_219161_ instanceof Villager villager) { @@ -52,13 +135,58 @@ if (p_219160_.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { return flag; } -@@ -388,6 +_,7 @@ - zombievillager.setGossips(villager.getGossips().store(NbtOps.INSTANCE)); - zombievillager.setTradeOffers(villager.getOffers().createTag()); - zombievillager.setVillagerXp(villager.getVillagerXp()); -+ net.minecraftforge.event.ForgeEventFactory.onLivingConvert(p_219161_, zombievillager); - if (!this.isSilent()) { - p_219160_.levelEvent((Player)null, 1026, this.blockPosition(), 0); +- +- ZombieVillager zombievillager = villager.convertTo(EntityType.ZOMBIE_VILLAGER, false); +- if (zombievillager != null) { +- zombievillager.finalizeSpawn(p_219160_, p_219160_.getCurrentDifficultyAt(zombievillager.blockPosition()), MobSpawnType.CONVERSION, new Zombie.ZombieGroupData(false, true), (CompoundTag)null); +- zombievillager.setVillagerData(villager.getVillagerData()); +- zombievillager.setGossips(villager.getGossips().store(NbtOps.INSTANCE)); +- zombievillager.setTradeOffers(villager.getOffers().createTag()); +- zombievillager.setVillagerXp(villager.getVillagerXp()); +- if (!this.isSilent()) { +- p_219160_.levelEvent((Player)null, 1026, this.blockPosition(), 0); +- } +- +- flag = false; +- } ++ // CraftBukkit start ++ flag = zombifyVillager(p_219160_, villager, this.blockPosition(), this.isSilent(), CreatureSpawnEvent.SpawnReason.INFECTION) == null; + } +- + return flag; ++ } ++ ++ public static ZombieVillager zombifyVillager(ServerLevel p_219160_, Villager p_219161_, BlockPos blockPosition, boolean silent, CreatureSpawnEvent.SpawnReason spawnReason) { ++ ZombieVillager zombieVillager = (ZombieVillager) p_219161_.convertTo(EntityType.ZOMBIE_VILLAGER, false, EntityTransformEvent.TransformReason.INFECTION, spawnReason); ++ // CraftBukkit end ++ ++ if (zombieVillager != null) { ++ zombieVillager.finalizeSpawn(p_219160_, p_219160_.getCurrentDifficultyAt(zombieVillager.blockPosition()), MobSpawnType.CONVERSION, new Zombie.ZombieGroupData(false, true), (CompoundTag) null); ++ zombieVillager.setVillagerData(p_219161_.getVillagerData()); ++ zombieVillager.setGossips(p_219161_.getGossips().store(NbtOps.INSTANCE)); ++ zombieVillager.setTradeOffers(p_219161_.getOffers().createTag()); ++ zombieVillager.setVillagerXp(p_219161_.getVillagerXp()); ++ net.minecraftforge.event.ForgeEventFactory.onLivingConvert(p_219161_, zombieVillager); ++ // CraftBukkit start ++ if (!silent) { ++ p_219160_.levelEvent((Player) null, 1026, blockPosition, 0); ++ } ++ ++ // flag = false; ++ } ++ return zombieVillager; ++ // CraftBukkit end + } + + protected float getStandingEyeHeight(Pose p_34313_, EntityDimensions p_34314_) { +@@ -439,7 +_,7 @@ + chicken1.finalizeSpawn(p_34297_, p_34298_, MobSpawnType.JOCKEY, (SpawnGroupData)null, (CompoundTag)null); + chicken1.setChickenJockey(true); + this.startRiding(chicken1); +- p_34297_.addFreshEntity(chicken1); ++ p_34297_.addFreshEntity(chicken1, CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit + } + } } @@ -465,7 +_,7 @@ } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/ZombieVillager.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/ZombieVillager.java.patch index 5310a487ea..0dea09ed5f 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/ZombieVillager.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/ZombieVillager.java.patch @@ -1,15 +1,88 @@ --- a/net/minecraft/world/entity/monster/ZombieVillager.java +++ b/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -129,7 +_,7 @@ +@@ -14,6 +_,7 @@ + import net.minecraft.network.syncher.EntityDataAccessor; + import net.minecraft.network.syncher.EntityDataSerializers; + import net.minecraft.network.syncher.SynchedEntityData; ++import net.minecraft.server.MinecraftServer; + import net.minecraft.server.level.ServerLevel; + import net.minecraft.server.level.ServerPlayer; + import net.minecraft.sounds.SoundEvent; +@@ -46,6 +_,8 @@ + import net.minecraft.world.level.block.BedBlock; + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.BlockState; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.bukkit.event.entity.EntityTransformEvent; + import org.joml.Vector3f; + import org.slf4j.Logger; + +@@ -65,6 +_,7 @@ + @Nullable + private CompoundTag tradeOffers; + private int villagerXp; ++ private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field + + public ZombieVillager(EntityType p_34368_, Level p_34369_) { + super(p_34368_, p_34369_); +@@ -128,8 +_,12 @@ + public void tick() { if (!this.level().isClientSide && this.isAlive() && this.isConverting()) { int i = this.getConversionProgress(); ++ // CraftBukkit start - Use wall time instead of ticks for villager conversion ++ int elapsedTicks = MinecraftServer.currentTick - this.lastTick; ++ i *= elapsedTicks; ++ // CraftBukkit end this.villagerConversionTime -= i; - if (this.villagerConversionTime <= 0) { + if (this.villagerConversionTime <= 0 && net.minecraftforge.event.ForgeEventFactory.canLivingConvert(this, EntityType.VILLAGER, (timer) -> this.villagerConversionTime = timer)) { this.finishConversion((ServerLevel)this.level()); } } -@@ -231,7 +_,7 @@ +@@ -174,8 +_,10 @@ + this.conversionStarter = p_34384_; + this.villagerConversionTime = p_34385_; + this.getEntityData().set(DATA_CONVERTING_ID, true); +- this.removeEffect(MobEffects.WEAKNESS); +- this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, p_34385_, Math.min(this.level().getDifficulty().getId() - 1, 0))); ++ // CraftBukkit start ++ this.removeEffect(MobEffects.WEAKNESS, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); ++ this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, p_34385_, Math.min(this.level().getDifficulty().getId() - 1, 0)), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); ++ // CraftBukkit end + this.level().broadcastEntityEvent(this, (byte)16); + } + +@@ -191,7 +_,13 @@ + } + + private void finishConversion(ServerLevel p_34399_) { +- Villager villager = this.convertTo(EntityType.VILLAGER, false); ++ // CraftBukkit start ++ Villager villager = (Villager) this.convertTo(EntityType.VILLAGER, false, EntityTransformEvent.TransformReason.CURED, CreatureSpawnEvent.SpawnReason.CURED); ++ if (villager == null) { ++ ((org.bukkit.entity.ZombieVillager) getBukkitEntity()).setConversionTime(-1); // SPIGOT-5208: End conversion to stop event spam ++ return; ++ } ++ // CraftBukkit end + + for(EquipmentSlot equipmentslot : EquipmentSlot.values()) { + ItemStack itemstack = this.getItemBySlot(equipmentslot); +@@ -201,7 +_,9 @@ + } else { + double d0 = (double)this.getEquipmentDropChance(equipmentslot); + if (d0 > 1.0D) { ++ this.forceDrops = true; // CraftBukkit + this.spawnAtLocation(itemstack); ++ this.forceDrops = false; // CraftBukkit + } + } + } +@@ -227,11 +_,11 @@ + } + } + +- villager.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)); ++ villager.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); // CraftBukkit if (!this.isSilent()) { p_34399_.levelEvent((Player)null, 1027, this.blockPosition(), 0); } diff --git a/patches/minecraft/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch new file mode 100644 index 0000000000..dcb5b8ea11 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch @@ -0,0 +1,51 @@ +--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java ++++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +@@ -40,6 +_,7 @@ + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.pathfinder.BlockPathTypes; + import net.minecraft.world.phys.AABB; ++import org.bukkit.event.entity.EntityTargetEvent; + import org.joml.Vector3f; + + public class ZombifiedPiglin extends Zombie implements NeutralMob { +@@ -142,7 +_,7 @@ + }).filter((p_296830_) -> { + return !p_296830_.isAlliedTo(this.getTarget()); + }).forEach((p_296829_) -> { +- p_296829_.setTarget(this.getTarget()); ++ p_296829_.setTarget(this.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit + }); + } + +@@ -150,7 +_,7 @@ + this.playSound(SoundEvents.ZOMBIFIED_PIGLIN_ANGRY, this.getSoundVolume() * 2.0F, this.getVoicePitch() * 1.8F); + } + +- public void setTarget(@Nullable LivingEntity p_34478_) { ++ public boolean setTarget(@Nullable LivingEntity p_34478_, EntityTargetEvent.TargetReason reason, boolean fireEvent) { // CraftBukkit - signature + if (this.getTarget() == null && p_34478_ != null) { + this.playFirstAngerSoundIn = FIRST_ANGER_SOUND_DELAY.sample(this.random); + this.ticksUntilNextAlert = ALERT_INTERVAL.sample(this.random); +@@ -160,11 +_,20 @@ + this.setLastHurtByPlayer((Player)p_34478_); + } + +- super.setTarget(p_34478_); ++ return super.setTarget(p_34478_, reason, fireEvent); // CraftBukkit + } + + public void startPersistentAngerTimer() { +- this.setRemainingPersistentAngerTime(PERSISTENT_ANGER_TIME.sample(this.random)); ++ // CraftBukkit start ++ Entity entity = ((ServerLevel) this.level()).getEntity(getPersistentAngerTarget()); ++ org.bukkit.event.entity.PigZombieAngerEvent event = new org.bukkit.event.entity.PigZombieAngerEvent((org.bukkit.entity.PigZombie) this.getBukkitEntity(), (entity == null) ? null : entity.getBukkitEntity(), ZombifiedPiglin.PERSISTENT_ANGER_TIME.sample(this.random)); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ this.setPersistentAngerTarget(null); ++ return; ++ } ++ this.setRemainingPersistentAngerTime(event.getNewAnger()); ++ // CraftBukkit end + } + + public static boolean checkZombifiedPiglinSpawnRules(EntityType p_219174_, LevelAccessor p_219175_, MobSpawnType p_219176_, BlockPos p_219177_, RandomSource p_219178_) { diff --git a/patches/minecraft/net/minecraft/world/entity/projectile/LargeFireball.java.patch b/patches/minecraft/net/minecraft/world/entity/projectile/LargeFireball.java.patch index 15c73d5a91..b8043d8ee2 100644 --- a/patches/minecraft/net/minecraft/world/entity/projectile/LargeFireball.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/projectile/LargeFireball.java.patch @@ -1,13 +1,17 @@ --- a/net/minecraft/world/entity/projectile/LargeFireball.java +++ b/net/minecraft/world/entity/projectile/LargeFireball.java -@@ -8,6 +_,7 @@ +@@ -8,9 +_,10 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; +import org.bukkit.event.entity.ExplosionPrimeEvent; public class LargeFireball extends Fireball { - private int explosionPower = 1; +- private int explosionPower = 1; ++ public int explosionPower = 1; + + public LargeFireball(EntityType p_37199_, Level p_37200_) { + super(p_37199_, p_37200_); @@ -24,8 +_,17 @@ protected void onHit(HitResult p_37218_) { super.onHit(p_37218_); From 6884264a1f54ebc8c48a6e8dfa502a40831e76cb Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 22:10:45 +0100 Subject: [PATCH 15/26] [skip ci] Warden monster patches --- .../world/entity/monster/warden/Warden.java.patch | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 patches/minecraft/net/minecraft/world/entity/monster/warden/Warden.java.patch diff --git a/patches/minecraft/net/minecraft/world/entity/monster/warden/Warden.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/warden/Warden.java.patch new file mode 100644 index 0000000000..7f8ddaa90a --- /dev/null +++ b/patches/minecraft/net/minecraft/world/entity/monster/warden/Warden.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/warden/Warden.java ++++ b/net/minecraft/world/entity/monster/warden/Warden.java +@@ -371,7 +_,7 @@ + + public static void applyDarknessAround(ServerLevel p_219376_, Vec3 p_219377_, @Nullable Entity p_219378_, int p_219379_) { + MobEffectInstance mobeffectinstance = new MobEffectInstance(MobEffects.DARKNESS, 260, 0, false, false); +- MobEffectUtil.addEffectToPlayersAround(p_219376_, p_219378_, p_219377_, (double)p_219379_, mobeffectinstance, 200); ++ MobEffectUtil.addEffectToPlayersAround(p_219376_, p_219378_, p_219377_, (double)p_219379_, mobeffectinstance, 200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.WARDEN); // CraftBukkit - Add EntityPotionEffectEvent.Cause + } + + public void addAdditionalSaveData(CompoundTag p_219434_) { From 0403a2ce146065a97b218b448b86195d6ea7baf8 Mon Sep 17 00:00:00 2001 From: TonimatasDEV Date: Tue, 14 Nov 2023 22:25:46 +0100 Subject: [PATCH 16/26] Piglin monster patches --- .../monster/piglin/AbstractPiglin.java.patch | 8 +- .../entity/monster/piglin/Piglin.java.patch | 69 ++++++++++++ .../entity/monster/piglin/PiglinAi.java.patch | 104 +++++++++++++++++- 3 files changed, 174 insertions(+), 7 deletions(-) diff --git a/patches/minecraft/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch index 7e71d6b5a8..a80f7bb014 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch @@ -12,8 +12,12 @@ this.playConvertedSound(); this.finishConversion((ServerLevel)this.level()); } -@@ -110,6 +_,7 @@ - ZombifiedPiglin zombifiedpiglin = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, true); +@@ -107,9 +_,10 @@ + } + + protected void finishConversion(ServerLevel p_34663_) { +- ZombifiedPiglin zombifiedpiglin = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, true); ++ ZombifiedPiglin zombifiedpiglin = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, true, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED); // CraftBukkit - add spawn and transform reasons if (zombifiedpiglin != null) { zombifiedpiglin.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)); + net.minecraftforge.event.ForgeEventFactory.onLivingConvert(this, zombifiedpiglin); diff --git a/patches/minecraft/net/minecraft/world/entity/monster/piglin/Piglin.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/piglin/Piglin.java.patch index b448373fb1..f717b5aa7a 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/piglin/Piglin.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/piglin/Piglin.java.patch @@ -1,5 +1,74 @@ --- a/net/minecraft/world/entity/monster/piglin/Piglin.java +++ b/net/minecraft/world/entity/monster/piglin/Piglin.java +@@ -2,14 +_,23 @@ + + import com.google.common.collect.ImmutableList; + import com.mojang.serialization.Dynamic; ++ ++import java.util.HashSet; + import java.util.List; ++import java.util.Set; + import java.util.UUID; ++import java.util.stream.Collectors; + import javax.annotation.Nullable; + 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; +@@ -44,6 +_,7 @@ + import net.minecraft.world.entity.npc.InventoryCarrier; + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.entity.projectile.Projectile; ++import net.minecraft.world.item.Item; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; + import net.minecraft.world.item.ProjectileWeaponItem; +@@ -74,6 +_,10 @@ + private boolean cannotHunt; + protected static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.NEAREST_ITEMS, SensorType.HURT_BY, SensorType.PIGLIN_SPECIFIC_SENSOR); + protected static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.LOOK_TARGET, MemoryModuleType.DOORS_TO_CLOSE, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, MemoryModuleType.NEARBY_ADULT_PIGLINS, MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, MemoryModuleType.ITEM_PICKUP_COOLDOWN_TICKS, MemoryModuleType.HURT_BY, MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.INTERACTION_TARGET, MemoryModuleType.PATH, MemoryModuleType.ANGRY_AT, MemoryModuleType.UNIVERSAL_ANGER, MemoryModuleType.AVOID_TARGET, MemoryModuleType.ADMIRING_ITEM, MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM, MemoryModuleType.ADMIRING_DISABLED, MemoryModuleType.DISABLE_WALK_TO_ADMIRE_ITEM, MemoryModuleType.CELEBRATE_LOCATION, MemoryModuleType.DANCING, MemoryModuleType.HUNTED_RECENTLY, MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, MemoryModuleType.RIDE_TARGET, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, MemoryModuleType.ATE_RECENTLY, MemoryModuleType.NEAREST_REPELLENT); ++ // CraftBukkit start - Custom bartering and interest list ++ public Set allowedBarterItems = new HashSet<>(); ++ public Set interestItems = new HashSet<>(); ++ // CraftBukkit end + + public Piglin(EntityType p_34683_, Level p_34684_) { + super(p_34683_, p_34684_); +@@ -91,6 +_,14 @@ + } + + this.writeInventoryToTag(p_34751_); ++ // CraftBukkit start ++ ListTag barterList = new ListTag(); ++ allowedBarterItems.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).map(StringTag::valueOf).forEach(barterList::add); ++ p_34751_.put("Bukkit.BarterList", barterList); ++ ListTag interestList = new ListTag(); ++ interestItems.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).map(StringTag::valueOf).forEach(interestList::add); ++ p_34751_.put("Bukkit.InterestList", interestList); ++ // CraftBukkit end + } + + public void readAdditionalSaveData(CompoundTag p_34725_) { +@@ -98,6 +_,10 @@ + this.setBaby(p_34725_.getBoolean("IsBaby")); + this.setCannotHunt(p_34725_.getBoolean("CannotHunt")); + this.readInventoryFromTag(p_34725_); ++ // CraftBukkit start ++ this.allowedBarterItems = p_34725_.getList("Bukkit.BarterList", 8).stream().map(Tag::getAsString).map(ResourceLocation::tryParse).map(BuiltInRegistries.ITEM::get).collect(Collectors.toCollection(HashSet::new)); ++ this.interestItems = p_34725_.getList("Bukkit.InterestList", 8).stream().map(Tag::getAsString).map(ResourceLocation::tryParse).map(BuiltInRegistries.ITEM::get).collect(Collectors.toCollection(HashSet::new)); ++ // CraftBukkit end + } + + @VisibleForDebug @@ -289,7 +_,7 @@ } else if (this.isChargingCrossbow()) { return PiglinArmPose.CROSSBOW_CHARGE; diff --git a/patches/minecraft/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch b/patches/minecraft/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch index a3d329b13c..5fd7e54808 100644 --- a/patches/minecraft/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch @@ -1,29 +1,110 @@ --- a/net/minecraft/world/entity/monster/piglin/PiglinAi.java +++ b/net/minecraft/world/entity/monster/piglin/PiglinAi.java -@@ -268,7 +_,7 @@ +@@ -6,6 +_,8 @@ + import java.util.Collections; + import java.util.List; + import java.util.Optional; ++import java.util.stream.Collectors; ++ + import net.minecraft.server.level.ServerLevel; + import net.minecraft.sounds.SoundEvent; + import net.minecraft.sounds.SoundEvents; +@@ -72,6 +_,9 @@ + import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; + import net.minecraft.world.level.storage.loot.parameters.LootContextParams; + import net.minecraft.world.phys.Vec3; ++import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory; ++import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; ++import org.bukkit.event.entity.PiglinBarterEvent; + + public class PiglinAi { + public static final int REPELLENT_DETECTION_RANGE_HORIZONTAL = 8; +@@ -221,23 +_,27 @@ + protected static void pickUpItem(Piglin p_34844_, ItemEntity p_34845_) { + stopWalking(p_34844_); + ItemStack itemstack; +- if (p_34845_.getItem().is(Items.GOLD_NUGGET)) { ++ // CraftBukkit start ++ if (p_34845_.getItem().is(Items.GOLD_NUGGET) && !org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityPickupItemEvent(p_34844_, p_34845_, 0, false).isCancelled()) { + p_34844_.take(p_34845_, p_34845_.getItem().getCount()); + itemstack = p_34845_.getItem(); + p_34845_.discard(); +- } else { ++ } else if (!org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callEntityPickupItemEvent(p_34844_, p_34845_, p_34845_.getItem().getCount() - 1, false).isCancelled()) { + p_34844_.take(p_34845_, 1); + itemstack = removeOneItemFromItemEntity(p_34845_); ++ } else { ++ return; + } ++ // CraftBukkit end + +- if (isLovedItem(itemstack)) { ++ if (isLovedItem(itemstack, p_34844_)) { // CraftBukkit - Changes to allow for custom payment in bartering + p_34844_.getBrain().eraseMemory(MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM); + holdInOffhand(p_34844_, itemstack); + admireGoldItem(p_34844_); + } else if (isFood(itemstack) && !hasEatenRecently(p_34844_)) { + eat(p_34844_); + } else { +- boolean flag = !p_34844_.equipItemIfPossible(itemstack).equals(ItemStack.EMPTY); ++ boolean flag = !p_34844_.equipItemIfPossible(itemstack, p_34845_).equals(ItemStack.EMPTY); // CraftBukkit + if (!flag) { + putInInventory(p_34844_, itemstack); + } +@@ -268,9 +_,14 @@ ItemStack itemstack = p_34868_.getItemInHand(InteractionHand.OFF_HAND); p_34868_.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); if (p_34868_.isAdult()) { - boolean flag = isBarterCurrency(itemstack); -+ boolean flag = itemstack.isPiglinCurrency(); ++ boolean flag = isBarterCurrency(itemstack, p_34868_); // CraftBukkit - Changes to allow custom payment for bartering if (p_34869_ && flag) { - throwItems(p_34868_, getBarterResponseItems(p_34868_)); +- throwItems(p_34868_, getBarterResponseItems(p_34868_)); ++ // CraftBukkit start ++ PiglinBarterEvent event = CraftEventFactory.callPiglinBarterEvent(p_34868_, getBarterResponseItems(p_34868_), itemstack); ++ if (!event.isCancelled()) { ++ throwItems(p_34868_, event.getOutcome().stream().map(CraftItemStack::asNMSCopy).collect(Collectors.toList())); ++ } ++ // CraftBukkit end } else if (!flag) { + boolean flag1 = !p_34868_.equipItemIfPossible(itemstack).isEmpty(); + if (!flag1) { +@@ -281,7 +_,7 @@ + boolean flag2 = !p_34868_.equipItemIfPossible(itemstack).isEmpty(); + if (!flag2) { + ItemStack itemstack1 = p_34868_.getMainHandItem(); +- if (isLovedItem(itemstack1)) { ++ if (isLovedItem(itemstack1, p_34868_)) { // CraftBukkit - Changes to allow for custom payment in bartering + putInInventory(p_34868_, itemstack1); + } else { + throwItems(p_34868_, Collections.singletonList(itemstack1)); @@ -356,7 +_,7 @@ return false; } else if (isAdmiringDisabled(p_34858_) && p_34858_.getBrain().hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) { return false; - } else if (isBarterCurrency(p_34859_)) { -+ } else if (p_34859_.isPiglinCurrency()) { ++ } else if (isBarterCurrency(p_34859_, p_34858_)) { return isNotHoldingLovedItemInOffHand(p_34858_); } else { boolean flag = p_34858_.canAddToInventory(p_34859_); +@@ -372,6 +_,12 @@ + } + } + ++ // CraftBukkit start - Added method to allow checking for custom payment items ++ protected static boolean isLovedItem(ItemStack itemstack, Piglin piglin) { ++ return isLovedItem(itemstack) || (piglin.interestItems.contains(itemstack.getItem()) || piglin.allowedBarterItems.contains(itemstack.getItem())); ++ } ++ // CraftBukkit end ++ + protected static boolean isLovedItem(ItemStack p_149966_) { + return p_149966_.is(ItemTags.PIGLIN_LOVED); + } @@ -455,7 +_,7 @@ } protected static boolean canAdmire(Piglin p_34910_, ItemStack p_34911_) { - return !isAdmiringDisabled(p_34910_) && !isAdmiringItem(p_34910_) && p_34910_.isAdult() && isBarterCurrency(p_34911_); -+ return !isAdmiringDisabled(p_34910_) && !isAdmiringItem(p_34910_) && p_34910_.isAdult() && p_34911_.isPiglinCurrency(); ++ return !isAdmiringDisabled(p_34910_) && !isAdmiringItem(p_34910_) && p_34910_.isAdult() && isBarterCurrency(p_34911_, p_34910_); // CraftBukkit } protected static void wasHurtBy(Piglin p_34838_, LivingEntity p_34839_) { @@ -45,3 +126,16 @@ } private static void admireGoldItem(LivingEntity p_34939_) { +@@ -713,6 +_,12 @@ + private static boolean isAdmiringItem(Piglin p_35021_) { + return p_35021_.getBrain().hasMemoryValue(MemoryModuleType.ADMIRING_ITEM); + } ++ ++ // CraftBukkit start - Changes to allow custom payment for bartering ++ private static boolean isBarterCurrency(ItemStack itemstack, Piglin piglin) { ++ return isBarterCurrency(itemstack) || piglin.allowedBarterItems.contains(itemstack.getItem()); ++ } ++ // CraftBukkit end + + private static boolean isBarterCurrency(ItemStack p_149968_) { + return p_149968_.is(BARTERING_ITEM); From df9b489969a2b20918e64cb77a36e893ce0c5702 Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Wed, 15 Nov 2023 07:24:30 +0100 Subject: [PATCH 17/26] Update forge to 48.0.34 --- docs/README.md | 4 ++-- .../net/minecraftforge/fml/loading/moddiscovery/ModInfo.java | 5 +++-- src/main/resources/META-INF/mods.toml | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index db5a6f42e3..08866a76aa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ [discord-widget]: https://canary.discord.com/api/guilds/1172551819138965605/widget.png [discord-invite]: https://discord.gg/jBHZDG9WS8 -[forge-version]: https://img.shields.io/badge/1.20.2--48.0.33-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d -[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/7a44327 +[forge-version]: https://img.shields.io/badge/1.20.2--48.0.34-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d +[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/a27405b diff --git a/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModInfo.java b/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModInfo.java index 267f302c8a..5456481c4c 100644 --- a/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModInfo.java +++ b/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModInfo.java @@ -80,7 +80,8 @@ public ModInfo(final ModFileInfo owningFile, final IConfigurable config) this.displayName = config.getConfigElement("displayName") .orElse(this.modId); this.description = config.getConfigElement("description") - .orElse("MISSING DESCRIPTION"); + .orElse("MISSING DESCRIPTION") + .replace("\r\n", "\n").stripIndent(); this.logoFile = Optional.ofNullable(config.getConfigElement("logoFile") .orElseGet(() -> ownFile.flatMap(mf -> mf.getConfigElement("logoFile")) .orElse(null))); @@ -205,7 +206,7 @@ class ModVersion implements net.minecraftforge.forgespi.language.IModInfo.ModVer private final boolean mandatory; private final Ordering ordering; private final DependencySide side; - private Optional referralUrl; + private final Optional referralUrl; public ModVersion(final IModInfo owner, final IConfigurable config) { this.owner = owner; diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 25ce7e46ce..09681342e3 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,14 +1,14 @@ modLoader="javafml" loaderVersion="[24,]" -issueTrackerURL="http://www.minecraftforge.net/" +issueTrackerURL="https://minecraftforge.net/" logoFile="forge_logo.png" license="LGPL v2.1" [[mods]] modId="forge" - # We use the global forge version version="${global.forgeVersion}" updateJSONURL="https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json" + displayURL="https://minecraftforge.net/" displayName="Forge" credits="Anyone who has contributed on Github and supports our development" authors="LexManos,cpw" From 2a58c9e0ab8dfe818b9f3e0c4c38e2144e9f4974 Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Wed, 15 Nov 2023 07:28:35 +0100 Subject: [PATCH 18/26] Update forge to 48.0.35 --- docs/README.md | 4 ++-- .../minecraft/world/item/crafting/Ingredient.java.patch | 9 +++++++++ src/main/java/net/minecraftforge/common/ForgeMod.java | 6 ++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 08866a76aa..0f3316b837 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ [discord-widget]: https://canary.discord.com/api/guilds/1172551819138965605/widget.png [discord-invite]: https://discord.gg/jBHZDG9WS8 -[forge-version]: https://img.shields.io/badge/1.20.2--48.0.34-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d -[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/a27405b +[forge-version]: https://img.shields.io/badge/1.20.2--48.0.35-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d +[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/da34d97 diff --git a/patches/minecraft/net/minecraft/world/item/crafting/Ingredient.java.patch b/patches/minecraft/net/minecraft/world/item/crafting/Ingredient.java.patch index 8561f9279c..3f237c1817 100644 --- a/patches/minecraft/net/minecraft/world/item/crafting/Ingredient.java.patch +++ b/patches/minecraft/net/minecraft/world/item/crafting/Ingredient.java.patch @@ -28,6 +28,15 @@ protected Ingredient(Stream p_43907_) { this.values = p_43907_.toArray((p_43933_) -> { +@@ -50,7 +_,7 @@ + } + + public ItemStack[] getItems() { +- if (this.itemStacks == null) { ++ if (this.itemStacks == null || checkInvalidation()) { + this.itemStacks = Arrays.stream(this.values).flatMap((p_43916_) -> { + return p_43916_.getItems().stream(); + }).distinct().toArray((p_43910_) -> { @@ -68,6 +_,15 @@ return p_43914_.isEmpty(); } else { diff --git a/src/main/java/net/minecraftforge/common/ForgeMod.java b/src/main/java/net/minecraftforge/common/ForgeMod.java index dc413efeec..97e7e0fa0c 100644 --- a/src/main/java/net/minecraftforge/common/ForgeMod.java +++ b/src/main/java/net/minecraftforge/common/ForgeMod.java @@ -58,6 +58,7 @@ import net.minecraftforge.common.world.NoneBiomeModifier; import net.minecraftforge.common.world.NoneStructureModifier; import net.minecraftforge.common.world.StructureModifier; +import net.minecraftforge.event.TagsUpdatedEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fluids.FluidType; import net.minecraftforge.fluids.ForgeFlowingFluid; @@ -428,6 +429,7 @@ public ForgeMod() { MinecraftForge.EVENT_BUS.addListener(VillagerTradingManager::loadTrades); MinecraftForge.EVENT_BUS.register(MinecraftForge.INTERNAL_HANDLER); MinecraftForge.EVENT_BUS.addListener(this::mappingChanged); + MinecraftForge.EVENT_BUS.addListener(this::tagsUpdated); MinecraftForge.EVENT_BUS.addListener(this::registerPermissionNodes); MinecraftForge.EVENT_BUS.register(new ForgeNetworkConfigurationHandler()); @@ -454,6 +456,10 @@ public void mappingChanged(IdMappingEvent evt) { Ingredient.invalidateAll(); } + public void tagsUpdated(TagsUpdatedEvent evt) { + Ingredient.invalidateAll(); + } + public void gatherData(GatherDataEvent event) { DataGenerator gen = event.getGenerator(); PackOutput packOutput = gen.getPackOutput(); From f51a9c77f8feb730f49db211ef22cfda03cebe90 Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Wed, 15 Nov 2023 07:42:15 +0100 Subject: [PATCH 19/26] Update forge to 48.0.36 --- build.gradle | 5 ++-- build_clean.gradle | 4 ++-- docs/README.md | 4 ++-- gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 63721 bytes gradle/wrapper/gradle-wrapper.properties | 5 ++-- gradlew | 29 +++++++++++++---------- 6 files changed, 27 insertions(+), 20 deletions(-) diff --git a/build.gradle b/build.gradle index 83da5725b7..d64b40fd63 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,4 @@ +import de.undercouch.gradle.tasks.download.Download import groovy.json.JsonBuilder import net.minecraftforge.forge.tasks.checks.CheckATs import net.minecraftforge.forge.tasks.checks.CheckExcs @@ -28,8 +29,8 @@ plugins { id 'net.minecraftforge.gradleutils' version '2.1.3' id 'eclipse' id 'de.undercouch.download' version '5.4.0' - id 'net.minecraftforge.gradle.patcher' version '[6.0.14,6.2)' apply false - id 'net.minecraftforge.gradle.mcp' version '[6.0.14,6.2)' apply false + id 'net.minecraftforge.gradle.patcher' version '[6.0.16,6.2)' apply false + id 'net.minecraftforge.gradle.mcp' version '[6.0.16,6.2)' apply false id "dev.vankka.dependencydownload.plugin" version "1.3.1" apply false } diff --git a/build_clean.gradle b/build_clean.gradle index 87767b3257..b41e464f89 100644 --- a/build_clean.gradle +++ b/build_clean.gradle @@ -1,8 +1,7 @@ plugins { - id 'org.cadixdev.licenser' id 'java-library' id 'eclipse' - id 'net.minecraftforge.gradle.patcher' version '[6.0.14,6.2)' + id 'net.minecraftforge.gradle.patcher' version '[6.0.16,6.2)' } evaluationDependsOn(':mcp') @@ -44,6 +43,7 @@ patcher { } } } + eclipse.classpath.file.whenMerged { // Disable optional warnings on the minecraft decompiled source code. It just muddies the warning window and hides warnings in our own codebase def src = entries.find { it.path == 'src/main/java' } diff --git a/docs/README.md b/docs/README.md index 0f3316b837..52f2f0bdf4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ [discord-widget]: https://canary.discord.com/api/guilds/1172551819138965605/widget.png [discord-invite]: https://discord.gg/jBHZDG9WS8 -[forge-version]: https://img.shields.io/badge/1.20.2--48.0.35-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d -[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/da34d97 +[forge-version]: https://img.shields.io/badge/1.20.2--48.0.36-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d +[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/dff52ec diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..7f93135c49b765f8051ef9d0a6055ff8e46073d8 100644 GIT binary patch delta 41154 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%0DEqyP8OADCy^l*0 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 221e3a607c..01f330a93e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,8 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip -distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f +distributionSha256Sum=f2b9ed0faf8472cbe469255ae6c86eddb77076c75191741b4a462f33128dd419 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68d65..1aa94a4269 100755 --- a/gradlew +++ b/gradlew @@ -83,10 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ From 7dff60368ddf0e7d126a9ecd8b59b4c18f5947db Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Wed, 15 Nov 2023 08:09:44 +0100 Subject: [PATCH 20/26] Update forge to 48.0.37 --- build.gradle | 2 +- docs/README.md | 4 ++-- .../java/net/minecraftforge/client/model/obj/ObjModel.java | 4 ++-- .../client/textures/UnitTextureAtlasSprite.java | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index d64b40fd63..5cf48ee271 100644 --- a/build.gradle +++ b/build.gradle @@ -55,7 +55,7 @@ ext { INSTALLER_VERSION = '2.1.+' GIT_INFO = gradleutils.gitInfo - FORGE_VERSION = "48.0.33" + FORGE_VERSION = "48.0.37" VERSION = "${MC_VERSION}-${FORGE_VERSION}" KETTING_VERSION = "${VERSION}-${GIT_INFO.abbreviatedId}" diff --git a/docs/README.md b/docs/README.md index 52f2f0bdf4..fb3c6c32c1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ [discord-widget]: https://canary.discord.com/api/guilds/1172551819138965605/widget.png [discord-invite]: https://discord.gg/jBHZDG9WS8 -[forge-version]: https://img.shields.io/badge/1.20.2--48.0.36-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d -[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/dff52ec +[forge-version]: https://img.shields.io/badge/1.20.2--48.0.37-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d +[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/7cd8894 diff --git a/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java b/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java index 3891d609a2..5a51631fd2 100644 --- a/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java +++ b/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java @@ -424,8 +424,8 @@ private Pair makeQuad(int[][] indices, int tintIndex, Vect quadBaker.vertex(position.x(), position.y(), position.z()); quadBaker.color(tintedColor.x(), tintedColor.y(), tintedColor.z(), tintedColor.w()); quadBaker.uv( - texture.getU(texCoord.x * 16), - texture.getV((flipV ? 1 - texCoord.y : texCoord.y) * 16) + texture.getU(texCoord.x), + texture.getV((flipV ? 1 - texCoord.y : texCoord.y)) ); quadBaker.uv2(uv2); quadBaker.normal(normal.x(), normal.y(), normal.z()); diff --git a/src/main/java/net/minecraftforge/client/textures/UnitTextureAtlasSprite.java b/src/main/java/net/minecraftforge/client/textures/UnitTextureAtlasSprite.java index 649cf9d687..2a3f4ffa09 100644 --- a/src/main/java/net/minecraftforge/client/textures/UnitTextureAtlasSprite.java +++ b/src/main/java/net/minecraftforge/client/textures/UnitTextureAtlasSprite.java @@ -27,11 +27,11 @@ private UnitTextureAtlasSprite() { @Override public float getU(float u) { - return u / 16; + return u; } @Override public float getV(float v) { - return v / 16; + return v; } } From bc8898cae98850f04c995f1a44e4eb4f1c532aea Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Wed, 15 Nov 2023 08:17:34 +0100 Subject: [PATCH 21/26] Update forge to 48.0.38 --- build.gradle | 2 +- docs/README.md | 4 ++-- patches/minecraft/net/minecraft/tags/TagLoader.java.patch | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 5cf48ee271..781be2c366 100644 --- a/build.gradle +++ b/build.gradle @@ -55,7 +55,7 @@ ext { INSTALLER_VERSION = '2.1.+' GIT_INFO = gradleutils.gitInfo - FORGE_VERSION = "48.0.37" + FORGE_VERSION = "48.0.38" VERSION = "${MC_VERSION}-${FORGE_VERSION}" KETTING_VERSION = "${VERSION}-${GIT_INFO.abbreviatedId}" diff --git a/docs/README.md b/docs/README.md index fb3c6c32c1..dc6664f94a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ [discord-widget]: https://canary.discord.com/api/guilds/1172551819138965605/widget.png [discord-invite]: https://discord.gg/jBHZDG9WS8 -[forge-version]: https://img.shields.io/badge/1.20.2--48.0.37-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d -[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/7cd8894 +[forge-version]: https://img.shields.io/badge/1.20.2--48.0.38-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d +[forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/83c651c diff --git a/patches/minecraft/net/minecraft/tags/TagLoader.java.patch b/patches/minecraft/net/minecraft/tags/TagLoader.java.patch index 0618d68d64..9e1adcce99 100644 --- a/patches/minecraft/net/minecraft/tags/TagLoader.java.patch +++ b/patches/minecraft/net/minecraft/tags/TagLoader.java.patch @@ -13,7 +13,7 @@ private Either, Collection> build(TagEntry.Lookup p_215979_, List p_215980_) { - ImmutableSet.Builder builder = ImmutableSet.builder(); -+ var builder = new java.util.HashSet(); ++ var builder = new java.util.LinkedHashSet(); // Order is important, as ImmutableSet is ordered and some people rely on that. https://github.com/MinecraftForge/MinecraftForge/issues/9774 List list = new ArrayList<>(); for(TagLoader.EntryWithSource tagloader$entrywithsource : p_215980_) { From b3b59fc818c6109a2d7fa220ece0e51b7e2b48ef Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Wed, 15 Nov 2023 08:28:06 +0100 Subject: [PATCH 22/26] [skip ci] add build status --- docs/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/README.md b/docs/README.md index dc6664f94a..0013311018 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,11 +2,14 @@ [discord-invite]: https://discord.gg/jBHZDG9WS8 [forge-version]: https://img.shields.io/badge/1.20.2--48.0.38-none?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjCGJ1kDAAACoElEQVQ4T22SeU8aURTF%2FULGtNRWWVQY9lXABWldIDPIMgVbNgEVtaa0damiqGBdipXaJcY2ofEf4ycbTt97pVAabzK5b27u%2BZ377kwXgK77QthRy7OfXbeJM%2BttqKSXN8sdwbT%2FA0L7elmsYqrPHZmROLPh5YkV4oEBwaKuHj%2ByyJptLDoAhbq3O1V1XCVObY3FL24mfn5oRPrcwSCRfQOyNWcjVjZdCbtcdwcgXrXUspdOKbDN%2FXE9tiBJMhXHT60gUIT2dMhcDLMc3NVKQklz0QIkf5qlyEcO6Qs7yPhMJB4amDMFimQSmqNlE8SKAZFzDfxHfVILIIZ10sJ3OwIbcqSuiOjchkzNCboHev9o2YhgiUP8mxnLN24I6%2F3ghYdtQG5iUMpFBuCP9iKwLsfiLyeCp2rMnZgwX3NArGoxW1Ridl%2BBzLEVKa8KSxOqNmDdz0kFnxaLHhWEgAyZigWhHXL%2BpEDy2ozsDxv8vAzTnh7w5kcghqCaFmCT10of4iPIT2mRdPUh4HoCcVwBH%2F8Ac2kzUkEV5r3EfVSOvbAJa5NDyI0r2oDtWb1EClh%2BOoC3Pg7v%2FBw7p939yI4rsRW2Y3lKh01eh7WpIRyKZqzyjjYgPdIvlaMWRqYuG7wWryYHsRM0sFolZiPvQ3jheIwSmSBPdkByG%2FB6Wi3RYiVmRX7GiAPiUCRisii8D%2BjZNKvPBrHCW1GY0bAz6WkDCtOaSyKQFsi4K5NqNiZtehN2Y5uAShETqolhBqJXpfdPuPsuWwAaRdHSkxdc11mPqkGnyY4pyKbpl1GyJ0Pel7yqBoFcF3zqno5f%2Bd8ohYy9Sx7lzQpxo1eirluCDgt%2B%2B00p6uxttrG4F%2FA39sJGZWZMfrcp6O6%2B5kaVzXJHAOj6DeSs8qw5o8oxAAAAAElFTkSuQmCC&labelColor=4e4e4e&color=2d2d2d [forge-commit]: https://github.com/MinecraftForge/MinecraftForge/commit/83c651c +[build-status]: https://img.shields.io/github/actions/workflow/status/kettingpowered/Ketting-1-20-x/build_and_release.yml +[build-link]: https://github.com/kettingpowered/Ketting-1-20-x/actions [![discord-widget][]][discord-invite] [![forge-version][]][forge-commit] +[![build-status][]][build-link] # Ketting From 15b11bc248c0c268868c816f91d6b5e60cfe0c2c Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Wed, 15 Nov 2023 08:58:17 +0100 Subject: [PATCH 23/26] Update README.md --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 0013311018..efa08b876e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -66,7 +66,7 @@ Forge MDK from [their website](https://files.minecraftforge.net/net/minecraftfor Ketting uses the Gradle build system, so you can build it by running the following command: ```bash -./gradlew build +./gradlew setup ``` To create a jar, run From 757c70c9c4ab4d3953a6ff55ce0b4cfea85a5d60 Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Thu, 16 Nov 2023 13:57:46 +0100 Subject: [PATCH 24/26] [skip ci] fix ambient entity patches --- docs/README.md | 2 +- .../net/minecraft/world/entity/ambient/Bat.java.patch | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index efa08b876e..f139eff54d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,7 @@ that enables the use of Bukkit plugins on Forge servers. Ketting is still in development and is not ready for production use. ### PATCHES DONE -Bukkit: 291 / 530 +Bukkit: 292 / 530
CraftBukkit: 0 / 685 diff --git a/patches/minecraft/net/minecraft/world/entity/ambient/Bat.java.patch b/patches/minecraft/net/minecraft/world/entity/ambient/Bat.java.patch index 8acb0a0663..e4b84d9f76 100644 --- a/patches/minecraft/net/minecraft/world/entity/ambient/Bat.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/ambient/Bat.java.patch @@ -8,7 +8,7 @@ public class Bat extends AmbientCreature { public static final float FLAP_DEGREES_PER_TICK = 74.48451F; -@@ -125,7 +_,7 @@ +@@ -125,13 +_,13 @@ this.yHeadRot = (float)this.random.nextInt(360); } @@ -17,6 +17,13 @@ this.setResting(false); if (!flag) { this.level().levelEvent((Player)null, 1025, blockpos, 0); + } + } +- } else { ++ } else if (CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent + this.setResting(false); + if (!flag) { + this.level().levelEvent((Player)null, 1025, blockpos, 0); @@ -156,7 +_,7 @@ float f1 = Mth.wrapDegrees(f - this.getYRot()); this.zza = 0.5F; From 83909828caf8933f840712863258094658899a9f Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Thu, 16 Nov 2023 14:31:02 +0100 Subject: [PATCH 25/26] [skip ci] fix boss entity patches --- .../boss/enderdragon/EndCrystal.java.patch | 2 +- .../boss/enderdragon/EnderDragon.java.patch | 37 ++++++++++++++++++- .../phases/EnderDragonPhaseManager.java.patch | 9 ++++- .../entity/boss/wither/WitherBoss.java.patch | 8 ++-- .../v1_20_R2/entity/CraftEnderDragon.java | 10 ++++- .../java/org/bukkit/entity/EnderDragon.java | 6 ++- 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch index 664c36fe70..14c6f066e3 100644 --- a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch @@ -41,7 +41,7 @@ + this.unsetRemoved(); + return false; + } -+ this.level().explode(this, damagesource, (ExplosionDamageCalculator) null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK); ++ this.level().explode(this, damagesource, null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK); + // CraftBukkit end } diff --git a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch index 6519a83ed6..2dd9f83257 100644 --- a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch @@ -1,5 +1,18 @@ --- a/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +++ b/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +@@ -8,10 +_,12 @@ + import net.minecraft.core.particles.ParticleTypes; + import net.minecraft.nbt.CompoundTag; + import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; ++import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; + 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.server.level.ServerPlayer; + import net.minecraft.sounds.SoundEvent; + import net.minecraft.sounds.SoundEvents; + import net.minecraft.sounds.SoundSource; @@ -37,8 +_,12 @@ import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhaseManager; import net.minecraft.world.entity.monster.Enemy; @@ -197,7 +210,7 @@ protected void tickDeath() { if (this.dragonFight != null) { this.dragonFight.updateDragon(this); -@@ -516,15 +_,21 @@ +@@ -516,26 +_,50 @@ this.level().addParticle(ParticleTypes.EXPLOSION_EMITTER, this.getX() + (double)f, this.getY() + 2.0D + (double)f1, this.getZ() + (double)f2, 0.0D, 0.0D, 0.0D); } @@ -221,7 +234,27 @@ } if (this.dragonDeathTime == 1 && !this.isSilent()) { -@@ -534,8 +_,9 @@ +- this.level().globalLevelEvent(1028, this.blockPosition(), 0); ++ // CraftBukkit start - Use relative location for far away sounds ++ // this.level().globalLevelEvent(1028, this.blockPosition(), 0); ++ int viewDistance = this.level().getCraftServer().getViewDistance() * 16; ++ for (ServerPlayer player : this.level().getServer().getPlayerList().players) { ++ double deltaX = this.getX() - player.getX(); ++ double deltaZ = this.getZ() - player.getZ(); ++ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; ++ if (this.level().spigotConfig.dragonDeathSoundRadius > 0 && distanceSquared > this.level().spigotConfig.dragonDeathSoundRadius * this.level().spigotConfig.dragonDeathSoundRadius) continue; // Spigot ++ if (distanceSquared > viewDistance * viewDistance) { ++ double deltaLength = Math.sqrt(distanceSquared); ++ double relativeX = player.getX() + (deltaX / deltaLength) * viewDistance; ++ double relativeZ = player.getZ() + (deltaZ / deltaLength) * viewDistance; ++ player.connection.send(new ClientboundLevelEventPacket(1028, new BlockPos((int) relativeX, (int) this.getY(), (int) relativeZ), 0, true)); ++ } else { ++ player.connection.send(new ClientboundLevelEventPacket(1028, new BlockPos((int) this.getX(), (int) this.getY(), (int) this.getZ()), 0, true)); ++ } ++ } ++ // CraftBukkit end + } + } this.move(MoverType.SELF, new Vec3(0.0D, (double)0.1F, 0.0D)); if (this.dragonDeathTime == 200 && this.level() instanceof ServerLevel) { diff --git a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch index 029b49fd1f..ef7d99ce81 100644 --- a/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/boss/enderdragon/phases/EnderDragonPhaseManager.java.patch @@ -9,7 +9,7 @@ import org.slf4j.Logger; public class EnderDragonPhaseManager { -@@ -22,6 +_,19 @@ +@@ -22,6 +_,24 @@ if (this.currentPhase != null) { this.currentPhase.end(); } @@ -24,7 +24,12 @@ + if (event.isCancelled()) { + return; + } -+ p_31417_ = CraftEnderDragon.getMinecraftPhase(event.getNewPhase()); ++ ++ //Ketting start - check for modded phases ++ EnderDragonPhase newPhase = CraftEnderDragon.getMinecraftPhase(event.getNewPhase()); ++ if (newPhase != null) ++ p_31417_ = newPhase; ++ //Ketting end + // CraftBukkit end this.currentPhase = this.getPhase(p_31417_); diff --git a/patches/minecraft/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/patches/minecraft/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch index fab1f1e105..e8937ee946 100644 --- a/patches/minecraft/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch +++ b/patches/minecraft/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch @@ -42,12 +42,13 @@ + this.level().explode(this, this.getX(), this.getEyeY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); + } + // CraftBukkit end ++ if (!this.isSilent()) { - this.level().globalLevelEvent(1023, this.blockPosition(), 0); +- this.level().globalLevelEvent(1023, this.blockPosition(), 0); + // CraftBukkit start - Use relative location for far away sounds + // this.level().globalLevelEvent(1023, new BlockPosition(this), 0); + int viewDistance = ((ServerLevel) this.level()).getCraftServer().getViewDistance() * 16; -+ for (ServerPlayer player : (List) MinecraftServer.getServer().getPlayerList().players) { ++ for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().players) { + double deltaX = this.getX() - player.getX(); + double deltaZ = this.getZ() - player.getZ(); + double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; @@ -71,10 +72,11 @@ } } else { -@@ -265,6 +_,7 @@ +@@ -265,6 +_,8 @@ List list = this.level().getNearbyEntities(LivingEntity.class, TARGETING_CONDITIONS, this, this.getBoundingBox().inflate(20.0D, 8.0D, 20.0D)); if (!list.isEmpty()) { LivingEntity livingentity1 = list.get(this.random.nextInt(list.size())); ++ + if (CraftEventFactory.callEntityTargetLivingEvent(this, livingentity1, EntityTargetEvent.TargetReason.CLOSEST_ENTITY).isCancelled()) continue; // CraftBukkit this.setAlternativeTarget(i, livingentity1.getId()); } diff --git a/src/main/java/org/bukkit/craftbukkit/v1_20_R2/entity/CraftEnderDragon.java b/src/main/java/org/bukkit/craftbukkit/v1_20_R2/entity/CraftEnderDragon.java index 9dd3c665b9..ed5ac0a4e5 100644 --- a/src/main/java/org/bukkit/craftbukkit/v1_20_R2/entity/CraftEnderDragon.java +++ b/src/main/java/org/bukkit/craftbukkit/v1_20_R2/entity/CraftEnderDragon.java @@ -43,7 +43,10 @@ public String toString() { } public Phase getPhase() { - return Phase.values()[(Integer) this.getHandle().getEntityData().get(net.minecraft.world.entity.boss.enderdragon.EnderDragon.DATA_PHASE)]; + //Ketting start + int phaseId = this.getHandle().getEntityData().get(net.minecraft.world.entity.boss.enderdragon.EnderDragon.DATA_PHASE); + return phaseId > Phase.values().length - 1 ? Phase.MODDED : Phase.values()[phaseId]; + //Ketting end } public void setPhase(Phase phase) { @@ -51,10 +54,13 @@ public void setPhase(Phase phase) { } public static Phase getBukkitPhase(EnderDragonPhase phase) { - return Phase.values()[phase.getId()]; + //Ketting start + return phase.getId() > Phase.values().length - 1 ? Phase.MODDED : Phase.values()[phase.getId()]; + //Ketting end } public static EnderDragonPhase getMinecraftPhase(Phase phase) { + if (phase == Phase.MODDED) return null; //Ketting return EnderDragonPhase.getById(phase.ordinal()); } diff --git a/src/main/java/org/bukkit/entity/EnderDragon.java b/src/main/java/org/bukkit/entity/EnderDragon.java index 1e56aef918..c04f276e1b 100644 --- a/src/main/java/org/bukkit/entity/EnderDragon.java +++ b/src/main/java/org/bukkit/entity/EnderDragon.java @@ -64,7 +64,11 @@ enum Phase { /** * The dragon will hover at its current location, not performing any actions. */ - HOVER + HOVER, + /** + * A phase created by a Forge mod. + */ + MODDED; } /** From a59203a34bb3b90806ce2c0e509e0ce2de5ca01f Mon Sep 17 00:00:00 2001 From: JustRed23 Date: Thu, 16 Nov 2023 14:43:25 +0100 Subject: [PATCH 26/26] [skip ci] update readme --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index f139eff54d..a742dd825e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,7 @@ that enables the use of Bukkit plugins on Forge servers. Ketting is still in development and is not ready for production use. ### PATCHES DONE -Bukkit: 292 / 530 +Bukkit: 296 / 530
CraftBukkit: 0 / 685