From 0b154b18523e8809cc54ad6c33b60aed11917a37 Mon Sep 17 00:00:00 2001 From: Lukas Hennig Date: Mon, 21 Nov 2016 15:29:36 +1100 Subject: [PATCH] SPIGOT-2272: Add API for virtual Merchants --- nms-patches/InventoryMerchant.patch | 4 +- .../org/bukkit/craftbukkit/CraftServer.java | 7 ++ .../craftbukkit/entity/CraftHumanEntity.java | 34 ++++++-- .../craftbukkit/entity/CraftVillager.java | 41 ++++------ .../craftbukkit/inventory/CraftMerchant.java | 80 +++++++++++++++++++ .../inventory/CraftMerchantCustom.java | 74 +++++++++++++++++ .../inventory/CraftMerchantRecipe.java | 4 +- 7 files changed, 207 insertions(+), 37 deletions(-) create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java diff --git a/nms-patches/InventoryMerchant.patch b/nms-patches/InventoryMerchant.patch index 58445a1259..8c56630707 100644 --- a/nms-patches/InventoryMerchant.patch +++ b/nms-patches/InventoryMerchant.patch @@ -43,12 +43,12 @@ + } + + public org.bukkit.inventory.InventoryHolder getOwner() { -+ return (CraftVillager) ((EntityVillager) this.merchant).getBukkitEntity(); ++ return (merchant instanceof EntityVillager) ? (CraftVillager) ((EntityVillager) this.merchant).getBukkitEntity() : null; + } + + @Override + public Location getLocation() { -+ return ((EntityVillager) this.merchant).getBukkitEntity().getLocation(); ++ return (merchant instanceof EntityVillager) ? ((EntityVillager) this.merchant).getBukkitEntity().getLocation() : null; + } + // CraftBukkit end + diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index fe677569f4..b3de034a68 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -59,6 +59,7 @@ import org.bukkit.craftbukkit.help.SimpleHelpMap; import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe; import org.bukkit.craftbukkit.inventory.CraftInventoryCustom; import org.bukkit.craftbukkit.inventory.CraftItemFactory; +import org.bukkit.craftbukkit.inventory.CraftMerchantCustom; import org.bukkit.craftbukkit.inventory.CraftRecipe; import org.bukkit.craftbukkit.inventory.CraftShapedRecipe; import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe; @@ -85,6 +86,7 @@ import org.bukkit.generator.ChunkGenerator; import org.bukkit.help.HelpMap; import org.bukkit.inventory.FurnaceRecipe; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Merchant; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.Recipe; @@ -1480,6 +1482,11 @@ public final class CraftServer implements Server { return new CraftInventoryCustom(owner, size, title); } + @Override + public Merchant createMerchant(String title) { + return new CraftMerchantCustom(title); + } + @Override public HelpMap getHelpMap() { return helpMap; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java index 4249512899..75d8246912 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -8,8 +8,10 @@ import net.minecraft.server.*; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.inventory.MainHand; +import org.bukkit.inventory.Merchant; import org.bukkit.Material; import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Villager; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; @@ -22,8 +24,8 @@ import org.bukkit.craftbukkit.inventory.CraftInventory; import org.bukkit.craftbukkit.inventory.CraftInventoryPlayer; import org.bukkit.craftbukkit.inventory.CraftInventoryView; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.inventory.CraftMerchant; import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.entity.Villager; import org.bukkit.inventory.EntityEquipment; import org.bukkit.permissions.PermissibleBase; import org.bukkit.permissions.Permission; @@ -357,16 +359,32 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { @Override public InventoryView openMerchant(Villager villager, boolean force) { Preconditions.checkNotNull(villager, "villager cannot be null"); - if (!force && villager.isTrading()) { + + return this.openMerchant(villager, force); + } + + @Override + public InventoryView openMerchant(Merchant merchant, boolean force) { + Preconditions.checkNotNull(merchant, "merchant cannot be null"); + + if (!force && merchant.isTrading()) { return null; - } else if (villager.isTrading()) { - // we're not supposed to have multiple people using the same villager, so we have to close it. - villager.getTrader().closeInventory(); + } else if (merchant.isTrading()) { + // we're not supposed to have multiple people using the same merchant, so we have to close it. + merchant.getTrader().closeInventory(); } - EntityVillager ev = ((CraftVillager) villager).getHandle(); - ev.setTradingPlayer(this.getHandle()); - this.getHandle().openTrade(ev); + IMerchant mcMerchant; + if (merchant instanceof CraftVillager) { + mcMerchant = ((CraftVillager) merchant).getHandle(); + } else if (merchant instanceof CraftMerchant) { + mcMerchant = ((CraftMerchant) merchant).getMerchant(); + } else { + throw new IllegalArgumentException("Can't open merchant " + merchant.toString()); + } + + mcMerchant.setTradingPlayer(this.getHandle()); + this.getHandle().openTrade(mcMerchant); return this.getHandle().activeContainer.getBukkitView(); } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java index 5fa6c4d5e4..6f50eb9866 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java @@ -1,16 +1,11 @@ package org.bukkit.craftbukkit.entity; -import com.google.common.base.Function; -import com.google.common.collect.Lists; -import java.util.Collections; import java.util.List; -import net.minecraft.server.EntityHuman; import net.minecraft.server.EntityVillager; -import net.minecraft.server.MerchantRecipeList; import org.apache.commons.lang.Validate; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.inventory.CraftInventory; -import org.bukkit.craftbukkit.inventory.CraftMerchantRecipe; +import org.bukkit.craftbukkit.inventory.CraftMerchant; import org.bukkit.entity.EntityType; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Villager; @@ -20,6 +15,8 @@ import org.bukkit.inventory.MerchantRecipe; public class CraftVillager extends CraftAgeable implements Villager, InventoryHolder { + private CraftMerchant merchant; + public CraftVillager(CraftServer server, EntityVillager entity) { super(server, entity); } @@ -53,38 +50,33 @@ public class CraftVillager extends CraftAgeable implements Villager, InventoryHo return new CraftInventory(getHandle().inventory); } - @Override - public List getRecipes() { - return Collections.unmodifiableList(Lists.transform(getHandle().getOffers(null), new Function() { - @Override - public MerchantRecipe apply(net.minecraft.server.MerchantRecipe recipe) { - return recipe.asBukkit(); - } - })); + private CraftMerchant getMerchant() { + return (merchant == null) ? merchant = new CraftMerchant(getHandle()) : merchant; } @Override - public void setRecipes(List list) { - MerchantRecipeList recipes = getHandle().getOffers(null); - recipes.clear(); - for (MerchantRecipe m : list) { - recipes.add(CraftMerchantRecipe.fromBukkit(m).toMinecraft()); - } + public List getRecipes() { + return getMerchant().getRecipes(); + } + + @Override + public void setRecipes(List recipes) { + this.getMerchant().setRecipes(recipes); } @Override public MerchantRecipe getRecipe(int i) { - return getHandle().getOffers(null).get(i).asBukkit(); + return getMerchant().getRecipe(i); } @Override public void setRecipe(int i, MerchantRecipe merchantRecipe) { - getHandle().getOffers(null).set(i, CraftMerchantRecipe.fromBukkit(merchantRecipe).toMinecraft()); + getMerchant().setRecipe(i, merchantRecipe); } @Override public int getRecipeCount() { - return getHandle().getOffers(null).size(); + return getMerchant().getRecipeCount(); } @Override @@ -94,8 +86,7 @@ public class CraftVillager extends CraftAgeable implements Villager, InventoryHo @Override public HumanEntity getTrader() { - EntityHuman eh = getHandle().getTrader(); - return eh == null ? null : eh.getBukkitEntity(); + return getMerchant().getTrader(); } @Override diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java new file mode 100644 index 0000000000..7569b29dc7 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchant.java @@ -0,0 +1,80 @@ +package org.bukkit.craftbukkit.inventory; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import java.util.Collections; +import java.util.List; +import net.minecraft.server.EntityHuman; +import net.minecraft.server.IMerchant; +import net.minecraft.server.MerchantRecipeList; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.Merchant; +import org.bukkit.inventory.MerchantRecipe; + +public class CraftMerchant implements Merchant { + + protected final IMerchant merchant; + + public CraftMerchant(IMerchant merchant) { + this.merchant = merchant; + } + + public IMerchant getMerchant() { + return merchant; + } + + @Override + public List getRecipes() { + return Collections.unmodifiableList(Lists.transform(merchant.getOffers(null), new Function() { + @Override + public MerchantRecipe apply(net.minecraft.server.MerchantRecipe recipe) { + return recipe.asBukkit(); + } + })); + } + + @Override + public void setRecipes(List recipes) { + MerchantRecipeList recipesList = merchant.getOffers(null); + recipesList.clear(); + for (MerchantRecipe recipe : recipes) { + recipesList.add(CraftMerchantRecipe.fromBukkit(recipe).toMinecraft()); + } + } + + @Override + public MerchantRecipe getRecipe(int i) { + return merchant.getOffers(null).get(i).asBukkit(); + } + + @Override + public void setRecipe(int i, MerchantRecipe merchantRecipe) { + merchant.getOffers(null).set(i, CraftMerchantRecipe.fromBukkit(merchantRecipe).toMinecraft()); + } + + @Override + public int getRecipeCount() { + return merchant.getOffers(null).size(); + } + + @Override + public boolean isTrading() { + return getTrader() != null; + } + + @Override + public HumanEntity getTrader() { + EntityHuman eh = merchant.getTrader(); + return eh == null ? null : eh.getBukkitEntity(); + } + + @Override + public int hashCode() { + return merchant.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + return obj instanceof CraftMerchant && ((CraftMerchant) obj).merchant.equals(this.merchant); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java new file mode 100644 index 0000000000..fe111454f4 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java @@ -0,0 +1,74 @@ +package org.bukkit.craftbukkit.inventory; + +import net.minecraft.server.BlockPosition; +import net.minecraft.server.EntityHuman; +import net.minecraft.server.IChatBaseComponent; +import net.minecraft.server.IMerchant; +import net.minecraft.server.ItemStack; +import net.minecraft.server.MerchantRecipe; +import net.minecraft.server.MerchantRecipeList; +import net.minecraft.server.World; +import org.bukkit.craftbukkit.util.CraftChatMessage; + +public class CraftMerchantCustom extends CraftMerchant { + + public CraftMerchantCustom(String title) { + super(new MinecraftMerchant(title)); + } + + @Override + public String toString() { + return "CraftMerchantCustom"; + } + + private static class MinecraftMerchant implements IMerchant { + + private final String title; + private final MerchantRecipeList trades = new MerchantRecipeList(); + private EntityHuman tradingPlayer; + + public MinecraftMerchant(String title) { + this.title = title; + } + + @Override + public void setTradingPlayer(EntityHuman entityhuman) { + this.tradingPlayer = entityhuman; + } + + @Override + public EntityHuman getTrader() { + return this.tradingPlayer; + } + + @Override + public MerchantRecipeList getOffers(EntityHuman entityhuman) { + return this.trades; + } + + @Override + public void a(MerchantRecipe merchantrecipe) { + // increase recipe's uses + merchantrecipe.g(); // PAIL: rename + } + + @Override + public void a(ItemStack itemstack) { + } + + @Override + public IChatBaseComponent getScoreboardDisplayName() { + return CraftChatMessage.fromString(title)[0]; + } + + @Override + public World t_() { + return null; + } + + @Override + public BlockPosition u_() { + return null; + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java index 9bf5f2f3b8..2c51fd8b95 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantRecipe.java @@ -19,8 +19,8 @@ public class CraftMerchantRecipe extends MerchantRecipe { public CraftMerchantRecipe(ItemStack result, int uses, int maxUses, boolean experienceReward) { super(result, uses, maxUses, experienceReward); this.handle = new net.minecraft.server.MerchantRecipe( - null, - null, + net.minecraft.server.ItemStack.a, + net.minecraft.server.ItemStack.a, CraftItemStack.asNMSCopy(result), uses, maxUses,