2021-09-23 06:10:35 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 2 Jul 2020 16:12:10 -0700
Subject: [PATCH] Add PlayerTradeEvent and PlayerPurchaseEvent
Co-authored-by: Alexander <protonull@protonmail.com>
diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
2024-10-24 15:25:36 +02:00
index 39cb40b077e9c07471437d5bec16ba9a7e6bce52..5f656fc726a1dc5f42657095a2f2b7cf85b92d7c 100644
2021-09-23 06:10:35 +02:00
--- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java
2024-09-15 21:39:53 +02:00
@@ -141,11 +141,24 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa
2021-09-23 06:10:35 +02:00
@Override
public void overrideXp(int experience) {}
2024-01-20 12:50:16 +01:00
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
+ @Override
2021-12-05 04:39:52 +01:00
+ 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()) {
2021-09-23 06:10:35 +02:00
+ recipe.increaseUses();
+ }
2021-12-05 04:39:52 +01:00
+ if (event == null || event.isRewardingExp()) {
2021-09-23 06:10:35 +02:00
+ this.rewardTradeXp(recipe);
+ }
+ this.notifyTrade(recipe);
+ }
2024-01-20 12:50:16 +01:00
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
+
@Override
public void notifyTrade(MerchantOffer offer) {
- offer.increaseUses();
2024-01-20 12:50:16 +01:00
+ // offer.increaseUses(); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
this.ambientSoundTime = -this.getAmbientSoundInterval();
- this.rewardTradeXp(offer);
2024-01-20 12:50:16 +01:00
+ // this.rewardTradeXp(offer); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
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
2024-10-24 15:25:36 +02:00
index 85caec29a705f216eff8a5ae11f250697891a05c..78d0ff45c016e900d87010e8b26b0bb10e63f445 100644
2021-09-23 06:10:35 +02:00
--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
2024-10-24 15:25:36 +02:00
@@ -831,6 +831,14 @@ public abstract class AbstractContainerMenu {
2021-09-23 06:10:35 +02:00
public abstract boolean stillValid(Player player);
protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean fromLast) {
2024-01-20 12:50:16 +01:00
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
+ 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();
+ }
2024-01-20 12:50:16 +01:00
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
boolean flag1 = false;
int k = startIndex;
2024-10-24 15:25:36 +02:00
@@ -854,6 +862,11 @@ public abstract class AbstractContainerMenu {
2021-09-23 06:10:35 +02:00
slot = (Slot) this.slots.get(k);
itemstack1 = slot.getItem();
2024-01-20 12:50:16 +01:00
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; clone if only a check
2021-09-23 06:10:35 +02:00
+ if (isCheck) {
+ itemstack1 = itemstack1.copy();
+ }
2024-01-20 12:50:16 +01:00
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
2024-04-25 02:36:24 +02:00
if (!itemstack1.isEmpty() && ItemStack.isSameItemSameComponents(stack, itemstack1)) {
l = itemstack1.getCount() + stack.getCount();
int i1 = slot.getMaxStackSize(itemstack1);
2024-10-24 15:25:36 +02:00
@@ -861,12 +874,16 @@ public abstract class AbstractContainerMenu {
2024-04-25 02:36:24 +02:00
if (l <= i1) {
2021-09-23 06:10:35 +02:00
stack.setCount(0);
itemstack1.setCount(l);
2024-01-20 12:50:16 +01:00
+ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
slot.setChanged();
2024-01-20 12:50:16 +01:00
+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
flag1 = true;
2024-04-25 02:36:24 +02:00
} else if (itemstack1.getCount() < i1) {
stack.shrink(i1 - itemstack1.getCount());
itemstack1.setCount(i1);
2024-01-20 12:50:16 +01:00
+ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
slot.setChanged();
2024-01-20 12:50:16 +01:00
+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
flag1 = true;
}
}
2024-10-24 15:25:36 +02:00
@@ -897,10 +914,21 @@ public abstract class AbstractContainerMenu {
2021-09-23 06:10:35 +02:00
slot = (Slot) this.slots.get(k);
itemstack1 = slot.getItem();
2024-01-20 12:50:16 +01:00
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
+ if (isCheck) {
+ itemstack1 = itemstack1.copy();
+ }
2024-01-20 12:50:16 +01:00
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
if (itemstack1.isEmpty() && slot.mayPlace(stack)) {
2024-04-25 02:36:24 +02:00
l = slot.getMaxStackSize(stack);
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
+ if (isCheck) {
+ stack.shrink(Math.min(stack.getCount(), l));
+ } else {
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
slot.setByPlayer(stack.split(Math.min(stack.getCount(), l)));
2021-09-23 06:10:35 +02:00
slot.setChanged();
2024-01-20 12:50:16 +01:00
+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
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
2024-10-24 15:25:36 +02:00
index 90560dfad263d42432dc034a29930e6bab953b9a..6a529b5e289c416c0ebdc0260086ec039777aa40 100644
2021-09-23 06:10:35 +02:00
--- a/src/main/java/net/minecraft/world/inventory/MerchantMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/MerchantMenu.java
2024-10-24 15:25:36 +02:00
@@ -123,12 +123,12 @@ public class MerchantMenu extends AbstractContainerMenu {
2021-09-23 06:10:35 +02:00
itemstack = itemstack1.copy();
2022-12-07 21:16:54 +01:00
if (slot == 2) {
2021-09-23 06:10:35 +02:00
- if (!this.moveItemStackTo(itemstack1, 3, 39, true)) {
2024-01-20 12:50:16 +01:00
+ if (!this.moveItemStackTo(itemstack1, 3, 39, true, true)) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
return ItemStack.EMPTY;
}
2022-12-07 21:16:54 +01:00
- slot1.onQuickCraft(itemstack1, itemstack);
2021-09-23 06:10:35 +02:00
- this.playTradeSound();
2024-01-20 12:50:16 +01:00
+ // slot1.onQuickCraft(itemstack1, itemstack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved to after the non-check moveItemStackTo call
2021-09-23 06:10:35 +02:00
+ // this.playTradeSound();
2022-12-07 21:16:54 +01:00
} else if (slot != 0 && slot != 1) {
if (slot >= 3 && slot < 30) {
2021-09-23 06:10:35 +02:00
if (!this.moveItemStackTo(itemstack1, 30, 39, false)) {
2024-10-24 15:25:36 +02:00
@@ -141,6 +141,7 @@ public class MerchantMenu extends AbstractContainerMenu {
2021-09-23 06:10:35 +02:00
return ItemStack.EMPTY;
}
2024-01-20 12:50:16 +01:00
+ if (slot != 2) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved down for slot 2
2021-09-23 06:10:35 +02:00
if (itemstack1.isEmpty()) {
2023-03-14 21:25:13 +01:00
slot1.setByPlayer(ItemStack.EMPTY);
2021-09-23 06:10:35 +02:00
} else {
2024-10-24 15:25:36 +02:00
@@ -152,6 +153,21 @@ public class MerchantMenu extends AbstractContainerMenu {
2021-09-23 06:10:35 +02:00
}
2022-12-07 21:16:54 +01:00
slot1.onTake(player, itemstack1);
2024-01-20 12:50:16 +01:00
+ } // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; handle slot 2
2022-12-07 21:16:54 +01:00
+ if (slot == 2) { // is merchant result slot
+ slot1.onTake(player, itemstack1);
2021-09-23 06:10:35 +02:00
+ if (itemstack1.isEmpty()) {
2022-12-07 21:16:54 +01:00
+ slot1.set(ItemStack.EMPTY);
2021-09-23 06:10:35 +02:00
+ return ItemStack.EMPTY;
+ }
+
+ this.moveItemStackTo(itemstack1, 3, 39, true, false); // This should always succeed because it's checked above
+
2022-12-07 21:16:54 +01:00
+ slot1.onQuickCraft(itemstack1, itemstack);
2021-09-23 06:10:35 +02:00
+ this.playTradeSound();
2022-12-07 21:16:54 +01:00
+ slot1.set(ItemStack.EMPTY); // itemstack1 should ALWAYS be empty
2021-09-23 06:10:35 +02:00
+ }
2024-01-20 12:50:16 +01:00
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
}
return itemstack;
diff --git a/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java b/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java
2024-04-12 21:14:06 +02:00
index 26227033613a641a9d5a6f29356b19e54753b3f1..c2376538215604210d08acd33e8e5fdc8a35c7d3 100644
2021-09-23 06:10:35 +02:00
--- a/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java
+++ b/src/main/java/net/minecraft/world/inventory/MerchantResultSlot.java
2021-12-05 04:39:52 +01:00
@@ -47,13 +47,32 @@ public class MerchantResultSlot extends Slot {
2021-09-23 06:10:35 +02:00
@Override
public void onTake(Player player, ItemStack stack) {
- this.checkTakeAchievements(stack);
2024-01-20 12:50:16 +01:00
+ // this.checkTakeAchievements(stack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; move to after event is called and not cancelled
2021-09-23 06:10:35 +02:00
MerchantOffer merchantOffer = this.slots.getActiveOffer();
2024-01-20 12:50:16 +01:00
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
+ io.papermc.paper.event.player.PlayerPurchaseEvent event = null;
2021-12-05 04:39:52 +01:00
+ 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);
2021-12-05 04:00:10 +01:00
+ }
+ if (event != null) {
+ if (!event.callEvent()) {
+ stack.setCount(0);
+ event.getPlayer().updateInventory();
+ return;
+ }
+ merchantOffer = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getTrade()).toMinecraft();
2021-09-23 06:10:35 +02:00
+ }
+ }
2021-12-05 04:39:52 +01:00
+ this.checkTakeAchievements(stack);
2024-01-20 12:50:16 +01:00
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
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);
2024-01-20 12:50:16 +01:00
+ this.merchant.processTrade(merchantOffer, event); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
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
2023-09-22 06:40:51 +02:00
index 5a350948a4735902f5c612592bc9d100445a0c8a..716b30dcd7e63c66736c448dd136c9f74dc7fe43 100644
2021-09-23 06:10:35 +02:00
--- a/src/main/java/net/minecraft/world/item/trading/Merchant.java
+++ b/src/main/java/net/minecraft/world/item/trading/Merchant.java
2021-11-24 18:37:07 +01:00
@@ -20,6 +20,7 @@ public interface Merchant {
2021-09-23 06:10:35 +02:00
void overrideOffers(MerchantOffers offers);
2021-12-05 04:39:52 +01:00
+ default void processTrade(MerchantOffer merchantRecipe, @Nullable io.papermc.paper.event.player.PlayerPurchaseEvent event) { this.notifyTrade(merchantRecipe); } // Paper
2021-09-23 06:10:35 +02:00
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
2024-09-15 21:39:53 +02:00
index ef47eb9a321a7b082413d3986d3d394afb899610..54debe9da0a26aea02c964fdc7efb372e07974c0 100644
2021-09-23 06:10:35 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
2024-09-15 21:39:53 +02:00
@@ -76,10 +76,25 @@ public class CraftMerchantCustom implements CraftMerchant {
2021-09-23 06:10:35 +02:00
return this.trades;
}
2024-01-20 12:50:16 +01:00
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
+ @Override
2021-12-05 04:39:52 +01:00
+ 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
2021-09-23 06:10:35 +02:00
+ /** 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) {
2021-12-05 04:39:52 +01:00
+ if (event == null || event.willIncreaseTradeUses()) {
2021-09-23 06:10:35 +02:00
+ merchantRecipe.increaseUses();
+ }
2021-12-05 04:39:52 +01:00
+ if (event == null || event.isRewardingExp()) {
2023-06-08 22:56:13 +02:00
+ 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));
2021-09-23 06:10:35 +02:00
+ }
+ }
+ this.notifyTrade(merchantRecipe);
+ }
2024-01-20 12:50:16 +01:00
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
2021-09-23 06:10:35 +02:00
@Override
public void notifyTrade(MerchantOffer offer) {
// increase recipe's uses
- offer.increaseUses();
2024-01-20 12:50:16 +01:00
+ // offer.increaseUses(); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; handled above in processTrade
2021-09-23 06:10:35 +02:00
}
@Override