c5a10665b8
Spigot still maintains some partial implementation of "tick skipping", a practice in which the MinecraftServer.currentTick field is updated not by an increment of one per actual tick, but instead set to System.currentTimeMillis() / 50. This behaviour means that the tracked tick may "skip" a tick value in case a previous tick took more than the expected 50ms. To compensate for this in important paths, spigot/craftbukkit implements "wall-time". Instead of incrementing/decrementing ticks on block entities/entities by one for each call to their tick() method, they instead increment/decrement important values, like an ItemEntity's age or pickupDelay, by the difference of `currentTick - lastTick`, where `lastTick` is the value of `currentTick` during the last tick() call. These "fixes" however do not play nicely with minecraft's simulation distance as entities/block entities implementing the above behaviour would "catch up" their values when moving from a non-ticking chunk to a ticking one as their `lastTick` value remains stuck on the last tick in a ticking chunk and hence lead to a large "catch up" once ticked again. Paper completely removes the "tick skipping" behaviour (See patch "Further-improve-server-tick-loop"), making the above precautions completely unnecessary, which also rids paper of the previous described incompatibility with non-ticking chunks.
182 Zeilen
11 KiB
Diff
182 Zeilen
11 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
|
Date: Thu, 20 May 2021 20:40:53 -0700
|
|
Subject: [PATCH] Fix potions splash events
|
|
|
|
Fix PotionSplashEvent for water splash potions
|
|
Fixes SPIGOT-6221: https://hub.spigotmc.org/jira/projects/SPIGOT/issues/SPIGOT-6221
|
|
Fix splash events cancellation that still show particles/sound
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
|
|
index be787a5b52e90796d4f06e17e564f4324807c3e6..cb34cc9443da56c0497c7a0192c8b8363c3426fe 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
|
|
@@ -106,55 +106,76 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
|
|
ItemStack itemstack = this.getItem();
|
|
PotionContents potioncontents = (PotionContents) itemstack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY);
|
|
|
|
+ boolean showParticles = true; // Paper - Fix potions splash events
|
|
if (potioncontents.is(Potions.WATER)) {
|
|
- this.applyWater();
|
|
+ showParticles = this.applyWater(hitResult); // Paper - Fix potions splash events
|
|
} else if (true || potioncontents.hasEffects()) { // CraftBukkit - Call event even if no effects to apply
|
|
if (this.isLingering()) {
|
|
- this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition
|
|
+ showParticles = this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper
|
|
} else {
|
|
- this.applySplash(potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition
|
|
+ showParticles = this.applySplash(potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper
|
|
}
|
|
}
|
|
|
|
+ if (showParticles) { // Paper - Fix potions splash events
|
|
int i = potioncontents.potion().isPresent() && ((Potion) ((Holder) potioncontents.potion().get()).value()).hasInstantEffects() ? 2007 : 2002;
|
|
|
|
this.level().levelEvent(i, this.blockPosition(), potioncontents.getColor());
|
|
+ } // Paper - Fix potions splash events
|
|
this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
|
|
}
|
|
}
|
|
|
|
- private void applyWater() {
|
|
+ private static final Predicate<net.minecraft.world.entity.LivingEntity> APPLY_WATER_GET_ENTITIES_PREDICATE = ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE.or(Axolotl.class::isInstance); // Paper - Fix potions splash events
|
|
+ private boolean applyWater(@Nullable HitResult hitResult) { // Paper - Fix potions splash events
|
|
AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D);
|
|
- List<net.minecraft.world.entity.LivingEntity> list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.WATER_SENSITIVE_OR_ON_FIRE);
|
|
+ // Paper start - Fix potions splash events
|
|
+ List<net.minecraft.world.entity.LivingEntity> list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb, ThrownPotion.APPLY_WATER_GET_ENTITIES_PREDICATE);
|
|
+ Map<LivingEntity, Double> affected = new HashMap<>();
|
|
+ java.util.Set<LivingEntity> rehydrate = new java.util.HashSet<>();
|
|
+ java.util.Set<LivingEntity> extinguish = new java.util.HashSet<>();
|
|
Iterator iterator = list.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
net.minecraft.world.entity.LivingEntity entityliving = (net.minecraft.world.entity.LivingEntity) iterator.next();
|
|
+ if (entityliving instanceof Axolotl axolotl) {
|
|
+ rehydrate.add(((org.bukkit.entity.Axolotl) axolotl.getBukkitEntity()));
|
|
+ }
|
|
double d0 = this.distanceToSqr((Entity) entityliving);
|
|
|
|
if (d0 < 16.0D) {
|
|
if (entityliving.isSensitiveToWater()) {
|
|
- entityliving.hurt(this.damageSources().indirectMagic(this, this.getOwner()), 1.0F);
|
|
+ affected.put(entityliving.getBukkitLivingEntity(), 1.0);
|
|
}
|
|
|
|
if (entityliving.isOnFire() && entityliving.isAlive()) {
|
|
- entityliving.extinguishFire();
|
|
+ extinguish.add(entityliving.getBukkitLivingEntity());
|
|
}
|
|
}
|
|
}
|
|
|
|
- List<Axolotl> list1 = this.level().getEntitiesOfClass(Axolotl.class, axisalignedbb);
|
|
- Iterator iterator1 = list1.iterator();
|
|
-
|
|
- while (iterator1.hasNext()) {
|
|
- Axolotl axolotl = (Axolotl) iterator1.next();
|
|
-
|
|
- axolotl.rehydrate();
|
|
+ io.papermc.paper.event.entity.WaterBottleSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callWaterBottleSplashEvent(
|
|
+ this, hitResult, affected, rehydrate, extinguish
|
|
+ );
|
|
+ if (!event.isCancelled()) {
|
|
+ for (LivingEntity affectedEntity : event.getToDamage()) {
|
|
+ ((CraftLivingEntity) affectedEntity).getHandle().hurt(this.damageSources().indirectMagic(this, this.getOwner()), 1.0F);
|
|
+ }
|
|
+ for (LivingEntity toExtinguish : event.getToExtinguish()) {
|
|
+ ((CraftLivingEntity) toExtinguish).getHandle().extinguishFire();
|
|
+ }
|
|
+ for (LivingEntity toRehydrate : event.getToRehydrate()) {
|
|
+ if (((CraftLivingEntity) toRehydrate).getHandle() instanceof Axolotl axolotl) {
|
|
+ axolotl.rehydrate();
|
|
+ }
|
|
+ }
|
|
+ // Paper end - Fix potions splash events
|
|
}
|
|
+ return !event.isCancelled(); // Paper - Fix potions splash events
|
|
|
|
}
|
|
|
|
- private void applySplash(Iterable<MobEffectInstance> iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition
|
|
+ private boolean applySplash(Iterable<MobEffectInstance> iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events
|
|
AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D);
|
|
List<net.minecraft.world.entity.LivingEntity> list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb);
|
|
Map<LivingEntity, Double> affected = new HashMap<LivingEntity, Double>(); // CraftBukkit
|
|
@@ -172,6 +193,7 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
|
|
if (d0 < 16.0D) {
|
|
double d1;
|
|
|
|
+ // Paper - diff on change, used when calling the splash event for water splash potions
|
|
if (entityliving == entity) {
|
|
d1 = 1.0D;
|
|
} else {
|
|
@@ -227,10 +249,11 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
|
|
}
|
|
}
|
|
}
|
|
+ return !event.isCancelled(); // Paper - Fix potions splash events
|
|
|
|
}
|
|
|
|
- private void makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition
|
|
+ private boolean makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition
|
|
AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ());
|
|
Entity entity = this.getOwner();
|
|
|
|
@@ -243,14 +266,16 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
|
|
entityareaeffectcloud.setWaitTime(10);
|
|
entityareaeffectcloud.setRadiusPerTick(-entityareaeffectcloud.getRadius() / (float) entityareaeffectcloud.getDuration());
|
|
entityareaeffectcloud.setPotionContents(potioncontents);
|
|
+ boolean noEffects = potioncontents.hasEffects(); // Paper - Fix potions splash events
|
|
// CraftBukkit start
|
|
org.bukkit.event.entity.LingeringPotionSplashEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callLingeringPotionSplashEvent(this, position, entityareaeffectcloud);
|
|
- if (!(event.isCancelled() || entityareaeffectcloud.isRemoved())) {
|
|
+ if (!(event.isCancelled() || entityareaeffectcloud.isRemoved() || (noEffects && !entityareaeffectcloud.potionContents.hasEffects()))) { // Paper - don't spawn area effect cloud if the effects were empty and not changed during the event handling
|
|
this.level().addFreshEntity(entityareaeffectcloud);
|
|
} else {
|
|
entityareaeffectcloud.discard(null); // CraftBukkit - add Bukkit remove cause
|
|
}
|
|
// CraftBukkit end
|
|
+ return !event.isCancelled(); // Paper - Fix potions splash events
|
|
}
|
|
|
|
public boolean isLingering() {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
index 36adcab02e97cae2d087bae74cc4ceaf3052a9f8..b93fa1ea73f0b218e6c6bed8bd36694e26544ab0 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
@@ -886,6 +886,32 @@ public class CraftEventFactory {
|
|
return event;
|
|
}
|
|
|
|
+ // Paper start - Fix potions splash events
|
|
+ public static io.papermc.paper.event.entity.WaterBottleSplashEvent callWaterBottleSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult hitResult, Map<LivingEntity, Double> affectedEntities, java.util.Set<LivingEntity> rehydrate, java.util.Set<LivingEntity> extinguish) {
|
|
+ ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity();
|
|
+
|
|
+ Block hitBlock = null;
|
|
+ BlockFace hitFace = null;
|
|
+ org.bukkit.entity.Entity hitEntity = null;
|
|
+
|
|
+ if (hitResult != null) {
|
|
+ if (hitResult.getType() == HitResult.Type.BLOCK) {
|
|
+ BlockHitResult blockHitResult = (BlockHitResult) hitResult;
|
|
+ hitBlock = CraftBlock.at(potion.level(), blockHitResult.getBlockPos());
|
|
+ hitFace = CraftBlock.notchToBlockFace(blockHitResult.getDirection());
|
|
+ } else if (hitResult.getType() == HitResult.Type.ENTITY) {
|
|
+ hitEntity = ((EntityHitResult) hitResult).getEntity().getBukkitEntity();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ io.papermc.paper.event.entity.WaterBottleSplashEvent event = new io.papermc.paper.event.entity.WaterBottleSplashEvent(
|
|
+ thrownPotion, hitEntity, hitBlock, hitFace, affectedEntities, rehydrate, extinguish
|
|
+ );
|
|
+ event.callEvent();
|
|
+ return event;
|
|
+ }
|
|
+ // Paper end - Fix potions splash events
|
|
+
|
|
/**
|
|
* BlockFadeEvent
|
|
*/
|