GriefDefender/bukkit/src/main/java/com/griefdefender/command/CommandHelper.java

1415 lines
76 KiB
Java

/*
* This file is part of GriefDefender, licensed under the MIT License (MIT).
*
* Copyright (c) bloodmc
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.griefdefender.command;
import java.time.Duration;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World.Environment;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.plugin.Plugin;
import com.flowpowered.math.vector.Vector3i;
import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.griefdefender.GDPlayerData;
import com.griefdefender.GriefDefenderPlugin;
import com.griefdefender.api.GriefDefender;
import com.griefdefender.api.Subject;
import com.griefdefender.api.Tristate;
import com.griefdefender.api.claim.Claim;
import com.griefdefender.api.claim.ClaimContexts;
import com.griefdefender.api.claim.ClaimResult;
import com.griefdefender.api.claim.TrustType;
import com.griefdefender.api.claim.TrustTypes;
import com.griefdefender.api.economy.PaymentTransaction;
import com.griefdefender.api.economy.PaymentType;
import com.griefdefender.api.economy.TransactionResultType;
import com.griefdefender.api.economy.TransactionType;
import com.griefdefender.api.permission.Context;
import com.griefdefender.api.permission.ContextKeys;
import com.griefdefender.api.permission.PermissionResult;
import com.griefdefender.api.permission.ResultTypes;
import com.griefdefender.api.permission.flag.Flag;
import com.griefdefender.api.permission.flag.Flags;
import com.griefdefender.api.permission.option.Option;
import com.griefdefender.api.permission.option.Options;
import com.griefdefender.api.permission.option.type.CreateModeTypes;
import com.griefdefender.cache.MessageCache;
import com.griefdefender.cache.PermissionHolderCache;
import com.griefdefender.claim.GDClaim;
import com.griefdefender.configuration.GriefDefenderConfig;
import com.griefdefender.configuration.MessageStorage;
import com.griefdefender.economy.GDPaymentTransaction;
import com.griefdefender.event.GDCauseStackManager;
import com.griefdefender.internal.pagination.PaginationList;
import com.griefdefender.internal.registry.BlockTypeRegistryModule;
import com.griefdefender.internal.registry.EntityTypeRegistryModule;
import com.griefdefender.internal.registry.ItemTypeRegistryModule;
import com.griefdefender.internal.util.NMSUtil;
import com.griefdefender.internal.util.VecHelper;
import com.griefdefender.internal.visual.GDClaimVisual;
import com.griefdefender.permission.GDPermissionHolder;
import com.griefdefender.permission.GDPermissionManager;
import com.griefdefender.permission.GDPermissionResult;
import com.griefdefender.permission.GDPermissionUser;
import com.griefdefender.permission.GDPermissions;
import com.griefdefender.permission.flag.GDFlag;
import com.griefdefender.permission.ui.MenuType;
import com.griefdefender.permission.ui.UIHelper;
import com.griefdefender.text.action.GDCallbackHolder;
import com.griefdefender.util.EconomyUtil;
import com.griefdefender.util.PermissionUtil;
import com.griefdefender.util.PlayerUtil;
import com.griefdefender.util.TaskUtil;
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.event.HoverEvent;
import net.kyori.text.format.TextColor;
import net.kyori.text.format.TextDecoration;
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.text.serializer.plain.PlainComponentSerializer;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
public class CommandHelper {
public static Comparator<Component> PLAIN_COMPARATOR = (text1, text2) -> PlainComponentSerializer.INSTANCE.serialize(text1).compareTo(PlainComponentSerializer.INSTANCE.serialize(text2));
public static Player checkPlayer(CommandSender source) {
if (source instanceof Player) {
return ((Player) source);
} else {
return null;
}
}
public static boolean validateFlagTarget(Flag flag, String target) {
if (!(flag instanceof GDFlag)) {
return true;
}
if (flag == Flags.BLOCK_BREAK || flag == Flags.BLOCK_PLACE || flag == Flags.COLLIDE_BLOCK) {
if (validateBlockTarget(target) ||
validateItemTarget(target)) {
return true;
}
return false;
}
if (flag == Flags.ENTER_CLAIM || flag == Flags.EXIT_CLAIM || flag == Flags.ENTITY_RIDING ||
flag == Flags.ENTITY_DAMAGE || flag == Flags.PORTAL_USE) {
if (validateEntityTarget(target) ||
validateBlockTarget(target) ||
validateItemTarget(target)) {
return true;
}
return false;
}
if (flag == Flags.INTERACT_INVENTORY) {
// Always return true due to custom inventories
return true;
}
if (flag == Flags.LIQUID_FLOW || flag == Flags.INTERACT_BLOCK_PRIMARY
|| flag == Flags.INTERACT_BLOCK_SECONDARY) {
return validateBlockTarget(target);
}
if (flag == Flags.ENTITY_CHUNK_SPAWN || flag == Flags.ENTITY_SPAWN ||
flag == Flags.INTERACT_ENTITY_PRIMARY || flag == Flags.INTERACT_ENTITY_SECONDARY) {
return validateEntityTarget(target);
}
if (flag == Flags.ITEM_DROP|| flag == Flags.ITEM_PICKUP ||
flag == Flags.ITEM_SPAWN || flag == Flags.ITEM_USE) {
return validateItemTarget(target);
}
return true;
}
private static boolean validateEntityTarget(String target) {
if (EntityTypeRegistryModule.getInstance().getById(target).isPresent()) {
return true;
}
return false;
}
private static boolean validateItemTarget(String target) {
if (ItemTypeRegistryModule.getInstance().getById(target).isPresent()) {
return true;
}
// target could be an item block, so validate blockstate
//if (BlockTypeRegistryModule.getInstance().getById(target).isPresent()) {
// return true;
//}
return false;
}
private static boolean validateBlockTarget(String target) {
if (BlockTypeRegistryModule.getInstance().getById(target).isPresent()) {
return true;
}
return false;
}
public static PermissionResult addFlagPermission(CommandSender src, GDPermissionHolder subject, Claim claim, Flag flag, String target, Tristate value, Set<Context> contexts) {
if (src instanceof Player) {
Component denyReason = ((GDClaim) claim).allowEdit((Player) src);
if (denyReason != null) {
GriefDefenderPlugin.sendMessage(src, denyReason);
return new GDPermissionResult(ResultTypes.NO_PERMISSION);
}
if (value == null) {
GriefDefenderPlugin.sendMessage(src, MessageCache.getInstance().COMMAND_INVALID);
return new GDPermissionResult(ResultTypes.FAILURE);
}
}
// special handling for commands
target = adjustTargetForTypes(target, flag);
if (flag == Flags.COMMAND_EXECUTE || flag == Flags.COMMAND_EXECUTE_PVP) {
target = handleCommandFlag(src, target);
if (target == null) {
// failed
return new GDPermissionResult(ResultTypes.TARGET_NOT_VALID);
}
} else {
if (!target.equalsIgnoreCase("any")) {
if (!target.startsWith("#") && !target.contains(":")) {
// assume vanilla
target = "minecraft:" + target;
}
String[] parts = target.split(":");
if (parts.length == 1) {
addFlagContexts(contexts, flag, target);
} else if (parts.length > 1 && !parts[1].equalsIgnoreCase("any")) {
addFlagContexts(contexts, flag, target);
if (!target.contains("#") && !CommandHelper.validateFlagTarget(flag, target)) {
return new GDPermissionResult(ResultTypes.TARGET_NOT_VALID);
}
}
} else {
target = "";
}
}
return applyFlagPermission(src, subject, claim, flag, target, value, contexts, null, false);
}
public static PermissionResult applyFlagPermission(CommandSender src, GDPermissionHolder subject, Claim claim, Flag flag, String target, Tristate value, Set<Context> contexts, MenuType flagType) {
return applyFlagPermission(src, subject, claim, flag, target, value, contexts, flagType, false);
}
public static PermissionResult applyFlagPermission(CommandSender src, GDPermissionHolder subject, Claim claim, Flag flag, String target, Tristate value, Set<Context> contexts, MenuType flagType, boolean clicked) {
boolean hasDefaultContext = false;
boolean hasOverrideContext = false;
boolean replaceOverrideContext = false;
Component reason = null;
Iterator<Context> iterator = contexts.iterator();
while (iterator.hasNext()) {
final Context context = iterator.next();
// validate perms
if (context.getKey().equalsIgnoreCase("reason")) {
reason = LegacyComponentSerializer.legacy().deserialize(context.getValue(), '&');
iterator.remove();
continue;
}
if (hasDefaultContext || hasOverrideContext) {
continue;
}
if (context.getKey().contains("gd_claim_default")) {
hasDefaultContext = true;
} else if (context.getKey().contains("gd_claim_override")) {
if (context.getValue().equalsIgnoreCase("claim")) {
iterator.remove();
replaceOverrideContext = true;
}
hasOverrideContext = true;
}
}
if (replaceOverrideContext) {
contexts.add(new Context(ContextKeys.CLAIM_OVERRIDE, claim.getUniqueId().toString()));
}
// Add target context
if (target != null && !target.isEmpty() && !target.equalsIgnoreCase("any")) {
contexts.add(new Context("target", target));
}
if (flagType == null) {
if (hasDefaultContext) {
flagType = MenuType.DEFAULT;
} else if (hasOverrideContext) {
flagType = MenuType.OVERRIDE;
} else {
flagType = MenuType.CLAIM;
}
}
TextComponent.Builder builder = null;
if (flagType == MenuType.OVERRIDE) {
builder = TextComponent.builder("OVERRIDE").color(TextColor.RED);
} else if (flagType == MenuType.DEFAULT) {
builder = TextComponent.builder("DEFAULT").color(TextColor.LIGHT_PURPLE);
} else if (flagType == MenuType.CLAIM) {
builder = TextComponent.builder("CLAIM").color(TextColor.GOLD);
if (contexts instanceof HashSet) {
contexts.add(claim.getContext());
}
}
Component flagTypeText = builder.build();
if (contexts.isEmpty()) {
// default to claim
contexts.add(claim.getContext());
}
// wilderness overrides affect all worlds
if (!contexts.contains(ClaimContexts.WILDERNESS_OVERRIDE_CONTEXT) && !contexts.contains(claim.getContext())) {
if (contexts instanceof HashSet) {
//contexts.add(claim.getWorld().getContext());
}
}
// Check if player can manage flag with contexts
if (src instanceof Player) {
final GDPermissionUser sourceUser = PermissionHolderCache.getInstance().getOrCreateUser(((Player) src));
final Tristate result = PermissionUtil.getInstance().getPermissionValue(sourceUser, GDPermissions.USER_CLAIM_FLAGS + "." + flag.getName().toLowerCase(), contexts);
if (result != Tristate.TRUE) {
GriefDefenderPlugin.sendMessage(src, MessageCache.getInstance().PERMISSION_FLAG_USE);
return new GDPermissionResult(ResultTypes.NO_PERMISSION);
}
}
if (subject == GriefDefenderPlugin.DEFAULT_HOLDER) {
if (flagType == MenuType.OVERRIDE) {
PermissionUtil.getInstance().setPermissionValue(GriefDefenderPlugin.GD_OVERRIDE_HOLDER, flag, value, contexts);
} else if (flagType == MenuType.CLAIM) {
PermissionUtil.getInstance().setPermissionValue(GriefDefenderPlugin.GD_CLAIM_HOLDER, flag, value, contexts);
} else {
PermissionUtil.getInstance().setPermissionValue(GriefDefenderPlugin.GD_DEFAULT_HOLDER, flag, value, contexts);
}
if (!clicked && src instanceof Player) {
TextAdapter.sendComponent(src, TextComponent.builder("")
.append(TextComponent.builder("\n[").append(MessageCache.getInstance().FLAG_UI_RETURN_FLAGS.color(TextColor.AQUA)).append("]\n")
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(createCommandConsumer(src, "claimflag", "")))).build())
.append(MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.FLAG_SET_PERMISSION_TARGET,
ImmutableMap.of(
"type", flagTypeText,
"permission", flag.getPermission(),
"contexts", getFriendlyContextString(claim, contexts),
"value", getClickableText(src, (GDClaim) claim, subject, contexts, flag, value, flagType).color(TextColor.LIGHT_PURPLE),
"target", MessageCache.getInstance().TITLE_ALL)))
.build());
}
} else {
PermissionUtil.getInstance().setPermissionValue(subject, flag, value, contexts);
if (!clicked && src instanceof Player) {
TextAdapter.sendComponent(src, TextComponent.builder("")
.append(TextComponent.builder("")
.append("\n[")
.append(MessageCache.getInstance().FLAG_UI_RETURN_FLAGS.color(TextColor.AQUA))
.append("]\n", TextColor.WHITE)
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(createCommandConsumer(src, subject instanceof GDPermissionUser ? "claimflagplayer" : "claimflaggroup", subject.getFriendlyName())))).build())
.append(MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.FLAG_SET_PERMISSION_TARGET,
ImmutableMap.of(
"type", flagTypeText,
"permission", flag.getPermission(),
"contexts", getFriendlyContextString(claim, contexts),
"value", getClickableText(src, (GDClaim) claim, subject, contexts, flag, value, flagType).color(TextColor.LIGHT_PURPLE),
"target", subject.getFriendlyName())))
.build());
}
}
return new GDPermissionResult(ResultTypes.SUCCESS);
}
public static String adjustTargetForTypes(String target, Flag flag) {
if (target.equals("player") || target.equals("minecraft:player") || target.equalsIgnoreCase("any")) {
return target;
}
if (flag.getName().contains("entity") || flag == Flags.ITEM_SPAWN) {
final String contextKey = "target";
String[] parts = target.split(":");
String targetId = "";
if (parts.length == 1) {
targetId = parts[0];
} else {
targetId = parts[1];
}
if (targetId.equalsIgnoreCase("animal")) {
return "#animal";
} else if (targetId.equalsIgnoreCase("aquatic")) {
return "#aquatic";
} else if (targetId.equalsIgnoreCase("monster")) {
return "#monster";
} else if (targetId.equalsIgnoreCase("ambient")) {
return "#ambient";
}
return target;
} else {
if ((target.equals("food") || target.endsWith(":food")) && !target.startsWith("#")) {
target = "#" + target;
}
}
return target;
}
public static void addFlagContexts(Set<Context> contexts, Flag flag, String target) {
if (target.equals("player") || target.equals("minecraft:player") || target.equalsIgnoreCase("any")) {
return;
}
if (flag.getName().contains("entity") || flag == Flags.ITEM_SPAWN) {
final String contextKey = "target";
String[] parts = target.split(":");
if (parts.length == 1) {
contexts.add(new Context(contextKey, target));
return;
}
if (parts[1].equalsIgnoreCase("animal")) {
contexts.add(new Context(contextKey, "#animal"));
} else if (parts[1].equalsIgnoreCase("aquatic")) {
contexts.add(new Context(contextKey, "#aquatic"));
} else if (parts[1].equalsIgnoreCase("monster")) {
contexts.add(new Context(contextKey, "#monster"));
} else if (parts[1].equalsIgnoreCase("ambient")) {
contexts.add(new Context(contextKey, "#ambient"));
} else {
contexts.add(new Context(contextKey, target));
}
}
}
public static Component getFriendlyContextString(Claim claim, Set<Context> contexts) {
if (contexts.isEmpty()) {
return TextComponent.of("[]", TextColor.WHITE);
}
TextComponent.Builder builder = TextComponent.builder();
final Iterator<Context> iterator = contexts.iterator();
while (iterator.hasNext()) {
final Context context = iterator.next();
builder.append("\n[", TextColor.WHITE)
.append(context.getKey(), TextColor.GREEN)
.append("=", TextColor.GRAY)
.append(context.getValue(), TextColor.WHITE);
if (iterator.hasNext()) {
builder.append("], ");
} else {
builder.append("]");
}
}
return builder.build();
}
public static TextColor getPermissionMenuTypeColor(MenuType type) {
TextColor color = TextColor.LIGHT_PURPLE;
if (type == MenuType.CLAIM) {
color = TextColor.GOLD;
} else if (type == MenuType.OVERRIDE) {
color = TextColor.RED;
}
return color;
}
public static Consumer<CommandSender> createFlagConsumer(CommandSender src, GDClaim claim, Subject subject, Set<Context> contexts, Flag flag, Tristate flagValue, MenuType flagType) {
return consumer -> {
Tristate newValue = Tristate.UNDEFINED;
if (flagValue == Tristate.TRUE) {
newValue = Tristate.FALSE;
} else if (flagValue == Tristate.UNDEFINED) {
newValue = Tristate.TRUE;
}
Component flagTypeText = TextComponent.empty();
if (flagType == MenuType.OVERRIDE) {
flagTypeText = TextComponent.of("OVERRIDE", TextColor.RED);
} else if (flagType == MenuType.DEFAULT) {
flagTypeText = TextComponent.of("DEFAULT", TextColor.LIGHT_PURPLE);
} else if (flagType == MenuType.CLAIM) {
flagTypeText = TextComponent.of("CLAIM", TextColor.GOLD);
}
Set<Context> newContexts = new HashSet<>(contexts);
PermissionUtil.getInstance().setPermissionValue(GriefDefenderPlugin.DEFAULT_HOLDER, flag, newValue, newContexts);
TextAdapter.sendComponent(src, TextComponent.builder("")
.append("Set ", TextColor.GREEN)
.append(flagTypeText)
.append(" permission ")
.append(flag.getName().toLowerCase(), TextColor.AQUA)
.append("\n to ", TextColor.GREEN)
.append(getClickableText(src, (GDClaim) claim, subject, newContexts, flag, newValue, flagType).color(TextColor.LIGHT_PURPLE))
.append(" for ", TextColor.GREEN)
.append(subject.getFriendlyName(), TextColor.GOLD).build());
};
}
public static Consumer<CommandSender> createCommandConsumer(CommandSender src, String command, String arguments) {
return createCommandConsumer(src, command, arguments, null);
}
public static Consumer<CommandSender> createCommandConsumer(CommandSender src, String command, String arguments, Consumer<CommandSender> postConsumerTask) {
return consumer -> {
if (!NMSUtil.getInstance().getBukkitCommandMap().dispatch(src, command + " " + arguments)) {
TextAdapter.sendComponent(src, MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.COMMAND_EXECUTE_FAILED,
ImmutableMap.of(
"command", command,
"args", arguments)));
}
if (postConsumerTask != null) {
postConsumerTask.accept(src);
}
};
}
public static void executeCommand(CommandSender src, String command, String arguments) {
if (!NMSUtil.getInstance().getBukkitCommandMap().dispatch(src, command + " " + arguments)) {
TextAdapter.sendComponent(src, MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.COMMAND_EXECUTE_FAILED,
ImmutableMap.of(
"command", command,
"args", arguments)));
}
}
public static void showClaims(CommandSender src, Set<Claim> claims) {
if (claims.isEmpty()) {
// do nothing
return;
}
showClaims(src, claims, 0, false);
}
public static void showOverlapClaims(CommandSender src, Set<Claim> claims, int height) {
showClaims(src, claims, height, true, true);
}
public static void showClaims(CommandSender src, Set<Claim> claims, int height, boolean visualizeClaims) {
showClaims(src, claims, height, visualizeClaims, false);
}
public static void showClaims(CommandSender src, Set<Claim> claims, int height, boolean visualizeClaims, boolean overlap) {
final String worldName = src instanceof Player ? ((Player) src).getWorld().getName() : Bukkit.getWorlds().get(0).getName();
List<Component> claimsTextList = generateClaimTextList(new ArrayList<Component>(), claims, worldName, null, src, createShowClaimsConsumer(src, claims, height, visualizeClaims), false, overlap, false);
if (visualizeClaims && src instanceof Player) {
Player player = (Player) src;
final GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(player.getWorld(), player.getUniqueId());
final boolean hideBorders = GriefDefenderPlugin.getInstance().getWorldEditProvider() != null &&
GriefDefenderPlugin.getInstance().getWorldEditProvider().hasCUISupport(player) &&
GriefDefenderPlugin.getActiveConfig(player.getWorld().getUID()).getConfig().visual.hideBorders;
if (claims.size() > 1) {
if (!hideBorders) {
if (height != 0) {
height = playerData.lastValidInspectLocation != null ? playerData.lastValidInspectLocation.getBlockY() : player.getEyeLocation().getBlockY();
}
for (Claim claim : claims) {
GDClaimVisual visualization = GDClaimVisual.fromClaim(claim, playerData.getClaimCreateMode() == CreateModeTypes.VOLUME ? height : player.getEyeLocation().getBlockY(), player.getLocation(), playerData, null);
visualization.apply(player);
}
}
if (GriefDefenderPlugin.getInstance().getWorldEditProvider() != null) {
GriefDefenderPlugin.getInstance().getWorldEditProvider().visualizeClaims(claims, player, playerData, true);
}
} else {
if (!hideBorders) {
for (Claim claim : claims) {
GDClaim gdClaim = (GDClaim) claim;
final GDClaimVisual visual = gdClaim.getVisualizer();
if (visual.getVisualTransactions().isEmpty()) {
visual.createClaimBlockVisuals(height, player.getLocation(), playerData);
}
visual.apply(player);
}
}
if (GriefDefenderPlugin.getInstance().getWorldEditProvider() != null) {
GriefDefenderPlugin.getInstance().getWorldEditProvider().visualizeClaims(claims, player, playerData, true);
}
}
}
if (!claimsTextList.isEmpty()) {
PaginationList.Builder builder = PaginationList.builder().title(MessageCache.getInstance().CLAIMLIST_UI_TITLE.color(TextColor.RED)).padding(TextComponent.builder(" ").decoration(TextDecoration.STRIKETHROUGH, true).build()).contents(claimsTextList);
builder.sendTo(src);
}
}
private static Consumer<CommandSender> createShowClaimsConsumer(CommandSender src, Set<Claim> claims, int height, boolean visualizeClaims) {
return consumer -> {
showClaims(src, claims, height, visualizeClaims);
};
}
public static List<Component> generateClaimTextListCommand(List<Component> claimsTextList, Set<Claim> claimList, String worldName, GDPermissionUser user, CommandSender src, Consumer<CommandSender> returnCommand, boolean listChildren) {
return generateClaimTextList(claimsTextList, claimList, worldName, user, src, returnCommand, listChildren, false, true);
}
public static List<Component> generateClaimTextList(List<Component> claimsTextList, Set<Claim> claimList, String worldName, GDPermissionUser user, CommandSender src, Consumer<CommandSender> returnCommand, boolean listChildren) {
return generateClaimTextList(claimsTextList, claimList, worldName, user, src, returnCommand, listChildren, false, false);
}
public static List<Component> generateClaimTextList(List<Component> claimsTextList, Set<Claim> claimList, String worldName, GDPermissionUser user, CommandSender src, Consumer<CommandSender> returnCommand, boolean listChildren, boolean overlap, boolean listCommand) {
if (claimList.size() > 0) {
final Player player = src instanceof Player ? (Player) src : null;
for (Claim playerClaim : claimList) {
GDClaim claim = (GDClaim) playerClaim;
if (player != null && claim.getEconomyData() != null && !claim.getEconomyData().isForSale()
&& !claim.getEconomyData().isForRent() && (claim.allowEdit(player) != null && !claim.isUserTrusted(player, TrustTypes.ACCESSOR))) {
continue;
}
if (!listCommand && !overlap && !listChildren && (claim.isSubdivision() && claimList.size() > 1)
&& claim.getEconomyData() != null && !claim.getEconomyData().isForSale() && !claim.getEconomyData().isForRent()) {
continue;
}
double teleportHeight = claim.getOwnerPlayerData() == null ? 65.0D : (claim.getOwnerMinClaimLevel() > 65.0D ? claim.getOwnerMinClaimLevel() : 65);
Vector3i lesserPos = claim.lesserBoundaryCorner;
Vector3i greaterPos = claim.greaterBoundaryCorner;
Vector3i center = claim.lesserBoundaryCorner.add(lesserPos.getX(), lesserPos.getY(), lesserPos.getZ()).div(2);
Vector3i newCenter = new Vector3i(center.getX(), teleportHeight, center.getZ());
Vector3i southWest = new Vector3i(newCenter.getX(), newCenter.getY(), newCenter.getZ());
//final double teleportHeight = claim.getOwnerPlayerData() == null ? 65.0D : (claim.getOwnerPlayerData().getMinClaimLevel() > 65.0D ? claim.getOwnerPlayerData().getMinClaimLevel() : 65);
//Location<World> southWest = claim.lesserBoundaryCorner.setPosition(new Vector3d(claim.lesserBoundaryCorner.getPosition().getX(), teleportHeight, claim.greaterBoundaryCorner.getPosition().getZ()));
Component claimName = claim.getData().getName().orElse(TextComponent.empty());
Component teleportName = claim.getData().getName().orElse(claim.getFriendlyNameType());
Component ownerLine = TextComponent.builder()
.append(MessageCache.getInstance().LABEL_OWNER.color(TextColor.YELLOW))
.append(" : ", TextColor.WHITE)
.append(claim.getOwnerDisplayName().color(TextColor.GOLD))
.append("\n").build();
Component claimTypeInfo = TextComponent.builder("Type").color(TextColor.YELLOW)
.append(" : ", TextColor.WHITE)
.append(claim.getFriendlyNameType())
.append(" ")
.append(claim.isCuboid() ? "3D " : "2D ", TextColor.GRAY)
.append(" (")
.append(MessageCache.getInstance().LABEL_AREA)
.append(": ", TextColor.WHITE)
.append(String.valueOf(claim.getClaimBlocks()), TextColor.GRAY)
.append(" blocks)\n", TextColor.WHITE).build();
Component clickInfo = MessageCache.getInstance().CLAIMLIST_UI_CLICK_INFO;
Component basicInfo = TextComponent.builder("")
.append(ownerLine)
.append(claimTypeInfo)
.append(clickInfo).build();
Component claimInfoCommandClick = TextComponent.builder("")
.append(claim.getFriendlyNameType())
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(CommandHelper.createCommandConsumer(src, "claiminfo", claim.getUniqueId().toString(), createReturnClaimListConsumer(src, returnCommand)))))
.hoverEvent(HoverEvent.showText(basicInfo)).build();
Component claimSpawn = null;
if (player !=null && PermissionUtil.getInstance().canPlayerTeleport(player, claim)) {
final Vector3i spawnPos = claim.getData().getSpawnPos().orElse(null);
if (spawnPos != null) {
Location spawnLoc = new Location(claim.getWorld(), spawnPos.getX(), spawnPos.getY(), spawnPos.getZ());
claimSpawn = TextComponent.builder("")
.append("[")
.append("TP", TextColor.LIGHT_PURPLE)
.append("]")
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(CommandHelper.createTeleportConsumer(src, spawnLoc, claim, true))))
.hoverEvent(HoverEvent.showText(MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.CLAIMLIST_UI_CLICK_TELEPORT_TARGET,
ImmutableMap.of(
"name", teleportName,
"target", "'s spawn @ " + spawnPos.toString(),
"world", claim.getWorld().getName()))))
.build();
} else {
claimSpawn = TextComponent.builder("")
.append("[")
.append("TP", TextColor.LIGHT_PURPLE)
.append("]")
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(CommandHelper.createTeleportConsumer(src, VecHelper.toLocation(claim.getWorld(), southWest), claim))))
.hoverEvent(HoverEvent.showText(MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.CLAIMLIST_UI_CLICK_TELEPORT_TARGET,
ImmutableMap.of(
"name", teleportName,
"target", southWest.toString(),
"world", claim.getWorld().getName()))))
.build();
}
}
List<Component> childrenTextList = new ArrayList<>();
if (!listChildren) {
childrenTextList = generateClaimTextList(new ArrayList<Component>(), claim.getChildren(true), worldName, user, src, returnCommand, true);
}
Component buyClaim = TextComponent.empty();
if (player != null && claim.getEconomyData().isForSale() && claim.getEconomyData().getSalePrice() > -1) {
Component buyInfo = TextComponent.builder()
.append(MessageCache.getInstance().LABEL_PRICE.color(TextColor.AQUA))
.append(" : ", TextColor.WHITE)
.append(String.valueOf(claim.getEconomyData().getSalePrice()), TextColor.GOLD)
.append("\n")
.append(MessageCache.getInstance().CLAIMLIST_UI_CLICK_PURCHASE).build();
buyClaim = TextComponent.builder()
.append(TextComponent.builder(" [").append(MessageCache.getInstance().LABEL_BUY.color(TextColor.GREEN)).append("]", TextColor.WHITE).build())
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(buyClaimConsumerConfirmation(src, claim))))
.hoverEvent(HoverEvent.showText(player.getUniqueId().equals(claim.getOwnerUniqueId()) ? MessageCache.getInstance().CLAIM_OWNER_ALREADY : buyInfo)).build();
}
Component rentClaim = TextComponent.empty();
if (player != null && claim.getEconomyData().isForRent() && player.hasPermission(GDPermissions.USER_RENT_BASE)) {
Component rentInfo = TextComponent.builder()
.append(MessageCache.getInstance().LABEL_PRICE.color(TextColor.AQUA))
.append(" : ", TextColor.WHITE)
.append(String.valueOf(claim.getEconomyData().getRentRate() + " per " + (claim.getEconomyData().getPaymentType() == PaymentType.DAILY ? "day" : "hour")), TextColor.GOLD)
.append("\n")
.append(MessageCache.getInstance().CLAIMLIST_UI_CLICK_RENT).build();
rentClaim = TextComponent.builder()
.append(TextComponent.builder(" [").append(MessageCache.getInstance().LABEL_RENT.color(TextColor.GREEN)).append("]", TextColor.WHITE).build())
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(EconomyUtil.getInstance().rentClaimConsumerConfirmation(src, claim))))
.hoverEvent(HoverEvent.showText(player.getUniqueId().equals(claim.getOwnerUniqueId()) ? MessageCache.getInstance().CLAIM_OWNER_ALREADY : rentInfo)).build();
}
if (!childrenTextList.isEmpty()) {
Component children = TextComponent.builder("[")
.append(MessageCache.getInstance().LABEL_CHILDREN.color(TextColor.AQUA))
.append("]", TextColor.WHITE)
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(showChildrenList(childrenTextList, src, returnCommand, claim))))
.hoverEvent(HoverEvent.showText(MessageCache.getInstance().CLAIMLIST_UI_CLICK_VIEW_CHILDREN)).build();
claimsTextList.add(TextComponent.builder("")
.append(claimSpawn != null ? claimSpawn.append(TextComponent.of(" ")) : TextComponent.of(""))
.append(claimInfoCommandClick)
.append(" : ", TextColor.WHITE)
.append(claim.getOwnerDisplayName().color(TextColor.GOLD)
.clickEvent(ClickEvent.suggestCommand("/claimlist " + claim.getOwnerName()))
.hoverEvent(HoverEvent.showText(MessageCache.getInstance().CLAIMLIST_UI_CLICK_PLAYER_LIST)))
.append(" ")
.append(claimName == TextComponent.empty() ? TextComponent.of("") : claimName)
.append(" ")
.append(children)
.append(" ")
.append(buyClaim)
.append(" ")
.append(rentClaim)
.build());
} else {
claimsTextList.add(TextComponent.builder("")
.append(claimSpawn != null ? claimSpawn.append(TextComponent.of(" ")) : TextComponent.of(""))
.append(claimInfoCommandClick)
.append(" : ", TextColor.WHITE)
.append(claim.getOwnerDisplayName().color(TextColor.GOLD)
.clickEvent(ClickEvent.suggestCommand("/claimlist " + claim.getOwnerName()))
.hoverEvent(HoverEvent.showText(MessageCache.getInstance().CLAIMLIST_UI_CLICK_PLAYER_LIST)))
.append(" ")
.append(claimName == TextComponent.empty() ? TextComponent.of("") : claimName)
.append(buyClaim)
.append(" ")
.append(rentClaim)
.build());
}
}
if (claimsTextList.size() == 0 && player != null) {
final GDPermissionUser srcUser = PermissionHolderCache.getInstance().getOrCreateUser(player);
if (srcUser.getInternalPlayerData().showNoClaimsFoundMessage) {
claimsTextList.add(MessageCache.getInstance().CLAIMLIST_UI_NO_CLAIMS_FOUND.color(TextColor.RED));
} else {
srcUser.getInternalPlayerData().showNoClaimsFoundMessage = true;
}
}
}
return claimsTextList;
}
public static Consumer<CommandSender> buyClaimConsumerConfirmation(CommandSender src, Claim claim) {
return confirm -> {
final Player player = (Player) src;
if (player.getUniqueId().equals(claim.getOwnerUniqueId())) {
return;
}
final Economy economy = GriefDefenderPlugin.getInstance().getVaultProvider().getApi();
if (!economy.hasAccount(player)) {
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_PLAYER_NOT_FOUND, ImmutableMap.of(
"player", player.getName()));
GriefDefenderPlugin.sendMessage(player, message);
return;
}
final double balance = economy.getBalance(player);
if (balance < claim.getEconomyData().getSalePrice()) {
Map<String, Object> params = ImmutableMap.of(
"amount", claim.getEconomyData().getSalePrice(),
"balance", balance,
"amount_required", claim.getEconomyData().getSalePrice() - balance);
GriefDefenderPlugin.sendMessage(player, GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_BUY_NOT_ENOUGH_FUNDS, params));
return;
}
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_BUY_CONFIRMATION,
ImmutableMap.of("amount", "$" + claim.getEconomyData().getSalePrice()));
final Component buyConfirmationText = TextComponent.builder()
.append(message)
.append(TextComponent.builder()
.append("\n[")
.append(MessageCache.getInstance().LABEL_CONFIRM.color(TextColor.GREEN))
.append("]\n")
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(src, createBuyConsumerConfirmed(src, claim), true))).build())
.build();
GriefDefenderPlugin.sendMessage(player, buyConfirmationText);
};
}
private static Consumer<CommandSender> createBuyConsumerConfirmed(CommandSender src, Claim claim) {
return confirm -> {
final Player player = (Player) src;
final GDPermissionUser owner = PermissionHolderCache.getInstance().getOrCreateUser(claim.getOwnerUniqueId());
final Economy economy = GriefDefenderPlugin.getInstance().getVaultProvider().getApi();
if (!economy.hasAccount(owner.getOfflinePlayer())) {
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_PLAYER_NOT_FOUND, ImmutableMap.of(
"player", owner.getName()));
GriefDefenderPlugin.sendMessage(player, message);
return;
}
GDCauseStackManager.getInstance().pushCause(player);
final ClaimResult result = ((GDClaim) claim).transferOwner(player.getUniqueId(), true, false);
if (!result.successful()) {
final Component defaultMessage = MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.ECONOMY_CLAIM_BUY_TRANSFER_CANCELLED,
ImmutableMap.of(
"owner", owner.getName(),
"player", player.getName(),
"result", result.getMessage().orElse(TextComponent.of(result.getResultType().toString()))));
TextAdapter.sendComponent(src, result.getMessage().orElse(defaultMessage));
return;
}
final double balance = economy.getBalance(player);
if (balance < claim.getEconomyData().getSalePrice()) {
Map<String, Object> params = ImmutableMap.of(
"amount", claim.getEconomyData().getSalePrice(),
"balance", balance,
"amount_required", claim.getEconomyData().getSalePrice() - balance);
GriefDefenderPlugin.sendMessage(player, GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_BUY_NOT_ENOUGH_FUNDS, params));
return;
}
final double salePrice = claim.getEconomyData().getSalePrice();
final EconomyResponse response = economy.depositPlayer(owner.getOfflinePlayer(), salePrice);
if (response.transactionSuccess()) {
final EconomyResponse withdrawResponse = EconomyUtil.getInstance().withdrawFunds(player, salePrice);
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_BUY_CONFIRMED,
ImmutableMap.of(
"amount", String.valueOf("$" +salePrice)));
final Component saleMessage = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_CLAIM_SOLD,
ImmutableMap.of(
"amount", String.valueOf("$" +salePrice),
"balance",String.valueOf("$" + economy.getBalance(owner.getOfflinePlayer()))));
if (owner.getOnlinePlayer() != null) {
TextAdapter.sendComponent(owner.getOnlinePlayer(), saleMessage);
}
claim.getEconomyData().setForSale(false);
claim.getEconomyData().setSalePrice(0);
claim.getData().save();
GriefDefenderPlugin.sendMessage(src, message);
}
};
}
public static Consumer<CommandSender> showChildrenList(List<Component> childrenTextList, CommandSender src, Consumer<CommandSender> returnCommand, GDClaim parent) {
return consumer -> {
Component claimListReturnCommand = TextComponent.builder("")
.append("\n[")
.append(MessageCache.getInstance().CLAIMLIST_UI_RETURN_CLAIMSLIST.color(TextColor.AQUA))
.append("]\n", TextColor.WHITE)
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(returnCommand))).build();
List<Component> textList = new ArrayList<>();
textList.add(claimListReturnCommand);
textList.addAll(childrenTextList);
PaginationList.Builder builder = PaginationList.builder()
.title(parent.getName().orElse(parent.getFriendlyNameType())
.append(TextComponent.of(" ").append(MessageCache.getInstance().CLAIMLIST_UI_TITLE_CHILD_CLAIMS))).padding(TextComponent.builder(" ").decoration(TextDecoration.STRIKETHROUGH, true).build()).contents(textList);
builder.sendTo(src);
};
}
public static Consumer<CommandSender> createReturnClaimListConsumer(CommandSender src, Consumer<CommandSender> returnCommand) {
return consumer -> {
Component claimListReturnCommand = TextComponent.builder("")
.append("\n[")
.append(MessageCache.getInstance().CLAIMLIST_UI_RETURN_CLAIMSLIST.color(TextColor.AQUA))
.append("]\n", TextColor.WHITE)
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(returnCommand))).build();
TextAdapter.sendComponent(src, claimListReturnCommand);
};
}
public static Consumer<CommandSender> createReturnClaimListConsumer(CommandSender src, String arguments) {
return consumer -> {
Component claimListReturnCommand = TextComponent.builder("")
.append("\n[")
.append(MessageCache.getInstance().CLAIMLIST_UI_RETURN_CLAIMSLIST.color(TextColor.AQUA))
.append("]\n", TextColor.WHITE)
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(CommandHelper.createCommandConsumer(src, "/claimslist", arguments)))).build();
TextAdapter.sendComponent(src, claimListReturnCommand);
};
}
public static Consumer<CommandSender> createFlagConsumer(CommandSender src, GDPermissionHolder subject, String subjectName, Set<Context> contexts, GDClaim claim, Flag flag, Tristate flagValue, String source) {
return consumer -> {
String target = flag.getName().toLowerCase();
if (target.isEmpty()) {
target = "any";
}
Tristate newValue = Tristate.UNDEFINED;
if (flagValue == Tristate.TRUE) {
newValue = Tristate.FALSE;
} else if (flagValue == Tristate.UNDEFINED) {
newValue = Tristate.TRUE;
}
CommandHelper.applyFlagPermission(src, subject, claim, flag, target, newValue, null, MenuType.GROUP);
};
}
public static Component getClickableText(CommandSender src, GDClaim claim, Subject subject, Set<Context> contexts, Flag flag, Tristate flagValue, MenuType type) {
TextComponent.Builder textBuilder = TextComponent.builder(flagValue.toString().toLowerCase())
.hoverEvent(HoverEvent.showText(TextComponent.builder("")
.append(MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.CLAIMLIST_UI_CLICK_TOGGLE_VALUE,
ImmutableMap.of("type", type.name().toLowerCase())))
.append("\n")
.append(UIHelper.getPermissionMenuTypeHoverText(type)).build()))
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(createFlagConsumer(src, claim, subject, contexts, flag, flagValue, type))));
return textBuilder.build();
}
public static Component getClickableText(CommandSender src, GDPermissionHolder subject, String subjectName, Set<Context> contexts, GDClaim claim, Flag flag, Tristate flagValue, String source, MenuType type) {
Component onClickText = MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.CLAIMLIST_UI_CLICK_TOGGLE_VALUE,
ImmutableMap.of("type", "flag"));
boolean hasPermission = true;
if (type == MenuType.INHERIT) {
onClickText = MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.FLAG_UI_INHERIT_PARENT,
ImmutableMap.of("name", claim.getFriendlyNameType()));
hasPermission = false;
} else if (src instanceof Player) {
Component denyReason = claim.allowEdit((Player) src);
if (denyReason != null) {
onClickText = denyReason;
hasPermission = false;
}
}
TextComponent.Builder textBuilder = TextComponent.builder(flagValue.toString().toLowerCase())
.hoverEvent(HoverEvent.showText(TextComponent.builder("")
.append(onClickText)
.append("\n")
.append(UIHelper.getPermissionMenuTypeHoverText(type)).build()));
if (hasPermission) {
textBuilder.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(createFlagConsumer(src, subject, subjectName, contexts, claim, flag, flagValue, source))));
}
return textBuilder.build();
}
public static String handleCommandFlag(CommandSender src, String target) {
String pluginId = "minecraft";
String args = "";
String command = "";
int argsIndex = target.indexOf("[");
if (argsIndex != -1) {
if (argsIndex == 0) {
// invalid
TextAdapter.sendComponent(src, MessageCache.getInstance().COMMAND_INVALID);
return null;
}
command = target.substring(0, argsIndex);
String[] parts = command.split(":");
if (parts.length > 1) {
pluginId = parts[0];
command = parts[1];
}
if (!validateCommandMapping(src, command, pluginId)) {
return null;
}
if (!pluginId.equals("minecraft")) {
Plugin pluginContainer = Bukkit.getPluginManager().getPlugin(pluginId);
if (pluginContainer == null) {
TextAdapter.sendComponent(src, MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.PLUGIN_NOT_FOUND,
ImmutableMap.of("id", pluginId)));
return null;
}
}
args = target.substring(argsIndex, target.length());
Pattern p = Pattern.compile("\\[([^\\]]+)\\]");
Matcher m = p.matcher(args);
if (!m.find()) {
// invalid
TextAdapter.sendComponent(src, MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.COMMAND_EXECUTE_FAILED,
ImmutableMap.of(
"command", command,
"args", args)));
return null;
}
args = m.group(1);
target = pluginId + ":" + command + "." + args.replace(":", ".");
} else {
String[] parts = target.split(":");
if (parts.length > 1) {
pluginId = parts[0];
command = parts[1];
} else {
command = target;
}
target = pluginId + ":" + command;
}
// validate command
if (!validateCommandMapping(src, command, pluginId)) {
return null;
}
return target;
}
private static boolean validateCommandMapping(CommandSender src, String command, String pluginId) {
if (command.equalsIgnoreCase("any")) {
return true;
}
Command commandMapping = NMSUtil.getInstance().getBukkitCommandMap().getCommand(command);
if (commandMapping == null) {
// check mod command mapping
commandMapping = NMSUtil.getInstance().getModCommandMap().getCommand(command);
if (commandMapping == null) {
TextAdapter.sendComponent(src, MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.PLUGIN_COMMAND_NOT_FOUND,
ImmutableMap.of(
"command", command,
"id", pluginId)));
return false;
}
}
return true;
}
public static String getTrustPermission(TrustType trustType) {
if (trustType == TrustTypes.ACCESSOR) {
return GDPermissions.TRUST_ACCESSOR;
} else if (trustType == TrustTypes.CONTAINER) {
return GDPermissions.TRUST_CONTAINER;
} else if (trustType == TrustTypes.BUILDER) {
return GDPermissions.TRUST_BUILDER;
} else {
return GDPermissions.TRUST_MANAGER;
}
}
public static Consumer<CommandSender> createTeleportConsumer(CommandSender src, Location location, Claim claim) {
return createTeleportConsumer(src, location, claim, false);
}
public static Consumer<CommandSender> createTeleportConsumer(CommandSender src, Location location, Claim claim, boolean isClaimSpawn) {
return teleport -> {
if (!(src instanceof Player)) {
// ignore
return;
}
final Player player = (Player) src;
// check if world is loaded
if (Bukkit.getWorld(location.getWorld().getUID()) == null) {
TextAdapter.sendComponent(player, MessageCache.getInstance().TELEPORT_NO_SAFE_LOCATION);
return;
}
final GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getPlayerData(player.getWorld(), player.getUniqueId());
final int teleportDelay = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), player, Options.PLAYER_TELEPORT_DELAY, claim);
if (isClaimSpawn) {
if (teleportDelay > 0) {
playerData.teleportDelay = teleportDelay + 1;
playerData.teleportSourceLocation = player.getLocation();
playerData.teleportLocation = location;
return;
}
player.teleport(location, TeleportCause.PLUGIN);
return;
}
final double safeY = location.getWorld().getHighestBlockYAt(location);
location.setY(safeY);
int currentY = location.getBlockY();
while (currentY > 0 && currentY < location.getWorld().getMaxHeight()) {
if (PlayerUtil.getInstance().isSafeLocation(location)) {
if (teleportDelay > 0) {
playerData.teleportDelay = teleportDelay + 1;
playerData.teleportLocation = location;
return;
}
player.teleport(location, TeleportCause.PLUGIN);
return;
}
if (location.getWorld().getEnvironment() == Environment.NETHER) {
currentY--;
} else {
currentY++;
}
location.setY(currentY);
}
TextAdapter.sendComponent(player, MessageCache.getInstance().TELEPORT_NO_SAFE_LOCATION);
};
}
public static void handleBankTransaction(CommandSender src, String[] args, GDClaim claim) {
if (GriefDefenderPlugin.getInstance().getVaultProvider() == null) {
GriefDefenderPlugin.sendMessage(src, MessageCache.getInstance().ECONOMY_NOT_INSTALLED);
return;
}
if (claim.isSubdivision() || claim.isAdminClaim()) {
return;
}
if (!claim.getEconomyAccountId().isPresent()) {
GriefDefenderPlugin.sendMessage(src, MessageCache.getInstance().ECONOMY_VIRTUAL_NOT_SUPPORTED);
return;
}
final Economy economy = GriefDefenderPlugin.getInstance().getVaultProvider().getApi();
final String command = args[0];
final double amount = args.length > 1 ? Double.parseDouble(args[1]) : 0;
final UUID playerSource = ((Player) src).getUniqueId();
final GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getPlayerData(claim.getWorld(), claim.getOwnerUniqueId());
if (playerData.canIgnoreClaim(claim) || claim.getOwnerUniqueId().equals(playerSource) || claim.getUserTrusts(TrustTypes.MANAGER).contains(playerData.playerID)) {
final UUID bankAccount = claim.getEconomyAccountId().orElse(null);
if (bankAccount == null) {
GriefDefenderPlugin.sendMessage(src, MessageCache.getInstance().ECONOMY_VIRTUAL_NOT_SUPPORTED);
return;
}
if (command.equalsIgnoreCase("withdraw")) {
EconomyResponse result = economy.bankWithdraw(bankAccount.toString(), amount);
if (result.transactionSuccess()) {
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.BANK_WITHDRAW,
ImmutableMap.of(
"amount", amount));
GriefDefenderPlugin.sendMessage(src, message);
economy.depositPlayer(((Player) src), amount);
claim.getData().getEconomyData().addPaymentTransaction(
new GDPaymentTransaction(TransactionType.BANK_WITHDRAW, TransactionResultType.SUCCESS, playerData.playerID, Instant.now(), amount));
} else {
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.BANK_WITHDRAW_NO_FUNDS,
ImmutableMap.of(
"balance", economy.bankBalance(bankAccount.toString()),
"amount", amount));
GriefDefenderPlugin.sendMessage(src, message);
claim.getData().getEconomyData()
.addPaymentTransaction(new GDPaymentTransaction(TransactionType.BANK_WITHDRAW, TransactionResultType.FAIL, playerData.playerID, Instant.now(), amount));
return;
}
} else if (command.equalsIgnoreCase("deposit")) {
EconomyResponse result = EconomyUtil.getInstance().withdrawFunds(((Player) src), amount);
if (result.transactionSuccess()) {
double depositAmount = amount;
if (claim.getData().isExpired()) {
final double taxBalance = claim.getEconomyData().getTaxBalance();
depositAmount -= claim.getEconomyData().getTaxBalance();
if (depositAmount >= 0) {
claim.getEconomyData().addPaymentTransaction(new GDPaymentTransaction(TransactionType.TAX, TransactionResultType.SUCCESS, Instant.now(), taxBalance));
claim.getEconomyData().setTaxPastDueDate(null);
claim.getEconomyData().setTaxBalance(0);
claim.getInternalClaimData().setExpired(false);
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.TAX_PAID_BALANCE,
ImmutableMap.of(
"amount", taxBalance));
GriefDefenderPlugin.sendMessage(src, message);
if (depositAmount == 0) {
return;
}
} else {
final double newTaxBalance = Math.abs(depositAmount);
claim.getEconomyData().setTaxBalance(newTaxBalance);
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.TAX_PAID_PARTIAL,
ImmutableMap.of(
"amount", depositAmount,
"balance", newTaxBalance));
GriefDefenderPlugin.sendMessage(src, message);
return;
}
}
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.BANK_DEPOSIT, ImmutableMap.of(
"amount", depositAmount));
GriefDefenderPlugin.sendMessage(src, message);
economy.bankDeposit(bankAccount.toString(), depositAmount);
claim.getData().getEconomyData().addPaymentTransaction(
new GDPaymentTransaction(TransactionType.BANK_DEPOSIT, TransactionResultType.SUCCESS, playerData.playerID, Instant.now(), depositAmount));
} else {
GriefDefenderPlugin.sendMessage(src, GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.BANK_WITHDRAW_NO_FUNDS));
claim.getData().getEconomyData()
.addPaymentTransaction(new GDPaymentTransaction(TransactionType.BANK_DEPOSIT, TransactionResultType.FAIL, playerData.playerID, Instant.now(), amount));
return;
}
}
} else {
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.BANK_NO_PERMISSION,
ImmutableMap.of(
"player", claim.getOwnerName()));
GriefDefenderPlugin.sendMessage(src, message);
}
}
public static void displayClaimBankInfo(Player player, GDClaim claim) {
displayClaimBankInfo(player, claim, false, false);
}
public static void displayClaimBankInfo(CommandSender player, GDClaim claim, boolean checkTown, boolean returnToClaimInfo) {
if (GriefDefenderPlugin.getInstance().getVaultProvider() == null) {
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().ECONOMY_NOT_INSTALLED);
return;
}
if (checkTown && !claim.isInTown()) {
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().TOWN_NOT_IN);
return;
}
if (!checkTown && (claim.isSubdivision() || claim.isAdminClaim())) {
return;
}
final GDClaim town = claim.getTownClaim();
final UUID bankAccount = checkTown ? town.getEconomyAccountId().orElse(null) : claim.getEconomyAccountId().orElse(null);
if (bankAccount == null) {
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().ECONOMY_VIRTUAL_NOT_SUPPORTED);
return;
}
final Economy economy = GriefDefenderPlugin.getInstance().getVaultProvider().getApi();
final GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getPlayerData(claim.getWorld(), claim.getOwnerUniqueId());
final double claimBalance = economy.bankBalance(bankAccount.toString()).balance;
double taxOwed = -1;
final double playerTaxRate = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Double.class), (Player) player, Options.TAX_RATE, claim);
if (checkTown) {
if (!town.getOwnerUniqueId().equals(playerData.playerID)) {
for (Claim playerClaim : playerData.getInternalClaims()) {
GDClaim playerTown = (GDClaim) playerClaim.getTown().orElse(null);
if (!playerClaim.isTown() && playerTown != null && playerTown.getUniqueId().equals(claim.getUniqueId())) {
taxOwed += playerTown.getClaimBlocks() * playerTaxRate;
}
}
} else {
taxOwed = town.getClaimBlocks() * playerTaxRate;
}
} else {
taxOwed = claim.getClaimBlocks() * playerTaxRate;
}
final GriefDefenderConfig<?> activeConfig = GriefDefenderPlugin.getActiveConfig(claim.getWorld().getUID());
final ZonedDateTime withdrawDate = TaskUtil.getNextTargetZoneDate(activeConfig.getConfig().economy.taxApplyHour, 0, 0);
Duration duration = Duration.between(Instant.now().truncatedTo(ChronoUnit.SECONDS), withdrawDate.toInstant()) ;
final long s = duration.getSeconds();
final String timeLeft = String.format("%d:%02d:%02d", s / 3600, (s % 3600) / 60, (s % 60));
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.BANK_INFO,
ImmutableMap.of(
"balance", claimBalance,
"tax-amount", taxOwed,
"time-remaining", timeLeft,
"tax-balance", claim.getData().getEconomyData().getTaxBalance()));
Component transactions = TextComponent.builder("")
.append(MessageCache.getInstance().BANK_TITLE_TRANSACTIONS.color(TextColor.AQUA).decoration(TextDecoration.ITALIC, true))
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(createBankTransactionsConsumer(player, claim, checkTown, returnToClaimInfo))))
.hoverEvent(HoverEvent.showText(MessageCache.getInstance().BANK_CLICK_VIEW_TRANSACTIONS))
.build();
List<Component> textList = new ArrayList<>();
if (returnToClaimInfo) {
textList.add(TextComponent.builder("")
.append("\n[")
.append(MessageCache.getInstance().CLAIMINFO_UI_RETURN_CLAIMINFO.color(TextColor.AQUA))
.append("]\n")
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(CommandHelper.createCommandConsumer(player, "claiminfo", "")))).build());
}
textList.add(message);
textList.add(transactions);
PaginationList.Builder builder = PaginationList.builder()
.title(TextComponent.of("Bank Info", TextColor.AQUA)).padding(TextComponent.builder(" ").decoration(TextDecoration.STRIKETHROUGH, true).build()).contents(textList);
builder.sendTo(player);
}
public static Consumer<CommandSender> createBankTransactionsConsumer(CommandSender src, GDClaim claim, boolean checkTown, boolean returnToClaimInfo) {
return settings -> {
List<PaymentTransaction> paymentTransactions = claim.getData().getEconomyData().getPaymentTransactions(TransactionType.BANK_DEPOSIT);
List<Component> textList = new ArrayList<>();
textList.add(TextComponent.builder("")
.append("\n[")
.append(MessageCache.getInstance().CLAIMINFO_UI_RETURN_BANKINFO.color(TextColor.AQUA))
.append("]\n")
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(consumer -> { displayClaimBankInfo(src, claim, checkTown, returnToClaimInfo); }))).build());
for (PaymentTransaction transaction : paymentTransactions) {
final Duration duration = Duration.between(transaction.getTimestamp(), Instant.now().truncatedTo(ChronoUnit.SECONDS)) ;
final long s = duration.getSeconds();
final GDPermissionUser user = PermissionHolderCache.getInstance().getOrCreateUser(transaction.getSource().orElse(null));
final String timeLeft = String.format("%dh %02dm %02ds", s / 3600, (s % 3600) / 60, (s % 60)) + " ago";
textList.add(TextComponent.builder("")
.append(transaction.getResultType().name(), getTransactionColor(transaction.getResultType()))
.append(" | ", TextColor.BLUE)
.append(TextComponent.of(String.valueOf(transaction.getAmount())))
.append(" | ", TextColor.BLUE)
.append(timeLeft, TextColor.GRAY)
.append(user == null ? TextComponent.empty() : TextComponent.builder("")
.append(" | ", TextColor.BLUE)
.append(user.getName(), TextColor.LIGHT_PURPLE)
.build())
.build());
}
textList.add(TextComponent.builder("")
.append("\n[")
.append(MessageCache.getInstance().CLAIMINFO_UI_RETURN_BANKINFO.color(TextColor.AQUA))
.append("]\n")
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(CommandHelper.createCommandConsumer(src, "claimbank", "")))).build());
PaginationList.Builder builder = PaginationList.builder()
.title(MessageCache.getInstance().BANK_TITLE_TRANSACTIONS.color(TextColor.AQUA)).padding(TextComponent.builder(" ").decoration(TextDecoration.STRIKETHROUGH, true).build()).contents(textList);
builder.sendTo(src);
};
}
public static Consumer<CommandSender> createRentTransactionsConsumer(CommandSender src, GDClaim claim, boolean checkTown, boolean returnToClaimInfo) {
return settings -> {
List<PaymentTransaction> paymentTransactions = claim.getData().getEconomyData().getPaymentTransactions(TransactionType.RENT);
List<Component> textList = new ArrayList<>();
textList.add(TextComponent.builder("")
.append("\n[")
.append(MessageCache.getInstance().RENT_UI_RETURN_INFO.color(TextColor.AQUA))
.append("]\n")
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(CommandHelper.createCommandConsumer(src, "claimrent", "info")))).build());
for (PaymentTransaction transaction : paymentTransactions) {
final Duration duration = Duration.between(transaction.getTimestamp(), Instant.now().truncatedTo(ChronoUnit.SECONDS)) ;
final long s = duration.getSeconds();
final GDPermissionUser user = PermissionHolderCache.getInstance().getOrCreateUser(transaction.getSource().orElse(null));
final String timeLeft = String.format("%dh %02dm %02ds", s / 3600, (s % 3600) / 60, (s % 60)) + " ago";
textList.add(TextComponent.builder("")
.append(transaction.getResultType().name(), getTransactionColor(transaction.getResultType()))
.append(" | ", TextColor.BLUE)
.append(TextComponent.of(String.valueOf(transaction.getAmount())))
.append(" | ", TextColor.BLUE)
.append(timeLeft, TextColor.GRAY)
.append(user == null ? TextComponent.empty() : TextComponent.builder("")
.append(" | ", TextColor.BLUE)
.append(user.getName(), TextColor.LIGHT_PURPLE)
.build())
.build());
}
textList.add(TextComponent.builder("")
.append("\n[")
.append(MessageCache.getInstance().RENT_UI_RETURN_INFO.color(TextColor.AQUA))
.append("]\n")
.clickEvent(ClickEvent.runCommand(GDCallbackHolder.getInstance().createCallbackRunCommand(CommandHelper.createCommandConsumer(src, "claimrent", "info")))).build());
PaginationList.Builder builder = PaginationList.builder()
.title(MessageCache.getInstance().RENT_UI_TITLE_TRANSACTIONS.color(TextColor.AQUA)).padding(TextComponent.builder(" ").decoration(TextDecoration.STRIKETHROUGH, true).build()).contents(textList);
builder.sendTo(src);
};
}
public static TextColor getTransactionColor(TransactionResultType type) {
switch (type) {
case SUCCESS :
return TextColor.GREEN;
case FAIL :
return TextColor.RED;
default :
return TextColor.GREEN;
}
}
public static Component getBaseOptionOverlayText(String option) {
String baseFlag = option.replace(GDPermissions.OPTION_BASE + ".", "");
int endIndex = baseFlag.indexOf(".");
if (endIndex != -1) {
baseFlag = baseFlag.substring(0, endIndex);
}
final Option flag = GriefDefender.getRegistry().getType(Option.class, baseFlag).orElse(null);
if (flag == null) {
return MessageStorage.MESSAGE_DATA.getMessage(MessageStorage.OPTION_NOT_FOUND, ImmutableMap.of(
"option", baseFlag));
}
return flag.getDescription();
}
public static TrustType getTrustType(String type) {
switch (type.toLowerCase()) {
case "accessor" :
return TrustTypes.ACCESSOR;
case "builder" :
return TrustTypes.BUILDER;
case "container" :
return TrustTypes.CONTAINER;
case "manager" :
return TrustTypes.MANAGER;
case "none" :
return TrustTypes.NONE;
default :
return null;
}
}
public static boolean checkTrustPermission(Player player, TrustType type) {
if (type == TrustTypes.ACCESSOR) {
return player.hasPermission(GDPermissions.GIVE_ACCESS_TRUST);
}
if (type == TrustTypes.BUILDER) {
return player.hasPermission(GDPermissions.GIVE_BUILDER_TRUST);
}
if (type == TrustTypes.CONTAINER) {
return player.hasPermission(GDPermissions.GIVE_CONTAINER_TRUST);
}
if (type == TrustTypes.MANAGER) {
return player.hasPermission(GDPermissions.GIVE_MANAGER_TRUST);
}
if (type == TrustTypes.NONE) {
return player.hasPermission(GDPermissions.REMOVE_TRUST);
}
return true;
}
}