/* * This file is part of GriefPrevention, licensed under the MIT License (MIT). * * Copyright (c) Ryan Hamshire * 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 me.ryanhamshire.griefprevention.command; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import me.ryanhamshire.griefprevention.GPPlayerData; import me.ryanhamshire.griefprevention.GriefPreventionPlugin; import me.ryanhamshire.griefprevention.api.claim.Claim; import me.ryanhamshire.griefprevention.api.claim.ClaimType; import me.ryanhamshire.griefprevention.claim.GPClaimManager; import me.ryanhamshire.griefprevention.permission.GPPermissions; import me.ryanhamshire.griefprevention.util.BlockUtils; import me.ryanhamshire.griefprevention.util.PaginationUtils; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.command.args.CommandContext; import org.spongepowered.api.command.spec.CommandExecutor; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.service.pagination.PaginationList; import org.spongepowered.api.service.pagination.PaginationService; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.text.format.TextStyles; import org.spongepowered.api.world.World; import org.spongepowered.api.world.storage.WorldProperties; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; public class CommandClaimList implements CommandExecutor { private final ClaimType forcedType; private boolean canListOthers; private boolean canListAdmin; private boolean displayOwned = true; private final Cache<UUID, String> lastActiveClaimTypeMap = Caffeine.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES) .build(); public CommandClaimList() { this.forcedType = null; } public CommandClaimList(ClaimType type) { this.forcedType = type; } @Override public CommandResult execute(CommandSource src, CommandContext ctx) { Player player; try { player = GriefPreventionPlugin.checkPlayer(src); } catch (CommandException e) { src.sendMessage(e.getText()); return CommandResult.success(); } List<User> userValues = new ArrayList<>(ctx.getAll("user")); WorldProperties worldProperties = ctx.<WorldProperties>getOne("world").orElse(null); User user = null; if (userValues.size() > 0) { user = userValues.get(0); } if (user == null) { if (!(src instanceof Player)) { GriefPreventionPlugin.sendMessage(src, GriefPreventionPlugin.instance.messageData.commandPlayerInvalid.toText()); return CommandResult.success(); } user = (User) src; } if (worldProperties == null) { worldProperties = Sponge.getServer().getDefaultWorld().get(); } if (worldProperties == null || !GriefPreventionPlugin.instance.claimsEnabledForWorld(worldProperties)) { GriefPreventionPlugin.sendMessage(src, GriefPreventionPlugin.instance.messageData.claimDisabledWorld.toText()); return CommandResult.success(); } // Always reset this.displayOwned = true; String arguments = ""; if (user != null) { arguments = user.getName(); } if (arguments.isEmpty()) { arguments = worldProperties.getWorldName(); } else { arguments += " " + worldProperties.getWorldName(); } this.canListOthers = src.hasPermission(GPPermissions.LIST_OTHER_CLAIMS); this.canListAdmin = src.hasPermission(GPPermissions.LIST_OTHER_CLAIMS); showClaimList(player, user, this.forcedType, worldProperties); return CommandResult.success(); } private void showClaimList(Player src, User user, ClaimType type, WorldProperties worldProperties) { List<Text> claimsTextList = new ArrayList<>(); Set<Claim> claims = new HashSet<>(); final GPPlayerData sourcePlayerData = GriefPreventionPlugin.instance.dataStore.getPlayerData(worldProperties, src.getUniqueId()); for (World world : Sponge.getServer().getWorlds()) { if (!this.displayOwned && !world.getProperties().getUniqueId().equals(worldProperties.getUniqueId())) { continue; } final GPClaimManager claimWorldManager = GriefPreventionPlugin.instance.dataStore.getClaimWorldManager(world.getProperties()); // load the target player's data final GPPlayerData playerData = GriefPreventionPlugin.instance.dataStore.getOrCreatePlayerData(world, user.getUniqueId()); Set<Claim> claimList = null; int count = 0; if (this.displayOwned) { claimList = playerData.getInternalClaims(); } else { if (sourcePlayerData.optionRadiusClaimList <= 0) { claimList = claimWorldManager.getInternalWorldClaims(); } else { claimList = BlockUtils.getNearbyClaims(src.getLocation(), sourcePlayerData.optionRadiusClaimList); } } final int claimListMax = GriefPreventionPlugin.getActiveConfig(world.getProperties()).getConfig().claim.claimListMax; for (Claim claim : claimList) { // Make sure not to show too many claims or client will time out if (!this.displayOwned && claimListMax > 0 && count == claimListMax) { break; } if (claims.contains(claim)) { continue; } if (user != null && this.displayOwned) { if (user.getUniqueId().equals(claim.getOwnerUniqueId())) { claims.add(claim); count++; } } else if (type != null) { if (claim.getType() == type) { claims.add(claim); count++; } } else { claims.add(claim); count++; } } } if (src instanceof Player) { final Player player = (Player) src; final String lastClaimType = this.lastActiveClaimTypeMap.getIfPresent(player.getUniqueId()); final String currentType = type == null ? "ALL" : type.toString(); if (lastClaimType != null && !lastClaimType.equals(currentType.toString())) { PaginationUtils.resetActivePage(player.getUniqueId()); } } claimsTextList = CommandHelper.generateClaimTextList(claimsTextList, claims, worldProperties.getWorldName(), user, src, createClaimListConsumer(src, user, type, worldProperties), this.canListOthers, false); final Text whiteOpenBracket = Text.of(TextColors.WHITE, "["); final Text whiteCloseBracket = Text.of(TextColors.WHITE, "]"); Text ownedShowText = Text.of("Click here to view the claims you own."); Text allShowText = Text.of("Click here to show all types."); Text adminShowText = Text.of("Click here to filter by ", TextColors.RED, "ADMIN ", TextColors.RESET, "type."); Text basicShowText = Text.of("Click here to filter by ", TextColors.YELLOW, "BASIC ", TextColors.RESET, "type."); Text subdivisionShowText = Text.of("Click here to filter by ", TextColors.AQUA, "SUBDIVISION ", TextColors.RESET, "type."); Text townShowText = Text.of("Click here to filter by ", TextColors.GREEN, "TOWN ", TextColors.RESET, "type."); Text ownedTypeText = Text.builder() .append(Text.of((this.displayOwned && type == null) ? Text.of(whiteOpenBracket, TextColors.GOLD, "OWN", whiteCloseBracket) : Text.of(TextColors.GRAY, "OWN"))) .onClick(TextActions.executeCallback(createClaimListConsumer(src, user, "OWN", worldProperties))) .onHover(TextActions.showText(ownedShowText)).build(); Text allTypeText = Text.builder() .append(Text.of((!this.displayOwned && type == null) ? Text.of(whiteOpenBracket, TextColors.LIGHT_PURPLE, "ALL", whiteCloseBracket) : Text.of(TextColors.GRAY, "ALL"))) .onClick(TextActions.executeCallback(createClaimListConsumer(src, user, "ALL", worldProperties))) .onHover(TextActions.showText(allShowText)).build(); Text adminTypeText = Text.builder() .append(Text.of(type == ClaimType.ADMIN ? Text.of(whiteOpenBracket, TextColors.RED, "ADMIN", whiteCloseBracket) : Text.of(TextColors.GRAY, "ADMIN"))) .onClick(TextActions.executeCallback(createClaimListConsumer(src, user, ClaimType.ADMIN, worldProperties))) .onHover(TextActions.showText(adminShowText)).build(); Text basicTypeText = Text.builder() .append(Text.of(type == ClaimType.BASIC ? Text.of(whiteOpenBracket, TextColors.YELLOW, "BASIC", whiteCloseBracket) : Text.of(TextColors.GRAY, "BASIC"))) .onClick(TextActions.executeCallback(createClaimListConsumer(src, user, ClaimType.BASIC, worldProperties))) .onHover(TextActions.showText(basicShowText)).build(); Text subTypeText = Text.builder() .append(Text.of(type == ClaimType.SUBDIVISION ? Text.of(whiteOpenBracket, TextColors.AQUA, "SUBDIVISION", whiteCloseBracket) : Text.of(TextColors.GRAY, "SUBDIVISION"))) .onClick(TextActions.executeCallback(createClaimListConsumer(src, user, ClaimType.SUBDIVISION, worldProperties))) .onHover(TextActions.showText(subdivisionShowText)).build(); Text townTypeText = Text.builder() .append(Text.of(type == ClaimType.TOWN ? Text.of(whiteOpenBracket, TextColors.GREEN, "TOWN", whiteCloseBracket) : Text.of(TextColors.GRAY, "TOWN"))) .onClick(TextActions.executeCallback(createClaimListConsumer(src, user, ClaimType.TOWN, worldProperties))) .onHover(TextActions.showText(townShowText)).build(); Text claimListHead = Text.builder().append(Text.of( TextColors.AQUA," Displaying : ", ownedTypeText, " ", allTypeText, " ", adminTypeText, " ", basicTypeText, " ", subTypeText, " ", townTypeText)).build(); final int fillSize = 20 - (claimsTextList.size() + 2); for (int i = 0; i < fillSize; i++) { claimsTextList.add(Text.of(" ")); } PaginationService paginationService = Sponge.getServiceManager().provide(PaginationService.class).get(); PaginationList.Builder paginationBuilder = paginationService.builder() .title(claimListHead).padding(Text.of(TextStyles.STRIKETHROUGH, "-")).contents(claimsTextList); final PaginationList paginationList = paginationBuilder.build(); Integer activePage = 1; if (src instanceof Player) { final Player player = (Player) src; activePage = PaginationUtils.getActivePage(player.getUniqueId()); if (activePage == null) { activePage = 1; } this.lastActiveClaimTypeMap.put(player.getUniqueId(), type == null ? "ALL" : type.toString()); } paginationList.sendTo(src, activePage); } private Consumer<CommandSource> createClaimListConsumer(Player src, User user, String type, WorldProperties worldProperties) { return consumer -> { if (type.equalsIgnoreCase("ALL")) { this.displayOwned = false; } else { this.displayOwned = true; } showClaimList(src, user, null, worldProperties); }; } private Consumer<CommandSource> createClaimListConsumer(Player src, User user, ClaimType type, WorldProperties worldProperties) { return consumer -> { this.displayOwned = false; showClaimList(src, user, type, worldProperties); }; } }