diff --git a/pom.xml b/pom.xml index 8bb476d..5178b68 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 ca.tweetzy auctionhouse - 2.28.1 + 2.29.0 UTF-8 diff --git a/src/main/java/ca/tweetzy/auctionhouse/AuctionHouse.java b/src/main/java/ca/tweetzy/auctionhouse/AuctionHouse.java index a2e09df..00323a4 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/AuctionHouse.java +++ b/src/main/java/ca/tweetzy/auctionhouse/AuctionHouse.java @@ -145,7 +145,8 @@ public class AuctionHouse extends TweetyPlugin { new _4_ItemsChangeMigration(), new _5_TransactionChangeMigration(), new _6_BigIntMigration(), - new _7_TransactionBigIntMigration() + new _7_TransactionBigIntMigration(), + new _8_ItemPerWorldMigration() ); dataMigrationManager.runMigrations(); diff --git a/src/main/java/ca/tweetzy/auctionhouse/api/AuctionAPI.java b/src/main/java/ca/tweetzy/auctionhouse/api/AuctionAPI.java index 0df5ec1..d49523c 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/api/AuctionAPI.java +++ b/src/main/java/ca/tweetzy/auctionhouse/api/AuctionAPI.java @@ -19,6 +19,7 @@ import ca.tweetzy.core.utils.items.ItemUtils; import ca.tweetzy.core.utils.nms.NBTEditor; import io.lumine.mythic.lib.api.item.NBTItem; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; import org.apache.commons.lang.WordUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -575,6 +576,7 @@ public class AuctionAPI { auctionedItem.setBidStartingPrice(bidStartPrice); auctionedItem.setBidIncrementPrice(bidIncPrice); auctionedItem.setCurrentPrice(currentPrice); + auctionedItem.setListedWorld(seller.getWorld().getName()); if (Settings.TAX_ENABLED.getBoolean() && Settings.TAX_CHARGE_LISTING_FEE.getBoolean()) { if (!EconomyManager.hasBalance(seller, Settings.TAX_LISTING_FEE.getDouble())) { @@ -664,7 +666,71 @@ public class AuctionAPI { logger.log(Level.FINER, th, () -> "A " + (type == null ? "critical" : type) + " error occurred"); } - void x(ItemStack item) { - NBTItem.get(item).getType(); + /** + * Converts the time from a human readable format like "10 minutes" + * to seconds. + * + * @param humanReadableTime the human readable time format: {time} {period} + * example: 5 seconds, 10 ticks, 7 minutes, 12 hours etc.. + * @return the converted human time to seconds + */ + public static long toTicks(final String humanReadableTime) { + if (humanReadableTime == null) return 0; + + long seconds = 0L; + + final String[] split = humanReadableTime.split(" "); + + if (!(split.length > 1)) { + return 0; + } + + for (int i = 1; i < split.length; i++) { + final String sub = split[i].toLowerCase(); + int multiplier = 0; // e.g 2 hours = 2 + long unit = 0; // e.g hours = 3600 + boolean isTicks = false; + + try { + multiplier = Integer.parseInt(split[i - 1]); + } catch (final NumberFormatException e) { + continue; + } + + // attempt to match the unit time + if (sub.startsWith("tick")) + isTicks = true; + + else if (sub.startsWith("second")) + unit = 1; + + else if (sub.startsWith("minute")) + unit = 60; + + else if (sub.startsWith("hour")) + unit = 3600; + + else if (sub.startsWith("day")) + unit = 86400; + + else if (sub.startsWith("week")) + unit = 604800; + + else if (sub.startsWith("month")) + unit = 2629743; + + else if (sub.startsWith("year")) + unit = 31556926; + + else if (sub.startsWith("potato")) + unit = 1337; + + else + throw new IllegalArgumentException("Must define date type! Example: '1 second' (Got '" + sub + "')"); + + seconds += multiplier * (isTicks ? 1 : unit); + } + + return seconds; } } diff --git a/src/main/java/ca/tweetzy/auctionhouse/auction/AuctionedItem.java b/src/main/java/ca/tweetzy/auctionhouse/auction/AuctionedItem.java index 526e0e5..a8054e6 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/auction/AuctionedItem.java +++ b/src/main/java/ca/tweetzy/auctionhouse/auction/AuctionedItem.java @@ -47,6 +47,8 @@ public class AuctionedItem { private boolean expired; private long expiresAt; + private String listedWorld = null; + public AuctionedItem() {} public AuctionedItem( diff --git a/src/main/java/ca/tweetzy/auctionhouse/commands/CommandSell.java b/src/main/java/ca/tweetzy/auctionhouse/commands/CommandSell.java index d9576e1..026a9ec 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/commands/CommandSell.java +++ b/src/main/java/ca/tweetzy/auctionhouse/commands/CommandSell.java @@ -12,11 +12,13 @@ import ca.tweetzy.core.compatibility.XMaterial; import ca.tweetzy.core.utils.NumberUtils; import ca.tweetzy.core.utils.PlayerUtils; import ca.tweetzy.core.utils.nms.NBTEditor; +import com.sun.prism.shader.Texture_ImagePattern_Loader; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -82,9 +84,17 @@ public final class CommandSell extends AbstractCommand { } // Check for block items - if (Settings.BLOCKED_ITEMS.getStringList().contains(itemToSell.getType().name())) { - AuctionHouse.getInstance().getLocale().getMessage("general.blockeditem").processPlaceholder("item", itemToSell.getType().name()).sendPrefixedMessage(player); - return ReturnType.FAILURE; + + if (Settings.MAKE_BLOCKED_ITEMS_A_WHITELIST.getBoolean()) { + if (!Settings.BLOCKED_ITEMS.getStringList().contains(itemToSell.getType().name())) { + AuctionHouse.getInstance().getLocale().getMessage("general.blockeditem").processPlaceholder("item", itemToSell.getType().name()).sendPrefixedMessage(player); + return ReturnType.FAILURE; + } + } else { + if (Settings.BLOCKED_ITEMS.getStringList().contains(itemToSell.getType().name())) { + AuctionHouse.getInstance().getLocale().getMessage("general.blockeditem").processPlaceholder("item", itemToSell.getType().name()).sendPrefixedMessage(player); + return ReturnType.FAILURE; + } } boolean blocked = false; @@ -126,18 +136,27 @@ public final class CommandSell extends AbstractCommand { Double bidIncrement = null; boolean isBundle = false; - for (String arg : args) { - if (NumberUtils.isDouble(arg)) { + + for (int i = 0; i < args.length; i++) { + if (NumberUtils.isDouble(args[i])) { if (buyNowPrice == null) - buyNowPrice = Double.parseDouble(arg); + buyNowPrice = Double.parseDouble(args[i]); else if (startingBid == null) - startingBid = Double.parseDouble(arg); + startingBid = Double.parseDouble(args[i]); else - bidIncrement = Double.parseDouble(arg); + bidIncrement = Double.parseDouble(args[i]); } - if (arg.equalsIgnoreCase("-b")) + if (args[i].equalsIgnoreCase("-b") || args[i].equalsIgnoreCase("-bundle")) isBundle = true; + + if (args[i].toLowerCase().startsWith("-t") && Settings.ALLOW_PLAYERS_TO_DEFINE_AUCTION_TIME.getBoolean()) { + if (i + 2 < args.length) { + int customTime = (int) AuctionAPI.toTicks(args[i + 1] + " " + args[i + 2]); + if (customTime <= Settings.MAX_CUSTOM_DEFINED_TIME.getInt()) + allowedTime = customTime; + } + } } boolean isBiddingItem = Settings.FORCE_AUCTION_USAGE.getBoolean() || buyNowPrice != null && startingBid != null && Settings.ALLOW_USAGE_OF_BID_SYSTEM.getBoolean(); @@ -231,8 +250,12 @@ public final class CommandSell extends AbstractCommand { @Override protected List onTab(CommandSender sender, String... args) { - if (args.length <= 3) return Arrays.asList("1", "2", "3", "4", "5"); - if (args.length == 4) return Collections.singletonList("-b"); + if (args.length == 1) + return Arrays.asList(AuctionHouse.getInstance().getLocale().getMessage("commands.sell.args.suggestion one").getMessage().split(" ")); + if (args.length == 2) + return Arrays.asList(AuctionHouse.getInstance().getLocale().getMessage("commands.sell.args.suggestion two").getMessage().split(" ")); + if (args.length == 3) + return Arrays.asList(AuctionHouse.getInstance().getLocale().getMessage("commands.sell.args.suggestion three").getMessage().split(" ")); return null; } diff --git a/src/main/java/ca/tweetzy/auctionhouse/database/DataManager.java b/src/main/java/ca/tweetzy/auctionhouse/database/DataManager.java index 36f69b8..e846f32 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/database/DataManager.java +++ b/src/main/java/ca/tweetzy/auctionhouse/database/DataManager.java @@ -248,7 +248,7 @@ public class DataManager extends DataManagerAbstract { public void insertAuction(AuctionedItem item, Callback callback) { this.databaseConnector.connect(connection -> { - try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + this.getTablePrefix() + "auctions(id, owner, highest_bidder, owner_name, highest_bidder_name, category, base_price, bid_start_price, bid_increment_price, current_price, expired, expires_at, item_material, item_name, item_lore, item_enchants, item) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) { + try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + this.getTablePrefix() + "auctions(id, owner, highest_bidder, owner_name, highest_bidder_name, category, base_price, bid_start_price, bid_increment_price, current_price, expired, expires_at, item_material, item_name, item_lore, item_enchants, item, listed_world) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) { PreparedStatement fetch = connection.prepareStatement("SELECT * FROM " + this.getTablePrefix() + "auctions WHERE id = ?"); fetch.setString(1, item.getId().toString()); @@ -269,6 +269,7 @@ public class DataManager extends DataManagerAbstract { statement.setString(15, AuctionAPI.getInstance().serializeLines(AuctionAPI.getInstance().getItemLore(item.getItem()))); statement.setString(16, AuctionAPI.getInstance().serializeLines(AuctionAPI.getInstance().getItemEnchantments(item.getItem()))); statement.setString(17, AuctionAPI.encodeItem(item.getItem())); + statement.setString(18, item.getListedWorld()); statement.executeUpdate(); if (callback != null) { @@ -415,7 +416,7 @@ public class DataManager extends DataManagerAbstract { } private AuctionedItem extractAuctionedItem(ResultSet resultSet) throws SQLException { - return new AuctionedItem( + AuctionedItem auctionItem = new AuctionedItem( UUID.fromString(resultSet.getString("id")), UUID.fromString(resultSet.getString("owner")), UUID.fromString(resultSet.getString("highest_bidder")), @@ -431,6 +432,10 @@ public class DataManager extends DataManagerAbstract { resultSet.getBoolean("expired"), resultSet.getLong("expires_at") ); + + auctionItem.setListedWorld(resultSet.getString("listed_world")); + + return auctionItem; } private Transaction extractTransaction(ResultSet resultSet) throws SQLException { diff --git a/src/main/java/ca/tweetzy/auctionhouse/database/migrations/_8_ItemPerWorldMigration.java b/src/main/java/ca/tweetzy/auctionhouse/database/migrations/_8_ItemPerWorldMigration.java new file mode 100644 index 0000000..cb4de14 --- /dev/null +++ b/src/main/java/ca/tweetzy/auctionhouse/database/migrations/_8_ItemPerWorldMigration.java @@ -0,0 +1,27 @@ +package ca.tweetzy.auctionhouse.database.migrations; + +import ca.tweetzy.core.database.DataMigration; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * The current file has been created by Kiran Hart + * Date Created: August 24 2021 + * Time Created: 4:04 p.m. + * Usage of any code found within this class is prohibited unless given explicit permission otherwise + */ +public final class _8_ItemPerWorldMigration extends DataMigration { + + public _8_ItemPerWorldMigration() { + super(8); + } + + @Override + public void migrate(Connection connection, String tablePrefix) throws SQLException { + try (Statement statement = connection.createStatement()) { + statement.execute("ALTER TABLE " + tablePrefix + "auctions ADD listed_world VARCHAR(64) NULL"); + } + } +} diff --git a/src/main/java/ca/tweetzy/auctionhouse/guis/GUIActiveAuctions.java b/src/main/java/ca/tweetzy/auctionhouse/guis/GUIActiveAuctions.java index de58885..4be1c13 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/guis/GUIActiveAuctions.java +++ b/src/main/java/ca/tweetzy/auctionhouse/guis/GUIActiveAuctions.java @@ -54,6 +54,12 @@ public class GUIActiveAuctions extends Gui { private void drawItems() { AuctionHouse.newChain().asyncFirst(() -> { this.items = this.auctionPlayer.getItems(false); + + // per world check + if (Settings.PER_WORLD_ITEMS.getBoolean()) { + this.items = this.items.stream().filter(item -> item.getListedWorld() == null || this.auctionPlayer.getPlayer().getWorld().getName().equals(item.getListedWorld())).collect(Collectors.toList()); + } + return this.items.stream().sorted(Comparator.comparingLong(AuctionedItem::getExpiresAt).reversed()).skip((page - 1) * 45L).limit(45).collect(Collectors.toList()); }).asyncLast((data) -> { pages = (int) Math.max(1, Math.ceil(this.items.size() / (double) 45L)); diff --git a/src/main/java/ca/tweetzy/auctionhouse/guis/GUIAuctionHouse.java b/src/main/java/ca/tweetzy/auctionhouse/guis/GUIAuctionHouse.java index a10fdc9..382dac5 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/guis/GUIAuctionHouse.java +++ b/src/main/java/ca/tweetzy/auctionhouse/guis/GUIAuctionHouse.java @@ -98,7 +98,13 @@ public class GUIAuctionHouse extends Gui { for (Map.Entry entry : AuctionHouse.getInstance().getAuctionItemManager().getItems().entrySet()) { AuctionedItem auctionItem = entry.getValue(); if (!auctionItem.isExpired() && !AuctionHouse.getInstance().getAuctionItemManager().getGarbageBin().containsKey(auctionItem.getId())) { - this.items.add(auctionItem); + if (Settings.PER_WORLD_ITEMS.getBoolean()) { + if (auctionItem.getListedWorld() == null || this.auctionPlayer.getPlayer().getWorld().getName().equals(auctionItem.getListedWorld())) { + this.items.add(auctionItem); + } + } else { + this.items.add(auctionItem); + } } } diff --git a/src/main/java/ca/tweetzy/auctionhouse/guis/GUIExpiredItems.java b/src/main/java/ca/tweetzy/auctionhouse/guis/GUIExpiredItems.java index 89c8bda..2f30e14 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/guis/GUIExpiredItems.java +++ b/src/main/java/ca/tweetzy/auctionhouse/guis/GUIExpiredItems.java @@ -50,6 +50,11 @@ public class GUIExpiredItems extends Gui { AuctionHouse.newChain().asyncFirst(() -> { this.items = this.auctionPlayer.getItems(true); + + if (Settings.PER_WORLD_ITEMS.getBoolean()) { + this.items = this.items.stream().filter(item -> item.getListedWorld() == null || this.auctionPlayer.getPlayer().getWorld().getName().equals(item.getListedWorld())).collect(Collectors.toList()); + } + return this.items.stream().sorted(Comparator.comparingLong(AuctionedItem::getExpiresAt).reversed()).skip((page - 1) * 45L).limit(45).collect(Collectors.toList()); }).asyncLast((data) -> { pages = (int) Math.max(1, Math.ceil(this.auctionPlayer.getItems(true).size() / (double) 45)); diff --git a/src/main/java/ca/tweetzy/auctionhouse/guis/GUISellItem.java b/src/main/java/ca/tweetzy/auctionhouse/guis/GUISellItem.java index fe8570b..7995393 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/guis/GUISellItem.java +++ b/src/main/java/ca/tweetzy/auctionhouse/guis/GUISellItem.java @@ -116,19 +116,20 @@ public class GUISellItem extends Gui { reset(); // the draw item that is being listed - setButton(1, 4, this.itemToBeListed, e -> { - if (e.clickType == ClickType.RIGHT || e.clickType == ClickType.NUMBER_KEY) e.event.setCancelled(true); - // Is the user selling with an item in hand? - if (AuctionHouse.getInstance().getAuctionPlayerManager().getSellHolding().containsKey(e.player.getUniqueId())) { - if (AuctionHouse.getInstance().getAuctionPlayerManager().getSellHolding().get(e.player.getUniqueId()).getType() != XMaterial.AIR.parseMaterial()) { - e.event.setCancelled(true); + setButton(1, 4, this.itemToBeListed, e -> { + if (e.clickType == ClickType.RIGHT || e.clickType == ClickType.NUMBER_KEY) e.event.setCancelled(true); + // Is the user selling with an item in hand? + if (AuctionHouse.getInstance().getAuctionPlayerManager().getSellHolding().containsKey(e.player.getUniqueId())) { + if (AuctionHouse.getInstance().getAuctionPlayerManager().getSellHolding().get(e.player.getUniqueId()).getType() != XMaterial.AIR.parseMaterial()) { + e.event.setCancelled(true); + } } - } - this.itemToBeListed = e.clickedItem; - }); + this.itemToBeListed = e.clickedItem; + }); - if (Settings.ALLOW_USAGE_OF_BUY_NOW_SYSTEM.getBoolean()) { + + if (Settings.ALLOW_USAGE_OF_BUY_NOW_SYSTEM.getBoolean() && this.isAllowingBuyNow) { setButton(3, 1, ConfigurationItemHelper.createConfigurationItem(Settings.GUI_SELL_ITEMS_BUY_NOW_ITEM.getString(), Settings.GUI_SELL_ITEMS_BUY_NOW_NAME.getString(), Settings.GUI_SELL_ITEMS_BUY_NOW_LORE.getStringList(), new HashMap() {{ put("%buy_now_price%", AuctionAPI.getInstance().formatNumber(buyNowPrice)); }}), ClickType.LEFT, e -> { @@ -153,7 +154,7 @@ public class GUISellItem extends Gui { } if (this.isBiddingItem) { - setButton(3, Settings.FORCE_CUSTOM_BID_AMOUNT.getBoolean() ? 3 : Settings.ALLOW_USAGE_OF_BUY_NOW_SYSTEM.getBoolean() ? 2 : 1, ConfigurationItemHelper.createConfigurationItem(Settings.GUI_SELL_ITEMS_STARTING_BID_ITEM.getString(), Settings.GUI_SELL_ITEMS_STARTING_BID_NAME.getString(), Settings.GUI_SELL_ITEMS_STARTING_BID_LORE.getStringList(), new HashMap() {{ + setButton(3, Settings.FORCE_CUSTOM_BID_AMOUNT.getBoolean() ? 2 : Settings.ALLOW_USAGE_OF_BUY_NOW_SYSTEM.getBoolean() ? 2 : 1, ConfigurationItemHelper.createConfigurationItem(Settings.GUI_SELL_ITEMS_STARTING_BID_ITEM.getString(), Settings.GUI_SELL_ITEMS_STARTING_BID_NAME.getString(), Settings.GUI_SELL_ITEMS_STARTING_BID_LORE.getStringList(), new HashMap() {{ put("%starting_bid_price%", AuctionAPI.getInstance().formatNumber(bidStartPrice)); }}), ClickType.LEFT, e -> { setTheItemToBeListed(); @@ -217,7 +218,7 @@ public class GUISellItem extends Gui { return; } - if (this.isBiddingItem && this.buyNowPrice <= this.bidStartPrice && Settings.BASE_PRICE_MUST_BE_HIGHER_THAN_BID_START.getBoolean()) { + if (this.isAllowingBuyNow && this.isBiddingItem && this.buyNowPrice <= this.bidStartPrice && Settings.BASE_PRICE_MUST_BE_HIGHER_THAN_BID_START.getBoolean()) { AuctionHouse.getInstance().getLocale().getMessage("pricing.basepricetoolow").sendPrefixedMessage(e.player); return; } diff --git a/src/main/java/ca/tweetzy/auctionhouse/settings/LocaleSettings.java b/src/main/java/ca/tweetzy/auctionhouse/settings/LocaleSettings.java index d8e5f62..fe06d85 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/settings/LocaleSettings.java +++ b/src/main/java/ca/tweetzy/auctionhouse/settings/LocaleSettings.java @@ -122,6 +122,9 @@ public class LocaleSettings { languageNodes.put("commands.invalid_syntax", "&7The valid syntax is: &6%syntax%&7."); languageNodes.put("commands.no_permission", "&dYou do not have permission to do that."); + languageNodes.put("commands.sell.args.suggestion one", "100"); + languageNodes.put("commands.sell.args.suggestion two", "50 -b"); + languageNodes.put("commands.sell.args.suggestion three", "10 -b"); languageNodes.put("commands.syntax.active", "active"); languageNodes.put("commands.syntax.auctionhouse", "/ah"); diff --git a/src/main/java/ca/tweetzy/auctionhouse/settings/Settings.java b/src/main/java/ca/tweetzy/auctionhouse/settings/Settings.java index 82e85c9..249d46d 100644 --- a/src/main/java/ca/tweetzy/auctionhouse/settings/Settings.java +++ b/src/main/java/ca/tweetzy/auctionhouse/settings/Settings.java @@ -79,6 +79,9 @@ public class Settings { public static final ConfigSetting USE_ALTERNATE_CURRENCY_FORMAT = new ConfigSetting(config, "auction setting.use alternate currency format", false, "If true, $123,456.78 will become $123.456,78"); public static final ConfigSetting DATE_FORMAT = new ConfigSetting(config, "auction setting.date format", "MMM dd, yyyy hh:mm aa", "You can learn more about date formats by googling SimpleDateFormat patterns or visiting this link", "https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html"); public static final ConfigSetting ALLOW_PLAYERS_TO_ACCEPT_BID = new ConfigSetting(config, "auction setting.allow players to accept bid", true, "If true, players can right click a biddable item inside their active listings menu to accept the current bid"); + public static final ConfigSetting PER_WORLD_ITEMS = new ConfigSetting(config, "auction setting.per world items", false, "If true, items can only be seen in the world they were listed in, same goes for bidding/buying/collecting"); + public static final ConfigSetting ALLOW_PLAYERS_TO_DEFINE_AUCTION_TIME = new ConfigSetting(config, "auction setting.allow players to set auction time", false, "If true players can use -t 1 day for example to set the listing time for their item"); + public static final ConfigSetting MAX_CUSTOM_DEFINED_TIME = new ConfigSetting(config, "auction setting.max custom defined time", 604800, "What should the limit on custom defined listing times be in seconds?"); public static final ConfigSetting USE_SEPARATE_FILTER_MENU = new ConfigSetting(config, "auction setting.use separate filter menu", false, "If true, rather than using a single filter item inside the auction menu", "it will open an entirely new menu to select the filter"); public static final ConfigSetting SELL_MENU_REQUIRES_USER_TO_HOLD_ITEM = new ConfigSetting(config, "auction setting.require user to hold item when using sell menu", false, "If enabled, when running just /ah sell, the user will need to hold the item in their hand, otherwise they just add it in the gui."); @@ -240,6 +243,7 @@ public class Settings { * BLACK LISTED * ===============================*/ public static final ConfigSetting BLOCKED_ITEMS = new ConfigSetting(config, "blocked items", Collections.singletonList("ENDER_CHEST"), "Materials that should be blocked (not allowed to sell)"); + public static final ConfigSetting MAKE_BLOCKED_ITEMS_A_WHITELIST = new ConfigSetting(config, "blocked items is whitelist", false, "If true, blocked items will become a whitelist, meaning only items specified in blacked list will be allowed in the ah"); public static final ConfigSetting BLOCKED_ITEM_NAMES = new ConfigSetting(config, "blocked item names", Arrays.asList( "fuck", "bitch",