ChestShop-3/src/main/java/com/Acrobot/ChestShop/Signs/ChestShopSign.java

301 lines
11 KiB
Java

package com.Acrobot.ChestShop.Signs;
import com.Acrobot.Breeze.Utils.BlockUtil;
import com.Acrobot.Breeze.Utils.QuantityUtil;
import com.Acrobot.Breeze.Utils.StringUtil;
import com.Acrobot.ChestShop.Configuration.Properties;
import com.Acrobot.ChestShop.Containers.AdminInventory;
import com.Acrobot.ChestShop.Database.Account;
import com.Acrobot.ChestShop.Events.AccountQueryEvent;
import com.Acrobot.ChestShop.Permission;
import com.Acrobot.ChestShop.UUIDs.NameManager;
import com.Acrobot.ChestShop.Utils.uBlock;
import org.bukkit.Bukkit;
import org.bukkit.block.*;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import java.util.Locale;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.Acrobot.Breeze.Utils.ImplementationAdapter.getState;
/**
* @author Acrobot
*/
public class ChestShopSign {
public static final byte NAME_LINE = 0;
public static final byte QUANTITY_LINE = 1;
public static final byte PRICE_LINE = 2;
public static final byte ITEM_LINE = 3;
public static final Pattern[][] SHOP_SIGN_PATTERN = {
{ Pattern.compile("^[1-9][0-9]{0,5}$"), QuantityUtil.QUANTITY_LINE_WITH_COUNTER_PATTERN },
{
Pattern.compile("(?i)^((\\d*([.e]\\d+)?)|free)$"),
Pattern.compile("(?i)^([BS] *((\\d*([.e]\\d+)?)|free))( *: *([BS] *((\\d*([.e]\\d+)?)|free)))?$"),
Pattern.compile("(?i)^(((\\d*([.e]\\d+)?)|free) *[BS])( *: *([BS] *((\\d*([.e]\\d+)?)|free)))?$"),
Pattern.compile("(?i)^(((\\d*([.e]\\d+)?)|free) *[BS]) *: *(((\\d*([.e]\\d+)?)|free) *[BS])$"),
Pattern.compile("(?i)^([BS] *((\\d*([.e]\\d+)?)|free)) *: *(((\\d*([.e]\\d+)?)|free) *[BS])$"),
},
{ Pattern.compile("^[\\p{L}\\d_? #:\\-]+$") }
};
public static final String AUTOFILL_CODE = "?";
public static boolean isAdminShop(Inventory ownerInventory) {
return ownerInventory instanceof AdminInventory;
}
public static boolean isAdminShop(String owner) {
return owner.replace(" ", "").equalsIgnoreCase(Properties.ADMIN_SHOP_NAME.replace(" ", ""));
}
public static boolean isAdminShop(Sign sign) {
return isAdminShop(sign.getLines());
}
public static boolean isAdminShop(String[] lines) {
return isAdminShop(getOwner(lines));
}
public static boolean isValid(Sign sign) {
return isValid(sign.getLines());
}
public static boolean isValid(String[] lines) {
lines = StringUtil.stripColourCodes(lines);
return isValidPreparedSign(lines)
&& (getPrice(lines).toUpperCase(Locale.ROOT).contains("B")
|| getPrice(lines).toUpperCase(Locale.ROOT).contains("S"))
&& !getOwner(lines).isEmpty();
}
public static boolean isValid(Block sign) {
return BlockUtil.isSign(sign) && isValid((Sign) getState(sign, false));
}
/**
* @deprecated Use {@link #isShopBlock(Block}
*/
@Deprecated
public static boolean isShopChest(Block chest) {
if (!BlockUtil.isChest(chest)) {
return false;
}
return uBlock.getConnectedSign(chest) != null;
}
public static boolean isShopBlock(Block block) {
if (!uBlock.couldBeShopContainer(block)) {
return false;
}
return uBlock.getConnectedSign(block) != null;
}
/**
* @deprecated Use {@link #isShopBlock(InventoryHolder}
*/
@Deprecated
public static boolean isShopChest(InventoryHolder holder) {
if (!BlockUtil.isChest(holder)) {
return false;
}
if (holder instanceof DoubleChest) {
return isShopChest(((DoubleChest) holder).getLocation().getBlock());
} else if (holder instanceof Chest) {
return isShopChest(((Chest) holder).getBlock());
} else {
return false;
}
}
public static boolean isShopBlock(InventoryHolder holder) {
if (holder instanceof DoubleChest) {
return isShopBlock(((DoubleChest) holder).getLeftSide())
|| isShopBlock(((DoubleChest) holder).getRightSide());
} else if (holder instanceof BlockState) {
return isShopBlock(((BlockState) holder).getBlock());
}
return false;
}
public static Block getShopBlock(InventoryHolder holder) {
if (holder instanceof DoubleChest) {
return Optional.ofNullable(getShopBlock(((DoubleChest) holder).getLeftSide()))
.orElse(getShopBlock(((DoubleChest) holder).getRightSide()));
} else if (holder instanceof BlockState) {
return ((BlockState) holder).getBlock();
}
return null;
}
public static boolean canAccess(Player player, Sign sign) {
return hasPermission(player, Permission.OTHER_NAME_ACCESS, sign);
}
public static boolean hasPermission(Player player, Permission base, Sign sign) {
if (player == null) return false;
if (sign == null) return true;
String name = getOwner(sign);
if (name == null || name.isEmpty()) return true;
return NameManager.canUseName(player, base, name);
}
public static boolean isOwner(Player player, Sign sign) {
if (player == null || sign == null) return false;
String name = getOwner(sign);
if (name == null || name.isEmpty()) return false;
AccountQueryEvent accountQueryEvent = new AccountQueryEvent(name);
Bukkit.getPluginManager().callEvent(accountQueryEvent);
Account account = accountQueryEvent.getAccount();
if (account == null) {
return player.getName().equalsIgnoreCase(name);
}
return account.getUuid().equals(player.getUniqueId());
}
public static boolean isValidPreparedSign(String[] lines) {
String playername = ChestShopSign.getOwner(lines);
// If the shop owner is not blank (auto-filled) or the admin shop string, we need to validate it
if ((!isAdminShop(playername)) && (playername.length() > 0)) {
// Prepare regexp patterns
Pattern playernamePattern = Pattern.compile(Properties.VALID_PLAYERNAME_REGEXP); // regexp from config file
Matcher playernameWithIdMatcher = Pattern.compile("^(.+):[A-Za-z0-9]+$").matcher(playername); // regexp to match ':' and a base62 encoded string
// Check if the playername has an ID. This can happen on duplicate or too long names
if (playernameWithIdMatcher.matches()) {
// Playername matches the id pattern, so validate everything before the last ':'
playername = playernameWithIdMatcher.group(1);
}
// If the playername doesn't match, this is not a valid sign, so return
if (!playernamePattern.matcher(playername).matches()) {
return false;
}
}
// The playername on the first line is valid. Now validate the last 3 lines against the predefined regexp patterns.
for (int i = 0; i < 3; i++) {
boolean matches = false;
for (Pattern pattern : SHOP_SIGN_PATTERN[i]) {
if (pattern.matcher(StringUtil.strip(StringUtil.stripColourCodes(lines[i+1]))).matches()) {
matches = true;
break;
}
}
if (!matches) {
return false;
}
}
// All lines are looking good. If the price line contains only one ':', then this is a valid prepared sign.
String priceLine = getPrice(lines);
return priceLine.indexOf(':') == priceLine.lastIndexOf(':');
}
/**
* Get the owner string of a shop sign
* @param sign The sign
* @return The owner string
*/
public static String getOwner(Sign sign) {
return getOwner(sign.getLines());
}
/**
* Get the owner string of a shop sign
* @param lines The sign lines
* @return The owner string
*/
public static String getOwner(String[] lines) {
return StringUtil.stripColourCodes(StringUtil.strip(StringUtil.stripColourCodes(lines[NAME_LINE])));
}
/**
* Get the quantity and count line of the shop sign
* @param sign The sign
* @return The quantity line
* @throws IllegalArgumentException Thrown when an invalid quantity is present
*/
public static String getQuantityLine(Sign sign) throws IllegalArgumentException {
return getQuantityLine(sign.getLines());
}
/**
* Get the quantity and count line of sign lines
* @param lines The sign lines
* @return The quantity line
* @throws IllegalArgumentException Thrown when an invalid quantity is present
*/
public static String getQuantityLine(String[] lines) throws IllegalArgumentException {
return lines.length > QUANTITY_LINE ? StringUtil.strip(StringUtil.stripColourCodes(lines[QUANTITY_LINE])) : "";
}
/**
* Get the quantity of the shop sign
* @param sign The sign
* @return The quantity line
* @throws IllegalArgumentException Thrown when an invalid quantity is present
*/
public static int getQuantity(Sign sign) throws IllegalArgumentException {
return getQuantity(sign.getLines());
}
/**
* Get the quantity of sign lines
* @param lines The sign lines
* @return The quantity
* @throws IllegalArgumentException Thrown when an invalid quantity is present
*/
public static int getQuantity(String[] lines) throws IllegalArgumentException {
return QuantityUtil.parseQuantity(getQuantityLine(lines));
}
/**
* Get the price line of the shop sign
* @param sign The sign
* @return The price line
*/
public static String getPrice(Sign sign) {
return StringUtil.strip(StringUtil.stripColourCodes(sign.getLine(PRICE_LINE)));
}
/**
* Get the price line of sign lines
* @param lines The sign lines
* @return The price line
*/
public static String getPrice(String[] lines) {
return lines.length > PRICE_LINE ? StringUtil.strip(StringUtil.stripColourCodes(lines[PRICE_LINE])) : "";
}
/**
* Get the item line of the shop sign
* @param sign The sign
* @return The item line
*/
public static String getItem(Sign sign) {
return getItem(sign.getLines());
}
/**
* Get the item line of sign lines
* @param lines The sign lines
* @return The item line
*/
public static String getItem(String[] lines) {
return lines.length > ITEM_LINE ? StringUtil.strip(StringUtil.stripColourCodes(lines[ITEM_LINE])) : "";
}
}