aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/1010-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/1010-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch')
-rw-r--r--patches/server/1010-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch251
1 files changed, 251 insertions, 0 deletions
diff --git a/patches/server/1010-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch b/patches/server/1010-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch
new file mode 100644
index 0000000000..14c24b80b2
--- /dev/null
+++ b/patches/server/1010-Add-PlayerTradeEvent-and-PlayerPurchaseEvent.patch
@@ -0,0 +1,251 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Thu, 2 Jul 2020 16:12:10 -0700
+Subject: [PATCH] Add PlayerTradeEvent and PlayerPurchaseEvent
+
+Co-authored-by: Alexander <[email protected]>
+
+diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
+index 9bc5a9592cabe087effc03e5347ea1d75794960b..4e6c2f6b2e54a4c126e9a026b9cad05ce835ad66 100644
+--- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
++++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
+@@ -137,11 +137,24 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa
+ @Override
+ public void overrideXp(int experience) {}
+
++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
++ @Override
++ public void processTrade(MerchantOffer recipe, @Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { // The MerchantRecipe passed in here is the one set by the PlayerPurchaseEvent
++ if (event == null || event.willIncreaseTradeUses()) {
++ recipe.increaseUses();
++ }
++ if (event == null || event.isRewardingExp()) {
++ this.rewardTradeXp(recipe);
++ }
++ this.notifyTrade(recipe);
++ }
++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
++
+ @Override
+ public void notifyTrade(MerchantOffer offer) {
+- offer.increaseUses();
++ // offer.increaseUses(); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ this.ambientSoundTime = -this.getAmbientSoundInterval();
+- this.rewardTradeXp(offer);
++ // this.rewardTradeXp(offer); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ if (this.tradingPlayer instanceof ServerPlayer) {
+ CriteriaTriggers.TRADE.trigger((ServerPlayer) this.tradingPlayer, this, offer.getResult());
+ }
+diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
+index eef0d3c59f0ce6e89033a5e228d31b63339c2773..48f634a7521d31c1e9dfd3cfc83139d428dbd37a 100644
+--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
++++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
+@@ -768,6 +768,14 @@ public abstract class AbstractContainerMenu {
+ public abstract boolean stillValid(Player player);
+
+ protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean fromLast) {
++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
++ return this.moveItemStackTo(stack, startIndex, endIndex, fromLast, false);
++ }
++ protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean fromLast, boolean isCheck) {
++ if (isCheck) {
++ stack = stack.copy();
++ }
++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
+ boolean flag1 = false;
+ int k = startIndex;
+
+@@ -790,18 +798,27 @@ public abstract class AbstractContainerMenu {
+
+ slot = (Slot) this.slots.get(k);
+ itemstack1 = slot.getItem();
++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; clone if only a check
++ if (isCheck) {
++ itemstack1 = itemstack1.copy();
++ }
++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
+ if (!itemstack1.isEmpty() && ItemStack.isSameItemSameTags(stack, itemstack1)) {
+ int l = itemstack1.getCount() + stack.getCount();
+
+ if (l <= stack.getMaxStackSize()) {
+ stack.setCount(0);
+ itemstack1.setCount(l);
++ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ slot.setChanged();
++ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ flag1 = true;
+ } else if (itemstack1.getCount() < stack.getMaxStackSize()) {
+ stack.shrink(stack.getMaxStackSize() - itemstack1.getCount());
+ itemstack1.setCount(stack.getMaxStackSize());
++ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ slot.setChanged();
++ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ flag1 = true;
+ }
+ }
+@@ -832,14 +849,33 @@ public abstract class AbstractContainerMenu {
+
+ slot = (Slot) this.slots.get(k);
+ itemstack1 = slot.getItem();
++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
++ if (isCheck) {
++ itemstack1 = itemstack1.copy();
++ }
++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
+ if (itemstack1.isEmpty() && slot.mayPlace(stack)) {
+ if (stack.getCount() > slot.getMaxStackSize()) {
++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
++ if (isCheck) {
++ stack.shrink(slot.getMaxStackSize());
++ } else {
++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
+ slot.setByPlayer(stack.split(slot.getMaxStackSize()));
++ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ } else {
++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
++ if (isCheck) {
++ stack.shrink(stack.getCount());
++ } else {
++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
+ slot.setByPlayer(stack.split(stack.getCount()));
++ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ }
+
++ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ slot.setChanged();
++ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ flag1 = true;
+ break;
+ }
+diff --git a/src/main/java/net/minecraft/world/inventory/MerchantMenu.java b/src/main/java/net/minecraft/world/inventory/MerchantMenu.java
+index 743a2adc465be5477d204185967265389d7102de..9c17c14de888ef3fbf4139cbad3889ece1d74aa1 100644
+--- a/src/main/java/net/minecraft/world/inventory/MerchantMenu.java
++++ b/src/main/java/net/minecraft/world/inventory/MerchantMenu.java
+@@ -134,12 +134,12 @@ public class MerchantMenu extends AbstractContainerMenu {
+
+ itemstack = itemstack1.copy();
+ if (slot == 2) {
+- if (!this.moveItemStackTo(itemstack1, 3, 39, true)) {
++ if (!this.moveItemStackTo(itemstack1, 3, 39, true, true)) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ return ItemStack.EMPTY;
+ }
+
+- slot1.onQuickCraft(itemstack1, itemstack);
+- this.playTradeSound();
++ // slot1.onQuickCraft(itemstack1, itemstack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved to after the non-check moveItemStackTo call
++ // this.playTradeSound();
+ } else if (slot != 0 && slot != 1) {
+ if (slot >= 3 && slot < 30) {
+ if (!this.moveItemStackTo(itemstack1, 30, 39, false)) {
+@@ -152,6 +152,7 @@ public class MerchantMenu extends AbstractContainerMenu {
+ return ItemStack.EMPTY;
+ }
+
++ if (slot != 2) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved down for slot 2
+ if (itemstack1.isEmpty()) {
+ slot1.setByPlayer(ItemStack.EMPTY);
+ } else {
+@@ -163,6 +164,21 @@ public class MerchantMenu extends AbstractContainerMenu {
+ }
+
+ slot1.onTake(player, itemstack1);
++ } // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; handle slot 2
++ if (slot == 2) { // is merchant result slot
++ slot1.onTake(player, itemstack1);
++ if (itemstack1.isEmpty()) {
++ slot1.set(ItemStack.EMPTY);
++ return ItemStack.EMPTY;
++ }
++
++ this.moveItemStackTo(itemstack1, 3, 39, true, false); // This should always succeed because it's checked above
++
++ slot1.onQuickCraft(itemstack1, itemstack);
++ this.playTradeSound();
++ slot1.set(ItemStack.EMPTY); // itemstack1 should ALWAYS be empty
++ }
++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
+ }
+
+ return itemstack;
+diff --git a/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java b/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java
+index e49bbb803399ef696665c5844a18b55a551654f6..23c1ba476869c9846a63138a8a11154bfd9379a2 100644
+--- a/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java
++++ b/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java
+@@ -47,13 +47,32 @@ public class MerchantResultSlot extends Slot {
+
+ @Override
+ public void onTake(Player player, ItemStack stack) {
+- this.checkTakeAchievements(stack);
++ // this.checkTakeAchievements(stack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; move to after event is called and not cancelled
+ MerchantOffer merchantOffer = this.slots.getActiveOffer();
++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
++ io.papermc.paper.event.player.PlayerPurchaseEvent event = null;
++ if (merchantOffer != null && player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
++ if (this.merchant instanceof net.minecraft.world.entity.npc.AbstractVillager abstractVillager) {
++ event = new io.papermc.paper.event.player.PlayerTradeEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.AbstractVillager) abstractVillager.getBukkitEntity(), merchantOffer.asBukkit(), true, true);
++ } else if (this.merchant instanceof org.bukkit.craftbukkit.inventory.CraftMerchantCustom.MinecraftMerchant) {
++ event = new io.papermc.paper.event.player.PlayerPurchaseEvent(serverPlayer.getBukkitEntity(), merchantOffer.asBukkit(), false, true);
++ }
++ if (event != null) {
++ if (!event.callEvent()) {
++ stack.setCount(0);
++ event.getPlayer().updateInventory();
++ return;
++ }
++ merchantOffer = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getTrade()).toMinecraft();
++ }
++ }
++ this.checkTakeAchievements(stack);
++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
+ if (merchantOffer != null) {
+ ItemStack itemStack = this.slots.getItem(0);
+ ItemStack itemStack2 = this.slots.getItem(1);
+ if (merchantOffer.take(itemStack, itemStack2) || merchantOffer.take(itemStack2, itemStack)) {
+- this.merchant.notifyTrade(merchantOffer);
++ this.merchant.processTrade(merchantOffer, event); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
+ player.awardStat(Stats.TRADED_WITH_VILLAGER);
+ this.slots.setItem(0, itemStack);
+ this.slots.setItem(1, itemStack2);
+diff --git a/src/main/java/net/minecraft/world/item/trading/Merchant.java b/src/main/java/net/minecraft/world/item/trading/Merchant.java
+index 5a350948a4735902f5c612592bc9d100445a0c8a..716b30dcd7e63c66736c448dd136c9f74dc7fe43 100644
+--- a/src/main/java/net/minecraft/world/item/trading/Merchant.java
++++ b/src/main/java/net/minecraft/world/item/trading/Merchant.java
+@@ -20,6 +20,7 @@ public interface Merchant {
+
+ void overrideOffers(MerchantOffers offers);
+
++ default void processTrade(MerchantOffer merchantRecipe, @Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { this.notifyTrade(merchantRecipe); } // Paper
+ void notifyTrade(MerchantOffer offer);
+
+ void notifyTradeUpdated(ItemStack stack);
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
+index adf22ce4f0bcd3bd57dc2030c6c92d3df96566e3..e33ddcd967a427abfda9e6692338da4996a81c6c 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
+@@ -74,10 +74,25 @@ public class CraftMerchantCustom extends CraftMerchant {
+ return this.trades;
+ }
+
++ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
++ @Override
++ public void processTrade(MerchantOffer merchantRecipe, @javax.annotation.Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { // The MerchantRecipe passed in here is the one set by the PlayerPurchaseEvent
++ /** Based on {@link net.minecraft.world.entity.npc.AbstractVillager#processTrade(MerchantOffer, io.papermc.paper.event.player.PlayerPurchaseEvent)} */
++ if (getTradingPlayer() instanceof net.minecraft.server.level.ServerPlayer) {
++ if (event == null || event.willIncreaseTradeUses()) {
++ merchantRecipe.increaseUses();
++ }
++ if (event == null || event.isRewardingExp()) {
++ this.tradingPlayer.level().addFreshEntity(new net.minecraft.world.entity.ExperienceOrb(this.tradingPlayer.level(), this.tradingPlayer.getX(), this.tradingPlayer.getY(), this.tradingPlayer.getZ(), merchantRecipe.getXp(), org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.tradingPlayer, null));
++ }
++ }
++ this.notifyTrade(merchantRecipe);
++ }
++ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
+ @Override
+ public void notifyTrade(MerchantOffer offer) {
+ // increase recipe's uses
+- offer.increaseUses();
++ // offer.increaseUses(); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; handled above in processTrade
+ }
+
+ @Override