diff --git a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerAdvancementCriterionRevokeEvent.java b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerAdvancementCriterionRevokeEvent.java new file mode 100644 index 000000000000..4b7ddecdca6b --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerAdvancementCriterionRevokeEvent.java @@ -0,0 +1,78 @@ +package io.papermc.paper.event.player; + +import org.bukkit.advancement.Advancement; +import org.bukkit.advancement.AdvancementProgress; +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; + +/** + * An event fired when a {@link Player} has an advancement revoked. + * If cancelled the criteria will be granted. + */ +@NullMarked +public final class PlayerAdvancementCriterionRevokeEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Advancement advancement; + private final String criterion; + private final AdvancementProgress advancementProgress; + + private boolean cancelled; + + @ApiStatus.Internal + public PlayerAdvancementCriterionRevokeEvent(final Player player, final Advancement advancement, final String criterion) { + super(player); + this.advancement = advancement; + this.criterion = criterion; + this.advancementProgress = player.getAdvancementProgress(advancement); + } + + /** + * Get the advancement which has been affected. + * + * @return affected advancement + */ + public Advancement getAdvancement() { + return this.advancement; + } + + /** + * Get the criterion which has been revoked. + * + * @return revoked criterion + */ + public String getCriterion() { + return this.criterion; + } + + /** + * Gets the current AdvancementProgress. + * + * @return advancement progress + */ + public AdvancementProgress getAdvancementProgress() { + return this.advancementProgress; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerAdvancementRevokeEvent.java b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerAdvancementRevokeEvent.java new file mode 100644 index 000000000000..0c0cfe625bd2 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerAdvancementRevokeEvent.java @@ -0,0 +1,54 @@ +package io.papermc.paper.event.player; + +import org.bukkit.advancement.Advancement; +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; + +/** + * An event fired when a {@link Player} has an advancement revoked. + */ +@NullMarked +public final class PlayerAdvancementRevokeEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Advancement advancement; + + private boolean cancelled; + + @ApiStatus.Internal + public PlayerAdvancementRevokeEvent(final Player player, final Advancement advancement) { + super(player); + this.advancement = advancement; + } + + /** + * Get the advancement which has been revoked. + * + * @return revoked advancement + */ + public Advancement getAdvancement() { + return this.advancement; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/paper-server/patches/sources/net/minecraft/server/PlayerAdvancements.java.patch b/paper-server/patches/sources/net/minecraft/server/PlayerAdvancements.java.patch index 03e35ed5d3d2..ccaeb23aea8e 100644 --- a/paper-server/patches/sources/net/minecraft/server/PlayerAdvancements.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/PlayerAdvancements.java.patch @@ -58,6 +58,35 @@ } }); } +@@ -193,10 +_,28 @@ + boolean result = false; + AdvancementProgress progress = this.getOrStartProgress(advancement); + boolean wasDone = progress.isDone(); ++ + if (progress.revokeProgress(criterion)) { ++ // Paper start - Add PlayerAdvancementCriterionRevokeEvent ++ if (!new io.papermc.paper.event.player.PlayerAdvancementCriterionRevokeEvent(this.player.getBukkitEntity(), advancement.toBukkit(), criterion).callEvent()) { ++ progress.grantProgress(criterion); ++ return false; ++ } ++ // Paper end - Add PlayerAdvancementCriterionRevokeEvent ++ + this.registerListeners(advancement); + this.progressChanged.add(advancement); + result = true; ++ ++ if (wasDone && !progress.isDone()) { ++ // Paper start - Add PlayerAdvancementRevokeEvent ++ final io.papermc.paper.event.player.PlayerAdvancementRevokeEvent event = new io.papermc.paper.event.player.PlayerAdvancementRevokeEvent(this.player.getBukkitEntity(), advancement.toBukkit()); ++ if (!event.callEvent()) { ++ progress.grantProgress(criterion); ++ return false; ++ } ++ // Paper end - Add PlayerAdvancementRevokeEvent ++ } + } + + if (wasDone && !progress.isDone()) { @@ -239,7 +_,7 @@ public void flushDirty(final ServerPlayer player, final boolean showAdvancements) { if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !this.progressChanged.isEmpty()) {