It's been over 3 years :)
The common module was designed to prevent the internal modules depending on the core plugin. With the introduction of localization, this overcomplication became ever more exacerbated. Probably will play around a bit more to remove freshly introduced static abuse before release. Closes #61
This commit is contained in:
		@@ -35,6 +35,7 @@ import com.lishid.openinv.listeners.PluginListener;
 | 
			
		||||
import com.lishid.openinv.util.Cache;
 | 
			
		||||
import com.lishid.openinv.util.ConfigUpdater;
 | 
			
		||||
import com.lishid.openinv.util.InternalAccessor;
 | 
			
		||||
import com.lishid.openinv.util.LanguageManager;
 | 
			
		||||
import com.lishid.openinv.util.Permissions;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
@@ -45,6 +46,7 @@ import java.util.concurrent.Future;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.OfflinePlayer;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandExecutor;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.command.PluginCommand;
 | 
			
		||||
import org.bukkit.entity.HumanEntity;
 | 
			
		||||
@@ -107,6 +109,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
    private InternalAccessor accessor;
 | 
			
		||||
    private LanguageManager languageManager;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Evicts all viewers lacking cross-world permissions from a Player's inventory.
 | 
			
		||||
@@ -128,8 +131,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
 | 
			
		||||
                HumanEntity human = iterator.next();
 | 
			
		||||
                // If player has permission or is in the same world, allow continued access
 | 
			
		||||
                // Just in case, also allow null worlds.
 | 
			
		||||
                if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld() == null
 | 
			
		||||
                        || human.getWorld().equals(player.getWorld())) {
 | 
			
		||||
                if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld().equals(player.getWorld())) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                human.closeInventory();
 | 
			
		||||
@@ -140,8 +142,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
 | 
			
		||||
            Iterator<HumanEntity> iterator = this.enderChests.get(key).getBukkitInventory().getViewers().iterator();
 | 
			
		||||
            while (iterator.hasNext()) {
 | 
			
		||||
                HumanEntity human = iterator.next();
 | 
			
		||||
                if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld() == null
 | 
			
		||||
                        || human.getWorld().equals(player.getWorld())) {
 | 
			
		||||
                if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld().equals(player.getWorld())) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                human.closeInventory();
 | 
			
		||||
@@ -284,6 +285,43 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
 | 
			
		||||
        return this.accessor.getPlayerDataManager().openInventory(player, inventory);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void sendMessage(@NotNull CommandSender sender, @NotNull String key) {
 | 
			
		||||
        String message = this.languageManager.getValue(key, getLocale(sender));
 | 
			
		||||
 | 
			
		||||
        if (message != null && !message.isEmpty()) {
 | 
			
		||||
            sender.sendMessage(message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void sendMessage(@NotNull CommandSender sender, @NotNull String key, String... replacements) {
 | 
			
		||||
        String message = this.languageManager.getValue(key, getLocale(sender), replacements);
 | 
			
		||||
 | 
			
		||||
        if (message != null && !message.isEmpty()) {
 | 
			
		||||
            sender.sendMessage(message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void sendSystemMessage(@NotNull Player player, @NotNull String key) {
 | 
			
		||||
        String message = this.languageManager.getValue(key, getLocale(player));
 | 
			
		||||
 | 
			
		||||
        if (message != null) {
 | 
			
		||||
            this.accessor.getPlayerDataManager().sendSystemMessage(player, message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public @Nullable String getLocalizedMessage(@NotNull CommandSender sender, @NotNull String key) {
 | 
			
		||||
        return this.languageManager.getValue(key, getLocale(sender));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    private String getLocale(@NotNull CommandSender sender) {
 | 
			
		||||
        if (sender instanceof Player) {
 | 
			
		||||
            return this.accessor.getPlayerDataManager().getLocale((Player) sender);
 | 
			
		||||
        } else {
 | 
			
		||||
            return this.getConfig().getString("settings.locale", "en_us");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean notifyAnyChest() {
 | 
			
		||||
        return this.getConfig().getBoolean("notify.any-chest", true);
 | 
			
		||||
@@ -317,6 +355,8 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
 | 
			
		||||
 | 
			
		||||
        this.accessor = new InternalAccessor(this);
 | 
			
		||||
 | 
			
		||||
        this.languageManager = new LanguageManager(this, "en_us");
 | 
			
		||||
 | 
			
		||||
        // Version check
 | 
			
		||||
        if (this.accessor.isSupported()) {
 | 
			
		||||
            // Update existing configuration. May require internal access.
 | 
			
		||||
@@ -332,16 +372,16 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
 | 
			
		||||
 | 
			
		||||
            // Register commands to their executors
 | 
			
		||||
            OpenInvCommand openInv = new OpenInvCommand(this);
 | 
			
		||||
            this.getCommand("openinv").setExecutor(openInv);
 | 
			
		||||
            this.getCommand("openender").setExecutor(openInv);
 | 
			
		||||
            this.setCommandExecutor("openinv", openInv);
 | 
			
		||||
            this.setCommandExecutor("openender", openInv);
 | 
			
		||||
            this.setCommandExecutor("searchcontainer", new SearchContainerCommand(this));
 | 
			
		||||
            SearchInvCommand searchInv = new SearchInvCommand(this);
 | 
			
		||||
            this.getCommand("searchcontainer").setExecutor(new SearchContainerCommand());
 | 
			
		||||
            this.getCommand("searchinv").setExecutor(searchInv);
 | 
			
		||||
            this.getCommand("searchender").setExecutor(searchInv);
 | 
			
		||||
            this.getCommand("searchenchant").setExecutor(new SearchEnchantCommand(this));
 | 
			
		||||
            this.setCommandExecutor("searchinv", searchInv);
 | 
			
		||||
            this.setCommandExecutor("searchender", searchInv);
 | 
			
		||||
            this.setCommandExecutor("searchenchant", new SearchEnchantCommand(this));
 | 
			
		||||
            ContainerSettingCommand settingCommand = new ContainerSettingCommand(this);
 | 
			
		||||
            this.getCommand("silentcontainer").setExecutor(settingCommand);
 | 
			
		||||
            this.getCommand("anycontainer").setExecutor(settingCommand);
 | 
			
		||||
            this.setCommandExecutor("silentcontainer", settingCommand);
 | 
			
		||||
            this.setCommandExecutor("anycontainer", settingCommand);
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
            this.getLogger().info("Your version of CraftBukkit (" + this.accessor.getVersion() + ") is not supported.");
 | 
			
		||||
@@ -351,12 +391,18 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void setCommandExecutor(String commandName, CommandExecutor executor) {
 | 
			
		||||
        PluginCommand command = this.getCommand(commandName);
 | 
			
		||||
        if (command != null) {
 | 
			
		||||
            command.setExecutor(executor);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
        if (!this.accessor.isSupported()) {
 | 
			
		||||
            sender.sendMessage("Your version of CraftBukkit (" + this.accessor.getVersion() + ") is not supported.");
 | 
			
		||||
            sender.sendMessage("If this version is a recent release, check for an update.");
 | 
			
		||||
            sender.sendMessage("If this is an older version, ensure that you've downloaded the legacy support version.");
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
 
 | 
			
		||||
@@ -22,12 +22,12 @@ import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.function.BiConsumer;
 | 
			
		||||
import java.util.function.Function;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import org.bukkit.OfflinePlayer;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.command.TabExecutor;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
public class ContainerSettingCommand implements TabExecutor {
 | 
			
		||||
 | 
			
		||||
@@ -38,15 +38,14 @@ public class ContainerSettingCommand implements TabExecutor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) {
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
        if (!(sender instanceof Player)) {
 | 
			
		||||
            sender.sendMessage(ChatColor.RED + "You can't use this from the console.");
 | 
			
		||||
            plugin.sendMessage(sender, "messages.error.consoleUnsupported");
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Player player = (Player) sender;
 | 
			
		||||
        boolean any = command.getName().startsWith("any");
 | 
			
		||||
        String commandName = any ? "AnyContainer" : "SilentContainer";
 | 
			
		||||
        Function<Player, Boolean> getSetting = any ? plugin::getPlayerAnyChestStatus : plugin::getPlayerSilentChestStatus;
 | 
			
		||||
        BiConsumer<OfflinePlayer, Boolean> setSetting = any ? plugin::setPlayerAnyChestStatus : plugin::setPlayerSilentChestStatus;
 | 
			
		||||
 | 
			
		||||
@@ -66,13 +65,18 @@ public class ContainerSettingCommand implements TabExecutor {
 | 
			
		||||
            setSetting.accept(player, !getSetting.apply(player));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sender.sendMessage(commandName + " is now " + (getSetting.apply(player) ? "ON" : "OFF") + ".");
 | 
			
		||||
        String onOff = plugin.getLocalizedMessage(player, getSetting.apply(player) ? "messages.info.on" : "messages.info.off");
 | 
			
		||||
        if (onOff == null) {
 | 
			
		||||
            onOff = String.valueOf(getSetting.apply(player));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        plugin.sendMessage(sender, "messages.info.settingState","%setting%", any ? "AnyContainer" : "SilentContainer", "%state%", onOff);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
 | 
			
		||||
    public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
        if (!command.testPermissionSilent(sender) || args.length != 1) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -23,13 +23,13 @@ import com.lishid.openinv.util.TabCompleter;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import org.bukkit.OfflinePlayer;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.command.TabExecutor;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.scheduler.BukkitRunnable;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
public class OpenInvCommand implements TabExecutor {
 | 
			
		||||
 | 
			
		||||
@@ -42,9 +42,9 @@ public class OpenInvCommand implements TabExecutor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) {
 | 
			
		||||
    public boolean onCommand(@NotNull final CommandSender sender, @NotNull final Command command, @NotNull final String label, @NotNull final String[] args) {
 | 
			
		||||
        if (!(sender instanceof Player)) {
 | 
			
		||||
            sender.sendMessage(ChatColor.RED + "You can't use this from the console.");
 | 
			
		||||
            plugin.sendMessage(sender, "messages.error.consoleUnsupported");
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -79,7 +79,7 @@ public class OpenInvCommand implements TabExecutor {
 | 
			
		||||
                final OfflinePlayer offlinePlayer = OpenInvCommand.this.plugin.matchPlayer(name);
 | 
			
		||||
 | 
			
		||||
                if (offlinePlayer == null || !offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) {
 | 
			
		||||
                    player.sendMessage(ChatColor.RED + "Player not found!");
 | 
			
		||||
                    plugin.sendMessage(player, "messages.error.invalidPlayer");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -100,49 +100,48 @@ public class OpenInvCommand implements TabExecutor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void openInventory(final Player player, final OfflinePlayer target, boolean openinv) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Player onlineTarget;
 | 
			
		||||
        boolean online = target.isOnline();
 | 
			
		||||
 | 
			
		||||
        if (!online) {
 | 
			
		||||
            // Try loading the player's data
 | 
			
		||||
            onlineTarget = this.plugin.loadPlayer(target);
 | 
			
		||||
 | 
			
		||||
            if (onlineTarget == null) {
 | 
			
		||||
                player.sendMessage(ChatColor.RED + "Player not found!");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            onlineTarget = target.getPlayer();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (onlineTarget == null) {
 | 
			
		||||
            plugin.sendMessage(player, "messages.error.invalidPlayer");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Permissions checks
 | 
			
		||||
        if (onlineTarget.equals(player)) {
 | 
			
		||||
            // Inventory: Additional permission required to open own inventory
 | 
			
		||||
            if (openinv && !Permissions.OPENSELF.hasPermission(player)) {
 | 
			
		||||
                player.sendMessage(ChatColor.RED + "You're not allowed to open your own inventory!");
 | 
			
		||||
                plugin.sendMessage(player, "messages.error.permissionOpenSelf");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Enderchest: Additional permission required to open others' ender chests
 | 
			
		||||
            if (!openinv && !Permissions.ENDERCHEST_ALL.hasPermission(player)) {
 | 
			
		||||
                player.sendMessage(ChatColor.RED + "You do not have permission to access other players' ender chests.");
 | 
			
		||||
                plugin.sendMessage(player, "messages.error.permissionEnderAll");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Protected check
 | 
			
		||||
            if (!Permissions.OVERRIDE.hasPermission(player)
 | 
			
		||||
                    && Permissions.EXEMPT.hasPermission(onlineTarget)) {
 | 
			
		||||
                player.sendMessage(ChatColor.RED + onlineTarget.getDisplayName() + "'s inventory is protected!");
 | 
			
		||||
                plugin.sendMessage(player, "messages.error.permissionExempt",
 | 
			
		||||
                        "%target%", onlineTarget.getDisplayName());
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Crossworld check
 | 
			
		||||
            if (!Permissions.CROSSWORLD.hasPermission(player)
 | 
			
		||||
                    && !onlineTarget.getWorld().equals(player.getWorld())) {
 | 
			
		||||
                player.sendMessage(
 | 
			
		||||
                        ChatColor.RED + onlineTarget.getDisplayName() + " is not in your world!");
 | 
			
		||||
                plugin.sendMessage(player, "messages.error.permissionCrossWorld",
 | 
			
		||||
                        "%target%", onlineTarget.getDisplayName());
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -155,7 +154,7 @@ public class OpenInvCommand implements TabExecutor {
 | 
			
		||||
        try {
 | 
			
		||||
            inv = openinv ? this.plugin.getSpecialInventory(onlineTarget, online) : this.plugin.getSpecialEnderChest(onlineTarget, online);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            player.sendMessage(ChatColor.RED + "An error occurred creating " + onlineTarget.getDisplayName() + "'s inventory!");
 | 
			
		||||
            plugin.sendMessage(player, "messages.error.commandException");
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -165,7 +164,7 @@ public class OpenInvCommand implements TabExecutor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
 | 
			
		||||
    public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
        if (!command.testPermissionSilent(sender) || args.length != 1) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,10 +16,10 @@
 | 
			
		||||
 | 
			
		||||
package com.lishid.openinv.commands;
 | 
			
		||||
 | 
			
		||||
import com.lishid.openinv.OpenInv;
 | 
			
		||||
import com.lishid.openinv.util.TabCompleter;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import org.bukkit.Chunk;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.World;
 | 
			
		||||
@@ -29,16 +29,23 @@ import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.command.TabExecutor;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.inventory.InventoryHolder;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Command for searching containers in a radius of chunks.
 | 
			
		||||
 */
 | 
			
		||||
public class SearchContainerCommand implements TabExecutor {
 | 
			
		||||
 | 
			
		||||
    private final OpenInv plugin;
 | 
			
		||||
 | 
			
		||||
    public SearchContainerCommand(OpenInv plugin) {
 | 
			
		||||
        this.plugin = plugin;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
        if (!(sender instanceof Player)) {
 | 
			
		||||
            sender.sendMessage(ChatColor.RED + "You can't use this from the console.");
 | 
			
		||||
            plugin.sendMessage(sender, "messages.error.consoleUnsupported");
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -47,10 +54,10 @@ public class SearchContainerCommand implements TabExecutor {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Material material = Material.getMaterial(args[0]);
 | 
			
		||||
        Material material = Material.getMaterial(args[0].toUpperCase());
 | 
			
		||||
 | 
			
		||||
        if (material == null) {
 | 
			
		||||
            sender.sendMessage(ChatColor.RED + "Unknown item: \"" + args[0] + "\"");
 | 
			
		||||
            plugin.sendMessage(sender, "messages.error.invalidMaterial", "%target%", args[0]);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -95,15 +102,18 @@ public class SearchContainerCommand implements TabExecutor {
 | 
			
		||||
        if (locations.length() > 0) {
 | 
			
		||||
            locations.delete(locations.length() - 2, locations.length());
 | 
			
		||||
        } else {
 | 
			
		||||
            sender.sendMessage("No containers found with " + material.toString());
 | 
			
		||||
            plugin.sendMessage(sender, "messages.info.container.noMatches",
 | 
			
		||||
                    "%target%", material.name());
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sender.sendMessage("Containers holding item " + material.toString() + ": " + locations.toString());
 | 
			
		||||
        plugin.sendMessage(sender, "messages.info.container.matches",
 | 
			
		||||
                "%target%", material.name(), "%detail%", locations.toString());
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
 | 
			
		||||
    public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
 | 
			
		||||
        if (args.length < 1 || args.length > 2 || !command.testPermissionSilent(sender)) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ import com.lishid.openinv.util.TabCompleter;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.NamespacedKey;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.command.TabExecutor;
 | 
			
		||||
@@ -29,6 +30,7 @@ import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.inventory.Inventory;
 | 
			
		||||
import org.bukkit.inventory.ItemStack;
 | 
			
		||||
import org.bukkit.inventory.meta.ItemMeta;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Command adding the ability to search online players' inventories for enchantments of a specific
 | 
			
		||||
@@ -45,7 +47,7 @@ public class SearchEnchantCommand implements TabExecutor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
        if (args.length == 0) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -54,14 +56,28 @@ public class SearchEnchantCommand implements TabExecutor {
 | 
			
		||||
        int level = 0;
 | 
			
		||||
 | 
			
		||||
        for (String argument : args) {
 | 
			
		||||
            Enchantment localEnchant = Enchantment.getByName(argument.toUpperCase());
 | 
			
		||||
            if (localEnchant != null) {
 | 
			
		||||
                enchant = localEnchant;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            try {
 | 
			
		||||
                level = Integer.parseInt(argument);
 | 
			
		||||
                continue;
 | 
			
		||||
            } catch (NumberFormatException ignored) {}
 | 
			
		||||
 | 
			
		||||
            argument = argument.toLowerCase();
 | 
			
		||||
            int colon = argument.indexOf(':');
 | 
			
		||||
            NamespacedKey key;
 | 
			
		||||
            try {
 | 
			
		||||
                if (colon > -1 && colon < argument.length() - 1) {
 | 
			
		||||
                    key = new NamespacedKey(argument.substring(0, colon), argument.substring(colon + 1));
 | 
			
		||||
                } else {
 | 
			
		||||
                    key = NamespacedKey.minecraft(argument);
 | 
			
		||||
                }
 | 
			
		||||
            } catch (IllegalArgumentException ignored) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Enchantment localEnchant = Enchantment.getByKey(key);
 | 
			
		||||
            if (localEnchant != null) {
 | 
			
		||||
                enchant = localEnchant;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Arguments not set correctly
 | 
			
		||||
@@ -97,12 +113,14 @@ public class SearchEnchantCommand implements TabExecutor {
 | 
			
		||||
            // Matches found, delete trailing comma and space
 | 
			
		||||
            players.delete(players.length() - 2, players.length());
 | 
			
		||||
        } else {
 | 
			
		||||
            sender.sendMessage("No players found with " + (enchant == null ? "any enchant" : enchant.getName())
 | 
			
		||||
                    + " of level " + level + " or higher.");
 | 
			
		||||
            plugin.sendMessage(sender, "messages.info.player.noMatches",
 | 
			
		||||
                    "%target%", (enchant != null ? enchant.getKey().toString() : "") + " >= " + level);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sender.sendMessage("Players: " + players.toString());
 | 
			
		||||
        plugin.sendMessage(sender, "messages.info.player.matches",
 | 
			
		||||
                "%target%", (enchant != null ? enchant.getKey().toString() : "") + " >= " + level,
 | 
			
		||||
                "%detail%", players.toString());
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -120,7 +138,7 @@ public class SearchEnchantCommand implements TabExecutor {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                ItemMeta meta = item.getItemMeta();
 | 
			
		||||
                if (!meta.hasEnchants()) {
 | 
			
		||||
                if (meta == null || !meta.hasEnchants()) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                for (int enchLevel : meta.getEnchants().values()) {
 | 
			
		||||
@@ -134,13 +152,13 @@ public class SearchEnchantCommand implements TabExecutor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
 | 
			
		||||
    public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
        if (!command.testPermissionSilent(sender) || args.length < 1 || args.length > 2) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (args.length == 1) {
 | 
			
		||||
            return TabCompleter.completeObject(args[0], Enchantment::getName, Enchantment.values());
 | 
			
		||||
            return TabCompleter.completeObject(args[0], enchantment -> enchantment.getKey().toString(), Enchantment.values());
 | 
			
		||||
        } else {
 | 
			
		||||
            return TabCompleter.completeInteger(args[1]);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -20,13 +20,13 @@ import com.lishid.openinv.OpenInv;
 | 
			
		||||
import com.lishid.openinv.util.TabCompleter;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.command.TabExecutor;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.inventory.Inventory;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
public class SearchInvCommand implements TabExecutor {
 | 
			
		||||
 | 
			
		||||
@@ -37,32 +37,33 @@ public class SearchInvCommand implements TabExecutor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
 | 
			
		||||
        Material material = null;
 | 
			
		||||
        int count = 1;
 | 
			
		||||
 | 
			
		||||
        if (args.length >= 1) {
 | 
			
		||||
            material = Material.getMaterial(args[0]);
 | 
			
		||||
            material = Material.getMaterial(args[0].toUpperCase());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (args.length >= 2) {
 | 
			
		||||
            try {
 | 
			
		||||
                count = Integer.parseInt(args[1]);
 | 
			
		||||
            } catch (NumberFormatException ex) {
 | 
			
		||||
                sender.sendMessage(ChatColor.RED + "'" + args[1] + "' is not a number!");
 | 
			
		||||
                plugin.sendMessage(sender, "messages.error.invalidNumber", "%target%", args[1]);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (material == null) {
 | 
			
		||||
            sender.sendMessage(ChatColor.RED + "Unknown item: \"" + args[0] + "\"");
 | 
			
		||||
            plugin.sendMessage(sender, "messages.error.invalidMaterial", "%target%", args[0]);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        StringBuilder players = new StringBuilder();
 | 
			
		||||
        boolean searchInv = command.getName().equals("searchinv");
 | 
			
		||||
        for (Player player : plugin.getServer().getOnlinePlayers()) {
 | 
			
		||||
            Inventory inventory = command.getName().equals("searchinv") ? player.getInventory() : player.getEnderChest();
 | 
			
		||||
            Inventory inventory = searchInv ? player.getInventory() : player.getEnderChest();
 | 
			
		||||
            if (inventory.contains(material, count)) {
 | 
			
		||||
                players.append(player.getName()).append(", ");
 | 
			
		||||
            }
 | 
			
		||||
@@ -72,15 +73,18 @@ public class SearchInvCommand implements TabExecutor {
 | 
			
		||||
        if (players.length() > 0) {
 | 
			
		||||
            players.delete(players.length() - 2, players.length());
 | 
			
		||||
        } else {
 | 
			
		||||
            sender.sendMessage("No players found with " + material.toString());
 | 
			
		||||
            plugin.sendMessage(sender, "messages.info.player.noMatches",
 | 
			
		||||
                    "%target%", material.name());
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sender.sendMessage("Players with the item " + material.toString() + ": " + players.toString());
 | 
			
		||||
        plugin.sendMessage(sender, "messages.info.player.matches",
 | 
			
		||||
                "%target%", material.name(), "%detail%", players.toString());
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
 | 
			
		||||
    public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
        if (args.length < 1 || args.length > 2 || !command.testPermissionSilent(sender)) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,56 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2020 lishid. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.lishid.openinv.internal;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.OfflinePlayer;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.inventory.InventoryView;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public interface IPlayerDataManager {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a Player for an OfflinePlayer.
 | 
			
		||||
     * </p>
 | 
			
		||||
     * This method is potentially blocking, and should not be called on the main thread.
 | 
			
		||||
     *
 | 
			
		||||
     * @param offline the OfflinePlayer
 | 
			
		||||
     * @return the Player loaded
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    Player loadPlayer(@NotNull OfflinePlayer offline);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens an ISpecialInventory for a Player.
 | 
			
		||||
     *
 | 
			
		||||
     * @param player the Player opening the ISpecialInventory
 | 
			
		||||
     * @param inventory the Inventory
 | 
			
		||||
     *`
 | 
			
		||||
     * @return the InventoryView opened
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
 | 
			
		||||
 | 
			
		||||
    void sendSystemMessage(@NotNull Player player, @NotNull String message);
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    default String getLocale(Player player) {
 | 
			
		||||
        return player.getLocale();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -55,7 +55,7 @@ public class PlayerListener implements Listener {
 | 
			
		||||
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
 | 
			
		||||
    public void onPlayerInteract(PlayerInteractEvent event) {
 | 
			
		||||
        if (event.getAction() != Action.RIGHT_CLICK_BLOCK || event.getPlayer().isSneaking()
 | 
			
		||||
                || event.useInteractedBlock() == Result.DENY
 | 
			
		||||
                || event.useInteractedBlock() == Result.DENY || event.getClickedBlock() == null
 | 
			
		||||
                || !plugin.getAnySilentContainer().isAnySilentContainer(event.getClickedBlock())) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -71,13 +71,15 @@ public class PlayerListener implements Listener {
 | 
			
		||||
        boolean silent = Permissions.SILENT.hasPermission(player) && plugin.getPlayerSilentChestStatus(player);
 | 
			
		||||
 | 
			
		||||
        // If anycontainer or silentcontainer is active
 | 
			
		||||
        if ((any || silent) && plugin.getAnySilentContainer().activateContainer(player, silent, event.getClickedBlock())) {
 | 
			
		||||
            if (silent && plugin.notifySilentChest() && needsAny && plugin.notifyAnyChest()) {
 | 
			
		||||
                player.sendMessage("You are opening a blocked container silently.");
 | 
			
		||||
            } else if (silent && plugin.notifySilentChest()) {
 | 
			
		||||
                player.sendMessage("You are opening a container silently.");
 | 
			
		||||
            } else if (needsAny && plugin.notifyAnyChest()) {
 | 
			
		||||
                player.sendMessage("You are opening a blocked container.");
 | 
			
		||||
        if (any || silent) {
 | 
			
		||||
            if (plugin.getAnySilentContainer().activateContainer(player, silent, event.getClickedBlock())) {
 | 
			
		||||
                if (silent && plugin.notifySilentChest() && needsAny && plugin.notifyAnyChest()) {
 | 
			
		||||
                    plugin.sendSystemMessage(player, "messages.info.containerBlockedSilent");
 | 
			
		||||
                } else if (needsAny && plugin.notifyAnyChest()) {
 | 
			
		||||
                    plugin.sendSystemMessage(player, "messages.info.containerBlocked");
 | 
			
		||||
                } else if (silent && plugin.notifySilentChest()) {
 | 
			
		||||
                    plugin.sendSystemMessage(player, "messages.info.containerSilent");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            event.setCancelled(true);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										185
									
								
								plugin/src/main/java/com/lishid/openinv/util/Cache.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								plugin/src/main/java/com/lishid/openinv/util/Cache.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,185 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2020 lishid. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.lishid.openinv.util;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.Multimap;
 | 
			
		||||
import com.google.common.collect.TreeMultimap;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.function.Function;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A minimal thread-safe time-based cache implementation backed by a HashMap and TreeMultimap.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Jikoo
 | 
			
		||||
 */
 | 
			
		||||
public class Cache<K, V> {
 | 
			
		||||
 | 
			
		||||
    private final Map<K, V> internal;
 | 
			
		||||
    private final Multimap<Long, K> expiry;
 | 
			
		||||
    private final long retention;
 | 
			
		||||
    private final Function<V, Boolean> inUseCheck, postRemoval;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a Cache with the specified retention duration, in use function, and post-removal function.
 | 
			
		||||
     *
 | 
			
		||||
     * @param retention duration after which keys are automatically invalidated if not in use
 | 
			
		||||
     * @param inUseCheck Function used to check if a key is considered in use
 | 
			
		||||
     * @param postRemoval Function used to perform any operations required when a key is invalidated
 | 
			
		||||
     */
 | 
			
		||||
    public Cache(final long retention, final Function<V, Boolean> inUseCheck, final Function<V, Boolean> postRemoval) {
 | 
			
		||||
        this.internal = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
        this.expiry = TreeMultimap.create(Long::compareTo, (k1, k2) -> Objects.equals(k1, k2) ? 0 : 1);
 | 
			
		||||
 | 
			
		||||
        this.retention = retention;
 | 
			
		||||
        this.inUseCheck = inUseCheck;
 | 
			
		||||
        this.postRemoval = postRemoval;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set a key and value pair. Keys are unique. Using an existing key will cause the old value to
 | 
			
		||||
     * be overwritten and the expiration timer to be reset.
 | 
			
		||||
     *
 | 
			
		||||
     * @param key key with which the specified value is to be associated
 | 
			
		||||
     * @param value value to be associated with the specified key
 | 
			
		||||
     */
 | 
			
		||||
    public void put(final K key, final V value) {
 | 
			
		||||
        // Invalidate key - runs lazy check and ensures value won't be cleaned up early
 | 
			
		||||
        this.invalidate(key);
 | 
			
		||||
 | 
			
		||||
        synchronized (this.internal) {
 | 
			
		||||
            this.internal.put(key, value);
 | 
			
		||||
            this.expiry.put(System.currentTimeMillis() + this.retention, key);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the value to which the specified key is mapped, or null if no value is mapped for the key.
 | 
			
		||||
     *
 | 
			
		||||
     * @param key the key whose associated value is to be returned
 | 
			
		||||
     * @return the value to which the specified key is mapped, or null if no value is mapped for the key
 | 
			
		||||
     */
 | 
			
		||||
    public V get(final K key) {
 | 
			
		||||
        // Run lazy check to clean cache
 | 
			
		||||
        this.lazyCheck();
 | 
			
		||||
 | 
			
		||||
        synchronized (this.internal) {
 | 
			
		||||
            return this.internal.get(key);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns true if the specified key is mapped to a value.
 | 
			
		||||
     *
 | 
			
		||||
     * @param key key to check if a mapping exists for
 | 
			
		||||
     * @return true if a mapping exists for the specified key
 | 
			
		||||
     */
 | 
			
		||||
    public boolean containsKey(final K key) {
 | 
			
		||||
        // Run lazy check to clean cache
 | 
			
		||||
        this.lazyCheck();
 | 
			
		||||
 | 
			
		||||
        synchronized (this.internal) {
 | 
			
		||||
            return this.internal.containsKey(key);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Forcibly invalidates a key, even if it is considered to be in use.
 | 
			
		||||
     *
 | 
			
		||||
     * @param key key to invalidate
 | 
			
		||||
     */
 | 
			
		||||
    public void invalidate(final K key) {
 | 
			
		||||
        // Run lazy check to clean cache
 | 
			
		||||
        this.lazyCheck();
 | 
			
		||||
 | 
			
		||||
        synchronized (this.internal) {
 | 
			
		||||
            if (!this.internal.containsKey(key)) {
 | 
			
		||||
                // Value either not present or cleaned by lazy check. Either way, we're good
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Remove stored object
 | 
			
		||||
            this.internal.remove(key);
 | 
			
		||||
 | 
			
		||||
            // Remove expiration entry - prevents more work later, plus prevents issues with values invalidating early
 | 
			
		||||
            for (Iterator<Map.Entry<Long, K>> iterator = this.expiry.entries().iterator(); iterator.hasNext();) {
 | 
			
		||||
                if (key.equals(iterator.next().getValue())) {
 | 
			
		||||
                    iterator.remove();
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Forcibly invalidates all keys, even if they are considered to be in use.
 | 
			
		||||
     */
 | 
			
		||||
    public void invalidateAll() {
 | 
			
		||||
        synchronized (this.internal) {
 | 
			
		||||
            for (V value : this.internal.values()) {
 | 
			
		||||
                this.postRemoval.apply(value);
 | 
			
		||||
            }
 | 
			
		||||
            this.expiry.clear();
 | 
			
		||||
            this.internal.clear();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidate all expired keys that are not considered in use. If a key is expired but is
 | 
			
		||||
     * considered in use by the provided Function, its expiration time is reset.
 | 
			
		||||
     */
 | 
			
		||||
    private void lazyCheck() {
 | 
			
		||||
        long now = System.currentTimeMillis();
 | 
			
		||||
        synchronized (this.internal) {
 | 
			
		||||
            List<K> inUse = new ArrayList<>();
 | 
			
		||||
            for (Iterator<Map.Entry<Long, K>> iterator = this.expiry.entries().iterator(); iterator
 | 
			
		||||
                    .hasNext();) {
 | 
			
		||||
                Map.Entry<Long, K> entry = iterator.next();
 | 
			
		||||
 | 
			
		||||
                if (entry.getKey() > now) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                iterator.remove();
 | 
			
		||||
 | 
			
		||||
                if (this.inUseCheck.apply(this.internal.get(entry.getValue()))) {
 | 
			
		||||
                    inUse.add(entry.getValue());
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                V value = this.internal.remove(entry.getValue());
 | 
			
		||||
 | 
			
		||||
                if (value == null) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.postRemoval.apply(value);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            long nextExpiry = now + this.retention;
 | 
			
		||||
            for (K value : inUse) {
 | 
			
		||||
                this.expiry.put(nextExpiry, value);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -59,6 +59,9 @@ public class ConfigUpdater {
 | 
			
		||||
                if (version < 3) {
 | 
			
		||||
                    updateConfig2To3();
 | 
			
		||||
                }
 | 
			
		||||
                if (version < 4) {
 | 
			
		||||
                    updateConfig3To4();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                new BukkitRunnable() {
 | 
			
		||||
                    @Override
 | 
			
		||||
@@ -71,6 +74,17 @@ public class ConfigUpdater {
 | 
			
		||||
        }.runTaskAsynchronously(plugin);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateConfig3To4() {
 | 
			
		||||
        new BukkitRunnable() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run() {
 | 
			
		||||
                plugin.getConfig().set("notify", null);
 | 
			
		||||
                plugin.getConfig().set("settings.locale", "en_US");
 | 
			
		||||
                plugin.getConfig().set("config-version", 4);
 | 
			
		||||
            }
 | 
			
		||||
        }.runTask(plugin);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateConfig2To3() {
 | 
			
		||||
        new BukkitRunnable() {
 | 
			
		||||
            @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,180 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2020 lishid. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.lishid.openinv.util;
 | 
			
		||||
 | 
			
		||||
import com.lishid.openinv.internal.IAnySilentContainer;
 | 
			
		||||
import com.lishid.openinv.internal.IPlayerDataManager;
 | 
			
		||||
import com.lishid.openinv.internal.ISpecialEnderChest;
 | 
			
		||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
 | 
			
		||||
import java.lang.reflect.Constructor;
 | 
			
		||||
import java.lang.reflect.InvocationTargetException;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.plugin.Plugin;
 | 
			
		||||
 | 
			
		||||
public class InternalAccessor {
 | 
			
		||||
 | 
			
		||||
    private final Plugin plugin;
 | 
			
		||||
    private final String version;
 | 
			
		||||
    private boolean supported = false;
 | 
			
		||||
    private IPlayerDataManager playerDataManager;
 | 
			
		||||
    private IAnySilentContainer anySilentContainer;
 | 
			
		||||
 | 
			
		||||
    public InternalAccessor(final Plugin plugin) {
 | 
			
		||||
        this.plugin = plugin;
 | 
			
		||||
 | 
			
		||||
        String packageName = plugin.getServer().getClass().getPackage().getName();
 | 
			
		||||
        this.version = packageName.substring(packageName.lastIndexOf('.') + 1);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            // TODO: implement support for CraftMagicNumbers#getMappingsVersion
 | 
			
		||||
            Class.forName("com.lishid.openinv.internal." + this.version + ".SpecialPlayerInventory");
 | 
			
		||||
            Class.forName("com.lishid.openinv.internal." + this.version + ".SpecialEnderChest");
 | 
			
		||||
            this.playerDataManager = this.createObject(IPlayerDataManager.class, "PlayerDataManager");
 | 
			
		||||
            this.anySilentContainer = this.createObject(IAnySilentContainer.class, "AnySilentContainer");
 | 
			
		||||
            this.supported = InventoryAccess.isUseable();
 | 
			
		||||
        } catch (Exception ignored) {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private <T> T createObject(final Class<? extends T> assignableClass, final String className,
 | 
			
		||||
            final Object... params) throws ClassCastException, ClassNotFoundException,
 | 
			
		||||
            InstantiationException, IllegalAccessException, IllegalArgumentException,
 | 
			
		||||
            InvocationTargetException, NoSuchMethodException, SecurityException {
 | 
			
		||||
        // Fetch internal class if it exists.
 | 
			
		||||
        Class<?> internalClass = Class.forName("com.lishid.openinv.internal." + this.version + "." + className);
 | 
			
		||||
        if (!assignableClass.isAssignableFrom(internalClass)) {
 | 
			
		||||
            String message = String.format("Found class %s but cannot cast to %s!", internalClass.getName(), assignableClass.getName());
 | 
			
		||||
            this.plugin.getLogger().warning(message);
 | 
			
		||||
            throw new IllegalStateException(message);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Quick return: no parameters, no need to fiddle about finding the correct constructor.
 | 
			
		||||
        if (params.length == 0) {
 | 
			
		||||
            return assignableClass.cast(internalClass.getConstructor().newInstance());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Search constructors for one matching the given parameters
 | 
			
		||||
        nextConstructor: for (Constructor<?> constructor : internalClass.getConstructors()) {
 | 
			
		||||
            Class<?>[] requiredClasses = constructor.getParameterTypes();
 | 
			
		||||
            if (requiredClasses.length != params.length) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            for (int i = 0; i < params.length; ++i) {
 | 
			
		||||
                if (!requiredClasses[i].isAssignableFrom(params[i].getClass())) {
 | 
			
		||||
                    continue nextConstructor;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return assignableClass.cast(constructor.newInstance(params));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        StringBuilder builder = new StringBuilder("Found class ").append(internalClass.getName())
 | 
			
		||||
                .append(" but cannot find any matching constructors for [");
 | 
			
		||||
        for (Object object : params) {
 | 
			
		||||
            builder.append(object.getClass().getName()).append(", ");
 | 
			
		||||
        }
 | 
			
		||||
        builder.delete(builder.length() - 2, builder.length());
 | 
			
		||||
 | 
			
		||||
        String message = builder.append(']').toString();
 | 
			
		||||
        this.plugin.getLogger().warning(message);
 | 
			
		||||
 | 
			
		||||
        throw new IllegalArgumentException(message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates an instance of the IAnySilentContainer implementation for the current server version.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the IAnySilentContainer
 | 
			
		||||
     * @throws IllegalStateException if server version is unsupported
 | 
			
		||||
     */
 | 
			
		||||
    public IAnySilentContainer getAnySilentContainer() {
 | 
			
		||||
        if (!this.supported) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Unsupported server version %s!", this.version));
 | 
			
		||||
        }
 | 
			
		||||
        return this.anySilentContainer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates an instance of the IPlayerDataManager implementation for the current server version.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the IPlayerDataManager
 | 
			
		||||
     * @throws IllegalStateException if server version is unsupported
 | 
			
		||||
     */
 | 
			
		||||
    public IPlayerDataManager getPlayerDataManager() {
 | 
			
		||||
        if (!this.supported) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Unsupported server version %s!", this.version));
 | 
			
		||||
        }
 | 
			
		||||
        return this.playerDataManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the server implementation version. If not initialized, returns the string "null"
 | 
			
		||||
     * instead.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the version, or "null"
 | 
			
		||||
     */
 | 
			
		||||
    public String getVersion() {
 | 
			
		||||
        return this.version != null ? this.version : "null";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if the server implementation is supported.
 | 
			
		||||
     *
 | 
			
		||||
     * @return true if initialized for a supported server version
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isSupported() {
 | 
			
		||||
        return this.supported;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates an instance of the ISpecialEnderChest implementation for the given Player, or
 | 
			
		||||
     * null if the current version is unsupported.
 | 
			
		||||
     *
 | 
			
		||||
     * @param player the Player
 | 
			
		||||
     * @param online true if the Player is online
 | 
			
		||||
     * @return the ISpecialEnderChest created
 | 
			
		||||
     * @throws InstantiationException if the ISpecialEnderChest could not be instantiated
 | 
			
		||||
     */
 | 
			
		||||
    public ISpecialEnderChest newSpecialEnderChest(final Player player, final boolean online) throws InstantiationException {
 | 
			
		||||
        if (!this.supported) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Unsupported server version %s!", this.version));
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            return this.createObject(ISpecialEnderChest.class, "SpecialEnderChest", player, online);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw new InstantiationException(String.format("Unable to create a new ISpecialEnderChest: %s", e.getMessage()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates an instance of the ISpecialPlayerInventory implementation for the given Player..
 | 
			
		||||
     *
 | 
			
		||||
     * @param player the Player
 | 
			
		||||
     * @param online true if the Player is online
 | 
			
		||||
     * @return the ISpecialPlayerInventory created
 | 
			
		||||
     * @throws InstantiationException if the ISpecialPlayerInventory could not be instantiated
 | 
			
		||||
     */
 | 
			
		||||
    public ISpecialPlayerInventory newSpecialPlayerInventory(final Player player, final boolean online) throws InstantiationException {
 | 
			
		||||
        if (!this.supported) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Unsupported server version %s!", this.version));
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            return this.createObject(ISpecialPlayerInventory.class, "SpecialPlayerInventory", player, online);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            throw new InstantiationException(String.format("Unable to create a new ISpecialPlayerInventory: %s", e.getMessage()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,165 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2020 Jikoo. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.lishid.openinv.util;
 | 
			
		||||
 | 
			
		||||
import com.lishid.openinv.OpenInv;
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import org.bukkit.configuration.file.YamlConfiguration;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A simple language manager supporting both custom and bundled languages.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Jikoo
 | 
			
		||||
 */
 | 
			
		||||
public class LanguageManager {
 | 
			
		||||
 | 
			
		||||
	private final OpenInv plugin;
 | 
			
		||||
	private final String defaultLocale;
 | 
			
		||||
	private Map<String, YamlConfiguration> locales;
 | 
			
		||||
 | 
			
		||||
	public LanguageManager(@NotNull OpenInv plugin, @NotNull String defaultLocale) {
 | 
			
		||||
		this.plugin = plugin;
 | 
			
		||||
		this.defaultLocale = defaultLocale;
 | 
			
		||||
		this.locales = new HashMap<>();
 | 
			
		||||
		getOrLoadLocale(defaultLocale);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private YamlConfiguration getOrLoadLocale(@NotNull String locale) {
 | 
			
		||||
		YamlConfiguration loaded = locales.get(locale);
 | 
			
		||||
		if (loaded != null) {
 | 
			
		||||
			return loaded;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		InputStream resourceStream = plugin.getResource(locale + ".yml");
 | 
			
		||||
		YamlConfiguration localeConfigDefaults;
 | 
			
		||||
		if (resourceStream == null) {
 | 
			
		||||
			localeConfigDefaults = new YamlConfiguration();
 | 
			
		||||
		} else {
 | 
			
		||||
			try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceStream))) {
 | 
			
		||||
				localeConfigDefaults = YamlConfiguration.loadConfiguration(reader);
 | 
			
		||||
			} catch (IOException e) {
 | 
			
		||||
				plugin.getLogger().log(Level.WARNING, "[LanguageManager] Unable to load resource " + locale + ".yml", e);
 | 
			
		||||
				localeConfigDefaults = new YamlConfiguration();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		File file = new File(plugin.getDataFolder(), locale + ".yml");
 | 
			
		||||
		YamlConfiguration localeConfig;
 | 
			
		||||
 | 
			
		||||
		if (!file.exists()) {
 | 
			
		||||
			localeConfig = localeConfigDefaults;
 | 
			
		||||
			try {
 | 
			
		||||
				localeConfigDefaults.save(file);
 | 
			
		||||
			} catch (IOException e) {
 | 
			
		||||
				plugin.getLogger().log(Level.WARNING, "[LanguageManager] Unable to save resource " + locale + ".yml", e);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			localeConfig = YamlConfiguration.loadConfiguration(file);
 | 
			
		||||
 | 
			
		||||
			// Add new language keys
 | 
			
		||||
			List<String> newKeys = new ArrayList<>();
 | 
			
		||||
			for (String key : localeConfigDefaults.getKeys(true)) {
 | 
			
		||||
				if (localeConfigDefaults.isConfigurationSection(key)) {
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (localeConfig.isSet(key)) {
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				localeConfig.set(key, localeConfigDefaults.get(key));
 | 
			
		||||
				newKeys.add(key);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!newKeys.isEmpty()) {
 | 
			
		||||
				plugin.getLogger().info("[LanguageManager] Added new language keys: " + String.join(", ", newKeys));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!locale.equals(defaultLocale)) {
 | 
			
		||||
			localeConfigDefaults = locales.get(defaultLocale);
 | 
			
		||||
 | 
			
		||||
			// Check for missing keys
 | 
			
		||||
			List<String> newKeys = new ArrayList<>();
 | 
			
		||||
			for (String key : localeConfigDefaults.getKeys(true)) {
 | 
			
		||||
				if (localeConfigDefaults.isConfigurationSection(key)) {
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (localeConfig.isSet(key)) {
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				newKeys.add(key);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!newKeys.isEmpty()) {
 | 
			
		||||
				plugin.getLogger().info("[LanguageManager] Missing translations from " + locale + ".yml: " + String.join(", ", newKeys));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Fall through to default locale
 | 
			
		||||
			localeConfig.setDefaults(localeConfigDefaults);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		locales.put(locale, localeConfig);
 | 
			
		||||
		return localeConfig;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Nullable
 | 
			
		||||
	public String getValue(@NotNull String key, @Nullable String locale) {
 | 
			
		||||
		String value = getOrLoadLocale(locale == null ? defaultLocale : locale.toLowerCase()).getString(key);
 | 
			
		||||
		if (value == null || value.isEmpty()) {
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		value = ChatColor.translateAlternateColorCodes('&', value);
 | 
			
		||||
 | 
			
		||||
		return value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Nullable
 | 
			
		||||
	public String getValue(@NotNull String key, @Nullable String locale, @NotNull String... replacements) {
 | 
			
		||||
		if (replacements.length % 2 != 0) {
 | 
			
		||||
			plugin.getLogger().log(Level.WARNING, "[LanguageManager] Replacement data is uneven", new Exception());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		String value = getValue(key, locale);
 | 
			
		||||
 | 
			
		||||
		if (value == null) {
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < replacements.length; i += 2) {
 | 
			
		||||
			value = value.replace(replacements[i], replacements[i + 1]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,69 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2020 lishid. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.lishid.openinv.util;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.permissions.Permissible;
 | 
			
		||||
 | 
			
		||||
public enum Permissions {
 | 
			
		||||
 | 
			
		||||
    OPENINV("openinv"),
 | 
			
		||||
    OVERRIDE("override"),
 | 
			
		||||
    EXEMPT("exempt"),
 | 
			
		||||
    CROSSWORLD("crossworld"),
 | 
			
		||||
    SILENT("silent"),
 | 
			
		||||
    SILENT_DEFAULT("silent.default"),
 | 
			
		||||
    ANYCHEST("anychest"),
 | 
			
		||||
    ANY_DEFAULT("any.default"),
 | 
			
		||||
    ENDERCHEST("openender"),
 | 
			
		||||
    ENDERCHEST_ALL("openenderall"),
 | 
			
		||||
    SEARCH("search"),
 | 
			
		||||
    EDITINV("editinv"),
 | 
			
		||||
    EDITENDER("editender"),
 | 
			
		||||
    OPENSELF("openself");
 | 
			
		||||
 | 
			
		||||
    private final String permission;
 | 
			
		||||
 | 
			
		||||
    Permissions(String permission) {
 | 
			
		||||
        this.permission = "OpenInv." + permission;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean hasPermission(Permissible permissible) {
 | 
			
		||||
 | 
			
		||||
        boolean hasPermission = permissible.hasPermission(permission);
 | 
			
		||||
        if (hasPermission || permissible.isPermissionSet(permission)) {
 | 
			
		||||
            return hasPermission;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        StringBuilder permissionDestroyer = new StringBuilder(permission);
 | 
			
		||||
        for (int lastPeriod = permissionDestroyer.lastIndexOf("."); lastPeriod > 0;
 | 
			
		||||
                lastPeriod = permissionDestroyer.lastIndexOf(".")) {
 | 
			
		||||
            permissionDestroyer.delete(lastPeriod + 1, permissionDestroyer.length()).append('*');
 | 
			
		||||
 | 
			
		||||
            hasPermission = permissible.hasPermission(permissionDestroyer.toString());
 | 
			
		||||
            if (hasPermission || permissible.isPermissionSet(permissionDestroyer.toString())) {
 | 
			
		||||
                return hasPermission;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            permissionDestroyer.delete(lastPeriod, permissionDestroyer.length());
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return permissible.hasPermission("*");
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user