From 28fbe45695f49aa806e688ff79a976ada3cdc984 Mon Sep 17 00:00:00 2001 From: Josh Roy <10731363+jroy@users.noreply.github.com> Date: Thu, 13 Apr 2023 02:22:47 -0400 Subject: [PATCH 1/2] Add Item group for sell sign --- .../com/earth2me/essentials/Essentials.java | 6 +++ .../earth2me/essentials/ItemGroupQuery.java | 36 +++++++++++++ .../com/earth2me/essentials/ItemGroups.java | 48 +++++++++++++++++ .../java/com/earth2me/essentials/Trade.java | 37 ++++++++++--- .../essentials/commands/Commandtop.java | 4 +- .../essentials/craftbukkit/Inventories.java | 54 +++++++++++++++++++ .../essentials/signs/EssentialsSign.java | 12 +++++ .../earth2me/essentials/signs/SignSell.java | 14 ++++- .../main/java/net/ess3/api/IItemGroups.java | 26 +++++++++ Essentials/src/main/resources/groups.yml | 12 +++++ 10 files changed, 238 insertions(+), 11 deletions(-) create mode 100644 Essentials/src/main/java/com/earth2me/essentials/ItemGroupQuery.java create mode 100644 Essentials/src/main/java/com/earth2me/essentials/ItemGroups.java create mode 100644 Essentials/src/main/java/net/ess3/api/IItemGroups.java create mode 100644 Essentials/src/main/resources/groups.yml diff --git a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java index 287446cd324..a191e195cb3 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java @@ -191,6 +191,8 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { EconomyLayers.init(); } + private ItemGroups itemGroups; + public Essentials() { } @@ -358,6 +360,10 @@ public void onEnable() { confList.add(jails); execTimer.mark("Init(Jails)"); + itemGroups = new ItemGroups(this); + confList.add(itemGroups); + execTimer.mark("Init(ItemGroups)"); + EconomyLayers.onEnable(this); //Spawner item provider only uses one but it's here for legacy... diff --git a/Essentials/src/main/java/com/earth2me/essentials/ItemGroupQuery.java b/Essentials/src/main/java/com/earth2me/essentials/ItemGroupQuery.java new file mode 100644 index 00000000000..ac20f61e9f9 --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/ItemGroupQuery.java @@ -0,0 +1,36 @@ +package com.earth2me.essentials; + +import net.ess3.api.IEssentials; +import org.bukkit.Material; + +public class ItemGroupQuery { + + private final String itemGroup; + private final int amount; + + public ItemGroupQuery(String group, int quantity) { + this.itemGroup = group; + this.amount = quantity; + } + + public boolean contains(IEssentials ess, Material item){ + final ItemGroups groupsConfig = new ItemGroups(ess); + return groupsConfig.getItemGroup(itemGroup).contains(item); + } + + public String getItemGroup() { + return itemGroup; + } + + public int getAmount() { + return amount; + } + + @Override + public String toString() { + return "ItemGroupQuery{" + + "itemGroup='" + itemGroup + '\'' + + ", quantity=" + amount + + '}'; + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/ItemGroups.java b/Essentials/src/main/java/com/earth2me/essentials/ItemGroups.java new file mode 100644 index 00000000000..193ce9220f3 --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/ItemGroups.java @@ -0,0 +1,48 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.config.EssentialsConfiguration; +import net.ess3.api.IEssentials; +import net.ess3.api.IItemGroups; +import org.bukkit.Material; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class ItemGroups implements IItemGroups { + + private final EssentialsConfiguration config; + private final Map> itemGroups = new HashMap<>(); + + public ItemGroups(final IEssentials ess) { + this.config = new EssentialsConfiguration(new File(ess.getDataFolder(), "groups.yml")); + reloadConfig(); + } + + @Override + public void reloadConfig() { + synchronized (itemGroups) { + config.load(); + itemGroups.clear(); + + for (String id : config.getKeys()) { + final List list = config.getList(id, String.class); + itemGroups.put(id, list.stream().map(Material::matchMaterial).collect(Collectors.toList())); + } + } + } + + @Override + public List getItemGroup(String group) { + return itemGroups.getOrDefault(group, Collections.emptyList()); + } + + @Override + public Set getItemGroups() { + return itemGroups.keySet(); + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/Trade.java b/Essentials/src/main/java/com/earth2me/essentials/Trade.java index c82bf51cbb6..c28d6835763 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Trade.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Trade.java @@ -31,39 +31,45 @@ public class Trade { private final transient Trade fallbackTrade; private final transient BigDecimal money; private final transient ItemStack itemStack; + private final transient ItemGroupQuery itemGroupQuery; private final transient Integer exp; private final transient IEssentials ess; public Trade(final String command, final IEssentials ess) { - this(command, null, null, null, null, ess); + this(command, null, null, null, null, null, ess); } public Trade(final String command, final Trade fallback, final IEssentials ess) { - this(command, fallback, null, null, null, ess); + this(command, fallback, null, null, null, null, ess); } @Deprecated public Trade(final double money, final com.earth2me.essentials.IEssentials ess) { - this(null, null, BigDecimal.valueOf(money), null, null, (IEssentials) ess); + this(null, null, BigDecimal.valueOf(money), null, null, null, (IEssentials) ess); } public Trade(final BigDecimal money, final IEssentials ess) { - this(null, null, money, null, null, ess); + this(null, null, money, null, null, null, ess); } public Trade(final ItemStack items, final IEssentials ess) { - this(null, null, null, items, null, ess); + this(null, null, null, items, null, null, ess); } public Trade(final int exp, final IEssentials ess) { - this(null, null, null, null, exp, ess); + this(null, null, null, null, null, exp, ess); } - private Trade(final String command, final Trade fallback, final BigDecimal money, final ItemStack item, final Integer exp, final IEssentials ess) { + public Trade(final ItemGroupQuery query, final IEssentials ess){ + this(null, null, null, null, query, null, ess); + } + + private Trade(final String command, final Trade fallback, final BigDecimal money, final ItemStack item, final ItemGroupQuery groupQuery, final Integer exp, final IEssentials ess) { this.command = command; this.fallbackTrade = fallback; this.money = money; this.itemStack = item; + this.itemGroupQuery = groupQuery; this.exp = exp; this.ess = ess; } @@ -146,7 +152,7 @@ public static void log(final String type, final String subtype, final String eve sb.append(loc.getBlockY()).append(","); sb.append(loc.getBlockZ()).append(","); } - + if (endBalance == null) { sb.append(","); } else { @@ -303,6 +309,17 @@ public void charge(final IUser user, final CompletableFuture future) { Inventories.removeItemAmount(user.getBase(), getItemStack(), getItemStack().getAmount()); user.getBase().updateInventory(); } + if(getItemGroupQuery() != null){ + if(ess.getSettings().isDebug()) { + ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " itemgroup " +getItemGroupQuery().toString()); + } + if (!Inventories.containsAtLeast(user.getBase(), ess, getItemGroupQuery())) { + future.completeExceptionally(new ChargeException(tl("missingItems", getItemGroupQuery().getAmount(), "~"+getItemGroupQuery().getItemGroup().toLowerCase(Locale.ENGLISH).replace("_", " ")))); + return; + } + Inventories.removeItemAmount(user.getBase(), ess, getItemGroupQuery()); + user.getBase().updateInventory(); + } if (command != null) { final BigDecimal cost = getCommandCost(user); if (!user.canAfford(cost) && cost.signum() > 0) { @@ -335,6 +352,10 @@ public ItemStack getItemStack() { return itemStack; } + public ItemGroupQuery getItemGroupQuery() { + return itemGroupQuery; + } + public Integer getExperience() { return exp; } diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtop.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtop.java index f39b127896d..70582850048 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtop.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtop.java @@ -24,12 +24,12 @@ public void run(final Server server, final User user, final String commandLabel, final float yaw = user.getLocation().getYaw(); final Location unsafe = new Location(user.getWorld(), topX, ess.getWorldInfoProvider().getMaxHeight(user.getWorld()), topZ, yaw, pitch); final Location safe = LocationUtil.getSafeDestination(ess, unsafe); - final CompletableFuture future = new CompletableFuture<>(); + final CompletableFuture future = getNewExceptionFuture(user.getSource(), commandLabel); future.thenAccept(success -> { if (success) { user.sendMessage(tl("teleportTop", safe.getWorld().getName(), safe.getBlockX(), safe.getBlockY(), safe.getBlockZ())); } }); - user.getAsyncTeleport().teleport(safe, new Trade(this.getName(), ess), TeleportCause.COMMAND, getNewExceptionFuture(user.getSource(), commandLabel)); + user.getAsyncTeleport().teleport(safe, new Trade(this.getName(), ess), TeleportCause.COMMAND, future); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/craftbukkit/Inventories.java b/Essentials/src/main/java/com/earth2me/essentials/craftbukkit/Inventories.java index eb5c395bff8..be462b34565 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/craftbukkit/Inventories.java +++ b/Essentials/src/main/java/com/earth2me/essentials/craftbukkit/Inventories.java @@ -1,7 +1,10 @@ package com.earth2me.essentials.craftbukkit; +import com.earth2me.essentials.ItemGroupQuery; +import com.earth2me.essentials.ItemGroups; import com.earth2me.essentials.utils.MaterialUtil; import com.earth2me.essentials.utils.VersionUtil; +import net.ess3.api.IEssentials; import org.bukkit.entity.Player; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.Inventory; @@ -85,6 +88,22 @@ public static boolean containsAtLeast(final Player player, final ItemStack item, return false; } + public static boolean containsAtLeast(final Player player, IEssentials ess, final ItemGroupQuery query) { + int amount = query.getAmount(); + for (final ItemStack invItem : player.getInventory().getContents()) { + if (isEmpty(invItem)) { + continue; + } + if (query.contains(ess, invItem.getType())) { + amount -= invItem.getAmount(); + if (amount <= 0) { + return true; + } + } + } + return false; + } + public static boolean hasSpace(final Player player, final int maxStack, final boolean includeArmor, ItemStack... items) { items = normalizeItems(cloneItems(items)); final InventoryData inventoryData = parseInventoryData(player.getInventory(), items, maxStack, includeArmor); @@ -276,6 +295,41 @@ public static boolean removeItemAmount(final Player player, final ItemStack toRe return false; } + public static boolean removeItemAmount(final Player player, final IEssentials ess, final ItemGroupQuery query) { + final List clearSlots = new ArrayList<>(); + final ItemStack[] items = player.getInventory().getContents(); + + int amount = query.getAmount(); + for (int i = 0; i < items.length; i++) { + final ItemStack item = items[i]; + if (isEmpty(item)) { + continue; + } + + if (query.contains(ess, item.getType())) { + if (item.getAmount() >= amount) { + item.setAmount(item.getAmount() - amount); + player.getInventory().setItem(i, item); + for (final int slot : clearSlots) { + clearSlot(player, slot); + } + return true; + } else { + amount -= item.getAmount(); + clearSlots.add(i); + } + + if (amount == 0) { + for (final int slot : clearSlots) { + clearSlot(player, slot); + } + return true; + } + } + } + return false; + } + public static void clearSlot(final Player player, final int slot) { final ItemStack item = player.getInventory().getItem(slot); if (!isEmpty(item)) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/signs/EssentialsSign.java b/Essentials/src/main/java/com/earth2me/essentials/signs/EssentialsSign.java index cb0aaaf96b2..73f83ad813f 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/signs/EssentialsSign.java +++ b/Essentials/src/main/java/com/earth2me/essentials/signs/EssentialsSign.java @@ -2,6 +2,7 @@ import com.earth2me.essentials.ChargeException; import com.earth2me.essentials.CommandSource; +import com.earth2me.essentials.ItemGroupQuery; import com.earth2me.essentials.MetaItemStack; import com.earth2me.essentials.Trade; import com.earth2me.essentials.User; @@ -338,6 +339,12 @@ protected final void validateTrade(final ISign sign, final int amountIndex, fina sign.setLine(itemIndex, "exp"); return; } + if(itemType.startsWith("~")){ + final int amount = getIntegerPositive(getSignText(sign, amountIndex)); + sign.setLine(amountIndex, Integer.toString(amount)); + sign.setLine(itemIndex, "§6~§r"+itemType.substring(1)); + return; + } final Trade trade = getTrade(sign, amountIndex, itemIndex, player, ess); final ItemStack item = trade.getItemStack(); sign.setLine(amountIndex, Integer.toString(item.getAmount())); @@ -354,6 +361,11 @@ protected final Trade getTrade(final ISign sign, final int amountIndex, final in final int amount = getIntegerPositive(getSignText(sign, amountIndex)); return new Trade(amount, ess); } + if(itemType.startsWith("§6~§r")){ + final int amount = Math.min(getIntegerPositive(getSignText(sign, amountIndex)), 64 * player.getBase().getInventory().getSize()); + final ItemGroupQuery query = new ItemGroupQuery(itemType.substring(5), amount); + return new Trade(query, ess); + } final ItemStack item = getItemStack(itemType, 1, allowId, ess); final int amount = Math.min(getIntegerPositive(getSignText(sign, amountIndex)), item.getType().getMaxStackSize() * player.getBase().getInventory().getSize()); if (item.getType() == Material.AIR || amount < 1) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/signs/SignSell.java b/Essentials/src/main/java/com/earth2me/essentials/signs/SignSell.java index 1e1079f2588..f4f81867bce 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/signs/SignSell.java +++ b/Essentials/src/main/java/com/earth2me/essentials/signs/SignSell.java @@ -1,6 +1,7 @@ package com.earth2me.essentials.signs; import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.ItemGroupQuery; import com.earth2me.essentials.Trade; import com.earth2me.essentials.Trade.OverflowType; import com.earth2me.essentials.User; @@ -30,13 +31,24 @@ protected boolean onSignInteract(final ISign sign, final User player, final Stri // Check if the player is trying to sell in bulk. if (ess.getSettings().isAllowBulkBuySell() && player.getBase().isSneaking()) { final ItemStack heldItem = player.getItemInHand(); - if (charge.getItemStack().isSimilar(heldItem)) { + if (charge.getItemStack() != null && charge.getItemStack().isSimilar(heldItem)) { final int initialItemAmount = charge.getItemStack().getAmount(); final int newItemAmount = heldItem.getAmount(); final ItemStack item = charge.getItemStack(); item.setAmount(newItemAmount); charge = new Trade(item, ess); + final BigDecimal chargeAmount = money.getMoney(); + //noinspection BigDecimalMethodWithoutRoundingCalled + BigDecimal pricePerSingleItem = chargeAmount.divide(new BigDecimal(initialItemAmount)); + pricePerSingleItem = pricePerSingleItem.multiply(new BigDecimal(newItemAmount)); + money = new Trade(pricePerSingleItem, ess); + }else if(charge.getItemGroupQuery() != null && charge.getItemGroupQuery().contains(ess, heldItem.getType())){ + final ItemGroupQuery groupQuery = charge.getItemGroupQuery(); + final int initialItemAmount = groupQuery.getAmount(); + final int newItemAmount = heldItem.getAmount(); + charge = new Trade(new ItemGroupQuery(groupQuery.getItemGroup(), newItemAmount), ess); + final BigDecimal chargeAmount = money.getMoney(); //noinspection BigDecimalMethodWithoutRoundingCalled BigDecimal pricePerSingleItem = chargeAmount.divide(new BigDecimal(initialItemAmount)); diff --git a/Essentials/src/main/java/net/ess3/api/IItemGroups.java b/Essentials/src/main/java/net/ess3/api/IItemGroups.java new file mode 100644 index 00000000000..15ab907a48a --- /dev/null +++ b/Essentials/src/main/java/net/ess3/api/IItemGroups.java @@ -0,0 +1,26 @@ +package net.ess3.api; + +import com.earth2me.essentials.IConf; +import org.bukkit.Material; + +import java.util.List; +import java.util.Set; + +/** + * Provides access to the storage of item groups. Maintainers should add methods to this interface. + */ +public interface IItemGroups extends IConf { + + /** + * Gets the set of saved item groups from config file + * @return the set of item groups + */ + Set getItemGroups(); + + /** + * Gets the list of item materials inside an item group + * @param group the item group + * @return a list of items in the item group + */ + List getItemGroup(String group); +} diff --git a/Essentials/src/main/resources/groups.yml b/Essentials/src/main/resources/groups.yml new file mode 100644 index 00000000000..d73750e3d79 --- /dev/null +++ b/Essentials/src/main/resources/groups.yml @@ -0,0 +1,12 @@ +#EssentialsX item group configuration +#Item groups are currently used only by sell sign +#By creating a group here and using ~[group_id] on the sign +#Any player will be able to sell items with one of the types written here + +#Example +#dirt: +# - DIRT +# - GRASS +# - PODZOL +# - COARSE_DIRT +# - ROOTED_DIRT \ No newline at end of file From f36f195cd0fef436e819b0318a028f5b0bbd5897 Mon Sep 17 00:00:00 2001 From: wyrdix Date: Thu, 27 Apr 2023 18:32:45 +0200 Subject: [PATCH 2/2] Add the possibility of using minecraft tags as item groups --- .../main/java/com/earth2me/essentials/ItemGroupQuery.java | 7 +++++++ Essentials/src/main/resources/groups.yml | 1 + 2 files changed, 8 insertions(+) diff --git a/Essentials/src/main/java/com/earth2me/essentials/ItemGroupQuery.java b/Essentials/src/main/java/com/earth2me/essentials/ItemGroupQuery.java index ac20f61e9f9..06e2a12efe4 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/ItemGroupQuery.java +++ b/Essentials/src/main/java/com/earth2me/essentials/ItemGroupQuery.java @@ -1,7 +1,10 @@ package com.earth2me.essentials; import net.ess3.api.IEssentials; +import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; public class ItemGroupQuery { @@ -14,6 +17,10 @@ public ItemGroupQuery(String group, int quantity) { } public boolean contains(IEssentials ess, Material item){ + Tag tag = Bukkit.getTag(Tag.REGISTRY_ITEMS, NamespacedKey.minecraft(itemGroup), Material.class); + if (tag != null && tag.isTagged(item)) { + return true; + } final ItemGroups groupsConfig = new ItemGroups(ess); return groupsConfig.getItemGroup(itemGroup).contains(item); } diff --git a/Essentials/src/main/resources/groups.yml b/Essentials/src/main/resources/groups.yml index d73750e3d79..a8b7907118b 100644 --- a/Essentials/src/main/resources/groups.yml +++ b/Essentials/src/main/resources/groups.yml @@ -3,6 +3,7 @@ #By creating a group here and using ~[group_id] on the sign #Any player will be able to sell items with one of the types written here +#You can use minecraft tags as groups, for reference https://minecraft.fandom.com/wiki/Tag#Item_tags #Example #dirt: # - DIRT