diff --git a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerCriticalHitEntityEvent.java b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerCriticalHitEntityEvent.java new file mode 100644 index 000000000000..92634bff4df0 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerCriticalHitEntityEvent.java @@ -0,0 +1,74 @@ +package io.papermc.paper.event.player; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Event, that is fired when it is decided whether Player attack will be a critical hit or not. + * It will be fired cancelled when the hit will not be a critical hit. When cancelled, the hit won't be critical. + */ +@NullMarked +public class PlayerCriticalHitEntityEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Entity attacked; + private float multiplier; + + private boolean cancelled; + + @ApiStatus.Internal + public PlayerCriticalHitEntityEvent(final Player who, final Entity attacked, final float multiplier, final boolean critical) { + super(who); + this.attacked = attacked; + this.multiplier = multiplier; + this.cancelled = !critical; + } + + /** + * Gets the entity that was attacked in this event. + * + * @return entity that was attacked + */ + public Entity getAttacked() { + return attacked; + } + + /** + * Gets a multiplier by which the damage will be multiplied when the hit is critical. + * + * @return critical hit damage multiplier + */ + public float getMultiplier() { + return multiplier; + } + + /** + * Sets a multiplier by which the damage will be multiplied if the hit is critical + * + * @param multiplier critical hit damage multiplier + */ + public void setMultiplier(final float multiplier) { + this.multiplier = multiplier; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } +} diff --git a/paper-server/patches/features/0016-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0016-Moonrise-optimisation-patches.patch index c458f8f1436f..7dfc137ed386 100644 --- a/paper-server/patches/features/0016-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0016-Moonrise-optimisation-patches.patch @@ -27496,7 +27496,7 @@ index d1f235ebd835f58cf0c703c3a64d29825d98e183..080091efc19bc768bb9a660f366c42e8 } diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index f054ea710108e5017bc48fdda5f180a04f5b55e2..f44600604a7bf68c990cd74a1ac2d7900ff6e88e 100644 +index 0bb610f12e3ddda649ecb5ad62ffdc7bfd243223..19428343b37c9b739b3d28984d52e257f85f253f 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -178,7 +178,7 @@ import net.minecraft.world.scores.Team; @@ -27508,7 +27508,7 @@ index f054ea710108e5017bc48fdda5f180a04f5b55e2..f44600604a7bf68c990cd74a1ac2d790 private static final Logger LOGGER = LogUtils.getLogger(); private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32; private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10; -@@ -388,6 +388,36 @@ public class ServerPlayer extends Player { +@@ -395,6 +395,36 @@ public class ServerPlayer extends Player { public @Nullable String clientBrandName = null; // Paper - Brand support public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event diff --git a/paper-server/patches/features/0026-Optional-per-player-mob-spawns.patch b/paper-server/patches/features/0026-Optional-per-player-mob-spawns.patch index 8aa76f34aa7b..29b33f2300f5 100644 --- a/paper-server/patches/features/0026-Optional-per-player-mob-spawns.patch +++ b/paper-server/patches/features/0026-Optional-per-player-mob-spawns.patch @@ -78,10 +78,10 @@ index 87d4291a3944f706a694536da6de0f28c548ab8d..5576bf1d1d70ab7a010653d3207909b5 profiler.popPush("spawnAndTick"); boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 1fe212e8584c177b49e83f29b1a869b534914348..cd6b5176f34248f844f0e591875701bd08f455ce 100644 +index 02fb30a3adf92de0795aee213caf94a228b01ca0..67f6e40216e0be063a3cfb61427f095f7c74d785 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -368,6 +368,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -375,6 +375,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc public boolean queueHealthUpdatePacket; public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket; // Paper end - cancellable death event diff --git a/paper-server/patches/features/0027-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch b/paper-server/patches/features/0027-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch index 0e16d7da2da7..e098cf9369fa 100644 --- a/paper-server/patches/features/0027-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch +++ b/paper-server/patches/features/0027-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch @@ -60,10 +60,10 @@ index 5576bf1d1d70ab7a010653d3207909b5de867e70..6540b2d6a1062d883811ce240c49d30d spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); } else { diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index cd6b5176f34248f844f0e591875701bd08f455ce..f347ff8d863f4bcef46604c757de112cb3fe445c 100644 +index 67f6e40216e0be063a3cfb61427f095f7c74d785..3de65c4025be91d938a350c884975cb6edc234d3 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -372,6 +372,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -379,6 +379,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length; public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper end - Optional per player mob spawns diff --git a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch index 597b6bda1ab3..85cc5bc1fa04 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -308,16 +308,22 @@ flag1 = true; } else { flag1 = false; -@@ -1161,7 +_,9 @@ +@@ -1161,8 +_,14 @@ && !this.isPassenger() && target instanceof LivingEntity && !this.isSprinting(); + flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits ++ // Paper start - Critical hit API ++ io.papermc.paper.event.player.PlayerCriticalHitEntityEvent crit = new io.papermc.paper.event.player.PlayerCriticalHitEntityEvent((org.bukkit.entity.Player) this.getBukkitEntity(), target.getBukkitEntity(), 1.5F, flag2); ++ flag2 = crit.callEvent(); ++ // Paper end - Critical hit API if (flag2) { +- f *= 1.5F; + damageSource = damageSource.critical(); // Paper - critical damage API - f *= 1.5F; ++ f *= crit.getMultiplier(); // Paper - Critical hit API } + float f2 = f + f1; @@ -1188,17 +_,23 @@ if (target instanceof LivingEntity livingEntity1) { livingEntity1.knockback(