package com.griefdefender.util; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import com.flowpowered.math.vector.Vector3i; import com.google.common.collect.ImmutableMap; import com.griefdefender.GriefDefenderPlugin; import com.griefdefender.api.claim.Claim; import com.griefdefender.api.economy.PaymentType; import com.griefdefender.cache.MessageCache; import com.griefdefender.cache.PermissionHolderCache; import com.griefdefender.claim.GDClaim; import com.griefdefender.configuration.MessageStorage; import com.griefdefender.internal.util.VecHelper; import com.griefdefender.permission.GDPermissionUser; import com.griefdefender.permission.GDPermissions; import com.griefdefender.text.action.GDCallbackHolder; import net.kyori.text.Component; import net.kyori.text.TextComponent; import net.kyori.text.adapter.bukkit.TextAdapter; import net.kyori.text.event.ClickEvent; import net.kyori.text.format.TextColor; import net.kyori.text.serializer.legacy.LegacyComponentSerializer; public class SignUtil { final static String SELL_SIGN = "[GD-sell]"; final static String RENT_SIGN = "[GD-rent]"; public static boolean isSellSign(Block block) { if (!isSign(block)) { return false; } final Sign sign = (Sign) block.getState(); final String header = ChatColor.stripColor(sign.getLine(0)); if (header.equalsIgnoreCase(SELL_SIGN)) { return true; } return false; } public static boolean isRentSign(Block block) { if (!isSign(block)) { return false; } final Sign sign = (Sign) block.getState(); final String header = ChatColor.stripColor(sign.getLine(0)); if (header.equalsIgnoreCase(RENT_SIGN)) { return true; } return false; } public static boolean isSellSign(Sign sign) { if (sign == null) { return false; } final String header = ChatColor.stripColor(sign.getLine(0)); if (header.equalsIgnoreCase(SELL_SIGN)) { return true; } return false; } public static boolean isRentSign(Claim claim, Sign sign) { if (sign == null) { return false; } if (claim.getEconomyData() == null) { return false; } if (claim.getEconomyData().getRentSignPosition() == null) { return isRentSign(sign); } return claim.getEconomyData().getRentSignPosition().equals(VecHelper.toVector3i(sign.getLocation())); } public static boolean isRentSign(Sign sign) { if (sign == null) { return false; } final String header = ChatColor.stripColor(sign.getLine(0)); if (header.equalsIgnoreCase(RENT_SIGN)) { return true; } return false; } public static boolean isSign(Block block) { if (block == null) { return false; } final BlockState state = block.getState(); if (!(state instanceof Sign)) { return false; } return true; } public static Sign getSign(World world, Vector3i pos) { if (pos == null) { return null; } // Don't load chunks to update signs if (!world.isChunkLoaded(pos.getX() >> 4, pos.getZ() >> 4)) { return null; } return getSign(VecHelper.toLocation(world, pos)); } public static Sign getSign(Location location) { if (location == null) { return null; } final Block block = location.getBlock(); final BlockState state = block.getState(); if (!(state instanceof Sign)) { return null; } return (Sign) state; } public static void setClaimForSale(Claim claim, Player player, Sign sign, double price) { if (claim.isWilderness()) { GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().ECONOMY_CLAIM_NOT_FOR_SALE); return; } // if not owner of claim, validate perms if (((GDClaim) claim).allowEdit(player) != null || !player.hasPermission(GDPermissions.COMMAND_CLAIM_INFO_OTHERS)) { TextAdapter.sendComponent(player, MessageCache.getInstance().CLAIM_NOT_YOURS); return; } final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_SALE_CONFIRMATION, ImmutableMap.of( "amount", price)); GriefDefenderPlugin.sendMessage(player, message); final Component saleConfirmationText = TextComponent.builder("") .append("\n[") .append("Confirm", TextColor.GREEN) .append("]\n") .clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(createSaleConfirmationConsumer(player, claim, sign, price)))) .build(); GriefDefenderPlugin.sendMessage(player, saleConfirmationText); } private static Consumer<CommandSender> createSaleConfirmationConsumer(CommandSender src, Claim claim, Sign sign, double price) { return confirm -> { claim.getEconomyData().setSalePrice(price); claim.getEconomyData().setForSale(true); claim.getEconomyData().setSaleSignPosition(VecHelper.toVector3i(sign.getLocation())); claim.getData().save(); List<String> lines = new ArrayList<>(4); lines.add(ChatColor.translateAlternateColorCodes('&', "&7[&bGD&7-&1sell&7]")); lines.add(ChatColor.translateAlternateColorCodes('&', LegacyComponentSerializer.legacy().serialize(MessageCache.getInstance().ECONOMY_SIGN_SELL_DESCRIPTION))); lines.add(ChatColor.translateAlternateColorCodes('&', "&4$" + String.format("%.2f", price))); lines.add(ChatColor.translateAlternateColorCodes('&', LegacyComponentSerializer.legacy().serialize(MessageCache.getInstance().ECONOMY_SIGN_SELL_FOOTER))); for (int i = 0; i < lines.size(); i++) { sign.setLine(i, lines.get(i)); } sign.update(); final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_SALE_CONFIRMED, ImmutableMap.of("amount", price)); GriefDefenderPlugin.sendMessage(src, message); }; } public static void setClaimForRent(Claim claim, Player player, Sign sign, double rate, int min, int max, PaymentType paymentType) { // if not owner of claim, validate perms if (((GDClaim) claim).allowEdit(player) != null || !player.hasPermission(GDPermissions.COMMAND_CLAIM_INFO_OTHERS)) { TextAdapter.sendComponent(player, MessageCache.getInstance().CLAIM_NOT_YOURS); return; } if (claim.getEconomyData().isRented()) { // already rented final UUID uuid = claim.getEconomyData().getRenters().get(0); final GDPermissionUser user = PermissionHolderCache.getInstance().getOrCreateUser(uuid); final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_RENTED_ALREADY, ImmutableMap.of( "player", user.getName())); GriefDefenderPlugin.sendMessage(player, message); return; } Duration duration = null; Component message = null; Component maxTime = null; Component minTime = null; Instant endDate = max > 0 ? Instant.now().plus(max, paymentType == PaymentType.DAILY ? ChronoUnit.DAYS : ChronoUnit.HOURS) : null; if (max > 0) { duration = Duration.between(Instant.now(), endDate); final long seconds = duration.getSeconds(); final int day = (int)TimeUnit.SECONDS.toDays(seconds); final long hours = TimeUnit.SECONDS.toHours(seconds) - (day *24); final long minutes = TimeUnit.SECONDS.toMinutes(seconds) - (TimeUnit.SECONDS.toHours(seconds)* 60); TextComponent.Builder maxBuilder = TextComponent.builder(); if (day > 0) { maxBuilder.append(String.valueOf(day)) .append(" ") .append((day > 1 ? MessageCache.getInstance().LABEL_DAYS : MessageCache.getInstance().LABEL_DAY)) .append(" "); } if (hours > 0) { maxBuilder.append(String.valueOf(hours)) .append(" ") .append((hours > 1 ? MessageCache.getInstance().LABEL_HOURS : MessageCache.getInstance().LABEL_HOUR)) .append(" "); } if (minutes > 0) { maxBuilder.append(String.valueOf(minutes)) .append(" ") .append((minutes > 1 ? MessageCache.getInstance().LABEL_MINUTES : MessageCache.getInstance().LABEL_MINUTE)) .append(" "); } maxTime = maxBuilder.build(); } if (min > 0) { minTime = TextComponent.builder() .append(String.valueOf(min)) .append(" ") .append(claim.getEconomyData().getPaymentType() == PaymentType.DAILY ? (min > 1 ? MessageCache.getInstance().LABEL_DAYS : MessageCache.getInstance().LABEL_DAY) : (min > 1 ? MessageCache.getInstance().LABEL_HOURS : MessageCache.getInstance().LABEL_HOUR)) .build(); } if (min <= 0 && max <= 0) { message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_RENT_CONFIRMATION, ImmutableMap.of( "amount", "$" + String.format("%.2f", rate), "type", paymentType == PaymentType.DAILY ? MessageCache.getInstance().LABEL_DAY : MessageCache.getInstance().LABEL_HOUR)); } else if (min > 0 && max <= 0) { message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_RENT_CONFIRMATION_MIN, ImmutableMap.of( "amount", "$" + String.format("%.2f",rate), "type", paymentType == PaymentType.DAILY ? MessageCache.getInstance().LABEL_DAY : MessageCache.getInstance().LABEL_HOUR, "min-time", minTime)); } else if (min <= 0 && max > 0) { message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_RENT_CONFIRMATION_MAX, ImmutableMap.of( "amount", "$" + String.format("%.2f",rate), "type", paymentType == PaymentType.DAILY ? MessageCache.getInstance().LABEL_DAY : MessageCache.getInstance().LABEL_HOUR, "max-time", maxTime)); } else if (min > 0 && max > 0) { message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_RENT_CONFIRMATION_MIN_MAX, ImmutableMap.of( "amount", "$" + String.format("%.2f",rate), "type", paymentType == PaymentType.DAILY ? MessageCache.getInstance().LABEL_DAY : MessageCache.getInstance().LABEL_HOUR, "min-time", minTime, "max-time", maxTime)); } GriefDefenderPlugin.sendMessage(player, message); final Component rentConfirmationText = TextComponent.builder("") .append("\n[") .append(MessageCache.getInstance().LABEL_CONFIRM.color(TextColor.GREEN)) .append("]\n") .clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(player, createRentConfirmationConsumer(player, claim, sign, rate, min, max, paymentType), true))) .build(); GriefDefenderPlugin.sendMessage(player, rentConfirmationText); } private static Consumer<CommandSender> createRentConfirmationConsumer(CommandSender src, Claim claim, Sign sign, double rate, int min, int max, PaymentType paymentType) { return confirm -> { resetRentData(claim); claim.getEconomyData().setRentRate(rate); claim.getEconomyData().setPaymentType(paymentType); if (min > 0) { if (min > max) { claim.getEconomyData().setRentMinTime(max); } else { claim.getEconomyData().setRentMinTime(min); } } if (max > 0) { final int rentMaxLimit = GriefDefenderPlugin.getActiveConfig(((GDClaim) claim).getWorld()).getConfig().economy.rentMaxTimeLimit; if (max > rentMaxLimit) { claim.getEconomyData().setRentMaxTime(rentMaxLimit); } else { claim.getEconomyData().setRentMaxTime(max); } claim.getEconomyData().setRentEndDate(Instant.now().plus(max, paymentType == PaymentType.DAILY ? ChronoUnit.DAYS : ChronoUnit.HOURS)); } claim.getEconomyData().setForRent(true); Sign rentSign = sign; if (rentSign == null) { rentSign = SignUtil.getSign(((GDClaim) claim).getWorld(), claim.getEconomyData().getRentSignPosition()); } if (rentSign != null) { claim.getEconomyData().setRentSignPosition(VecHelper.toVector3i(sign.getLocation())); claim.getData().save(); List<String> lines = new ArrayList<>(4); lines.add(ChatColor.translateAlternateColorCodes('&', "&7[&bGD&7-&1rent&7]")); lines.add(ChatColor.translateAlternateColorCodes('&', LegacyComponentSerializer.legacy().serialize(MessageCache.getInstance().ECONOMY_SIGN_RENT_DESCRIPTION))); lines.add(ChatColor.translateAlternateColorCodes('&', "&4$" + String.format("%.2f", rate) + "/" + LegacyComponentSerializer.legacy().serialize((paymentType == PaymentType.DAILY ? MessageCache.getInstance().LABEL_DAY : MessageCache.getInstance().LABEL_HOUR)))); for (int i = 0; i < lines.size(); i++) { sign.setLine(i, lines.get(i)); } sign.update(); } final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_RENT_CONFIRMED, ImmutableMap.of( "amount", "$" + rate, "type", paymentType == PaymentType.DAILY ? MessageCache.getInstance().LABEL_DAY : MessageCache.getInstance().LABEL_HOUR)); GriefDefenderPlugin.sendMessage(src, message); }; } public static void updateSignRentable(Claim claim, Sign sign) { if (!isRentSign(claim, sign)) { return; } final PaymentType paymentType = claim.getEconomyData().getPaymentType(); List<String> colorLines = new ArrayList<>(4); colorLines.add(ChatColor.translateAlternateColorCodes('&', "&7[&bGD&7-&1rent&7]")); colorLines.add(ChatColor.translateAlternateColorCodes('&', LegacyComponentSerializer.legacy().serialize(MessageCache.getInstance().ECONOMY_SIGN_RENT_DESCRIPTION))); colorLines.add(ChatColor.translateAlternateColorCodes('&', "&4$" + claim.getEconomyData().getRentRate())); for (int i = 0; i < colorLines.size(); i++) { sign.setLine(i, colorLines.get(i)); } sign.update(); } public static int getRentMinTime(String line) { if (line == null || line.isEmpty() && !line.matches(".*\\d.*")) { return 0; } // check if spaces String[] split = line.split(" "); String min = null; if (split[0].contains("max")) { return 0; } min = split[0].replace("min", ""); Integer rentMin = null; try { rentMin = Integer.valueOf(min); } catch (NumberFormatException e) { return 0; } return rentMin; } public static int getRentMaxTime(String line) { if (line == null || line.isEmpty() && !line.matches(".*\\d.*")) { return 0; } // check if spaces String[] split = line.split(" "); String max = null; if (split.length == 1) { if (split[0].contains("min") && !split[0].contains("max")) { return 0; } max = split[0].replace("max", ""); } else { max = split[1].replace("max", ""); } Integer rentMax = null; try { rentMax = Integer.valueOf(max); } catch (NumberFormatException e) { return 0; } return rentMax; } public static PaymentType getPaymentType(String line) { final String strType = line.substring(line.length() - 1); PaymentType paymentType = PaymentType.UNDEFINED; if (strType.equalsIgnoreCase("d")) { paymentType = PaymentType.DAILY; } else if(strType.equalsIgnoreCase("h")) { paymentType = PaymentType.HOURLY; } return paymentType; } public static void resetRentData(Claim claim) { claim.getEconomyData().setForRent(false); claim.getEconomyData().setRentStartDate(null); claim.getEconomyData().setRentEndDate(null); claim.getEconomyData().setRentSignPosition(null); claim.getEconomyData().setRentPastDueDate(null); claim.getEconomyData().setRentMaxTime(0); claim.getEconomyData().setRentMinTime(0); claim.getEconomyData().getRenters().clear(); } public static void resetSellData(Claim claim) { claim.getEconomyData().setForSale(false); claim.getEconomyData().setSaleEndDate(null); claim.getEconomyData().setSalePrice(-1); claim.getEconomyData().setSaleSignPosition(null); } }