diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/README.md b/README.md index 1a7ac04..f009fb1 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,18 @@ SimpleCompass is a small plugin for [Spigot](https://www.spigotmc.org) Minecraft ## How to install -There is no dependencies, simply drop the jar file into your plugin directory, then restart (or reload) your server. All configuration parameters are explained in this [config.yml](https://github.com/arboriginal/SimpleCompass/blob/master/src/config.yml). +There is no dependencies, simply drop the jar file into your plugin directory, then restart (or reload) your server. All configuration parameters are explained in this [config.yml](https://github.com/arboriginal/SimpleCompass/blob/master/src/main/resources/config.yml). You can download the last release here: [SimpleCompass.jar](https://github.com/arboriginal/SimpleCompass/releases). ## Permissions -All permissions are listed with a short description in this [plugin.yml](https://github.com/arboriginal/SimpleCompass/blob/master/src/plugin.yml#L41). +All permissions are listed with a short description in this [plugin.yml](https://github.com/arboriginal/SimpleCompass/blob/master/src/main/resources/plugin.yml#L41). ## Commands * **/scompass** visual interface (clickable book) +* **/scompass-toggle** to quickly toggle on/off your compass(es) * **/scompass-option** will show the menu to choose where and when display the compass * **/sctrack** to tracker a position, coordinates or a player (see below) * **/scompass-reload** will reload the configuration diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..771ddcd --- /dev/null +++ b/pom.xml @@ -0,0 +1,60 @@ + + 4.0.0 + + SimpleCompass + Simple compass to help player who don't have sense of direction. + + me.arboriginal + SimpleCompass + 1.1 + + + + arboriginal + https://github.com/arboriginal + + + + + UTF-8 + 1.8 + 1.8 + 1.13 + simplecompass.63140 + plugin.SimpleCompass + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + org.spigotmc + spigot-api + 1.13.2-R0.1-SNAPSHOT + provided + + + + + src/main/java + clean package + + + src/main/resources + true + + config.yml + plugin.yml + lang/*.yml + + + + + diff --git a/src/main/java/me/arboriginal/SimpleCompass/commands/AbstractCommand.java b/src/main/java/me/arboriginal/SimpleCompass/commands/AbstractCommand.java new file mode 100644 index 0000000..e0a9f71 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/commands/AbstractCommand.java @@ -0,0 +1,228 @@ +package me.arboriginal.SimpleCompass.commands; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.bukkit.entity.Player; +import com.google.common.collect.ImmutableMap; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; +import me.arboriginal.SimpleCompass.plugin.AbstractTracker; +import me.arboriginal.SimpleCompass.plugin.AbstractTracker.TrackingActions; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public abstract class AbstractCommand { + protected SimpleCompass sc; + protected String mainCommand; + protected Map subCommands = new HashMap(); + + public enum SubCmds { + OPTION, TRACK, + } + + public enum CompassOptions { + ALWAYS, ELYTRA, ELYTRA_VEHICLE, VEHICLE, DISABLED, + } + + // Constructor methods --------------------------------------------------------------------------------------------- + + public AbstractCommand(SimpleCompass plugin, String command) { + sc = plugin; + mainCommand = command; + } + + // Abstract methods ------------------------------------------------------------------------------------------------ + + protected abstract void showOptions(Player player, CompassTypes modified); + + // Public methods > Options ---------------------------------------------------------------------------------------- + + public CompassTypes modifyOption(Player player, CompassTypes type, String value) { + if (value.equals(CompassModes.MODE180.toString()) || value.equals(CompassModes.MODE360.toString())) + sc.datas.compassModeSet(player, type, CompassModes.valueOf(value)); + else + sc.datas.compassOptionSet(player, type, CompassOptions.valueOf(value)); + return type; + } + + public boolean performCommandOption(Player player, String[] args) { + if (!hasAccessOption(player, args, true)) return false; + + CompassTypes modified = null; + + switch (args.length) { + case 0: + break; + + case 1: + if (allowedOptions(player).size() != 1) { + sc.sendMessage(player, "missing_type"); + return false; + } + + modified = modifyOption(player, CompassTypes.valueOf(args[1]), allowedOptions(player).get(0)); + break; + + case 2: + modified = modifyOption(player, CompassTypes.valueOf(args[1]), args[0]); + break; + + default: + return false; + } + + showOptions(player, modified); + + return true; + } + + // Protected methods > Options ------------------------------------------------------------------------------------- + + protected List completeCommandOption(Player player, String[] args) { + switch (args.length) { + case 1: + return getFilteredList(allowedOptions(player), args[0]); + + case 2: + if (allowedOptions(player).contains(args[0])) return getFilteredList(allowedTypes(player), args[1]); + } + + return null; + } + + protected List allowedOptions(Player player) { + List list = new ArrayList<>(); + + for (CompassOptions option : CompassOptions.values()) + if (player.hasPermission("scompass.option." + option)) list.add(option.toString()); + + for (CompassModes mode : CompassModes.values()) list.add(mode.toString()); + + return list; + } + + protected List allowedTypes(Player player) { + List list = new ArrayList(); + + for (CompassTypes type : CompassTypes.values()) + if (player.hasPermission("scompass.use." + type)) list.add(type); + + return list; + } + + protected boolean hasAccessOption(Player player, String[] args, boolean showError) { + if (args.length > 2 || allowedOptions(player).isEmpty() || allowedTypes(player).isEmpty()) { + if (showError) sc.sendMessage(player, "wrong_usage"); + return false; + } + + if (args.length > 0 && !allowedOptions(player).contains(args[0])) { + if (showError) sc.sendMessage(player, "invalid_option", ImmutableMap.of("option", args[0])); + return false; + } + + if (args.length > 1 && !isAllowedTypes(player, args[1])) { + if (showError) sc.sendMessage(player, "invalid_type", ImmutableMap.of("type", args[0])); + return false; + } + + return true; + } + + protected boolean isAllowedTypes(Player player, String value) { + for (CompassTypes type : allowedTypes(player)) if (type.toString().equalsIgnoreCase(value)) return true; + + return false; + } + + // Public methods > Trackers --------------------------------------------------------------------------------------- + + public boolean performCommandTrack(Player player, String[] args) { + HashMap cmdArgs = getTrackArguments(player, args); + AbstractTracker tracker = (AbstractTracker) cmdArgs.get("tracker"); + TrackingActions action = (TrackingActions) cmdArgs.get("action"); + String target = (String) cmdArgs.get("target"); + + if (tracker == null) { + sc.sendMessage(player, "wrong_usage"); + return false; + } + + if (action == null) { + List list = tracker.list(player, null, ""); + + if (list == null || list.isEmpty()) tracker.sendMessage(player, "list_empty"); + else tracker.sendMessage(player, "list", ImmutableMap.of("list", String.join(", ", list))); + return true; + } + + if (action == TrackingActions.HELP && args.length == 2 && player.hasPermission("scompass.help")) { + String help = tracker.help(player, + mainCommand + (subCommands.containsKey(SubCmds.TRACK) ? " " + subCommands.get(SubCmds.TRACK) : "")); + + if (help != null && !help.isEmpty()) player.sendMessage(help); + return true; + } + + return tracker.perform(player, "sctrack", action, target, args); + } + + // Protected methods > Trackers ------------------------------------------------------------------------------------ + + protected List completeCommandTrack(Player player, String[] args) { + if (args.length == 1) return sc.targets.getTrackersList((Player) player, args[0]); + + HashMap parsed = getTrackArguments((Player) player, args); + AbstractTracker tracker = (AbstractTracker) parsed.get("tracker"); + if (tracker != null) return tracker.commandSuggestions((Player) player, args, parsed); + + return null; + } + + protected List getActionsAvailable(Player player, String trackerID) { + if (!sc.targets.canUseTracker(player, trackerID)) return null; + return sc.trackers.get(trackerID).getActionsAvailable(player, false); + } + + protected HashMap getTrackArguments(Player player, String[] args) { + HashMap parsed = new HashMap(); + if (args.length == 0) return parsed; + + AbstractTracker tracker = sc.targets.getTrackerByName(args[0]); + if (tracker == null || !sc.targets.getAvailableTrackers(player).contains(tracker.trackerID())) + return parsed; + + parsed.put("tracker", tracker); + if (args.length == 1) return parsed; + + tracker.parseArguments(player, args, parsed); + return parsed; + } + + // Utils methods --------------------------------------------------------------------------------------------------- + + protected ImmutableMap clickableOption(CompassTypes type, Object option, Object selected) { + String optionType = (option instanceof CompassModes) ? "modes" : "options"; + String optionName = sc.locale.getString(optionType + "." + option); + + return ImmutableMap.of( + "text", sc.prepareMessage("commands." + mainCommand + ".options." + + (option.toString().equals(selected.toString()) ? "active" : "inactive"), + ImmutableMap.of("option", optionName)), + "hover", sc.prepareMessage("commands." + mainCommand + ".options.hover", + ImmutableMap.of("option", optionName, "type", sc.locale.getString("types." + type))), + "click", "/" + mainCommand + + (subCommands.containsKey(SubCmds.OPTION) ? " " + subCommands.get(SubCmds.OPTION) : "") + + " " + option + " " + type); + } + + protected List getFilteredList(List inputList, String startWith) { + List list = new ArrayList(); + + for (Object candidate : inputList) + if (candidate.toString().toLowerCase().startsWith(startWith.toLowerCase())) list.add(candidate.toString()); + + return list; + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/commands/InterfaceCommand.java b/src/main/java/me/arboriginal/SimpleCompass/commands/InterfaceCommand.java new file mode 100644 index 0000000..6b88dc7 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/commands/InterfaceCommand.java @@ -0,0 +1,416 @@ +package me.arboriginal.SimpleCompass.commands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.bukkit.Material; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.conversations.Conversation; +import org.bukkit.conversations.ConversationContext; +import org.bukkit.conversations.Prompt; +import org.bukkit.conversations.StringPrompt; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import org.bukkit.scheduler.BukkitRunnable; +import com.google.common.collect.ImmutableMap; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; +import me.arboriginal.SimpleCompass.plugin.AbstractTracker; +import me.arboriginal.SimpleCompass.plugin.AbstractTracker.TargetSelector; +import me.arboriginal.SimpleCompass.plugin.AbstractTracker.TrackingActions; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; +import me.arboriginal.SimpleCompass.utils.NMSUtil; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; + +public class InterfaceCommand extends AbstractCommand implements CommandExecutor, TabCompleter { + private static final String SELECT_TARGET = "*S313C7:74R637*", SELECT_PAGER = "*S313C7:P463R*"; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public InterfaceCommand(SimpleCompass plugin) { + super(plugin, "scompass"); + + subCommands.put(SubCmds.OPTION, plugin.locale.getString("subcommands." + SubCmds.OPTION)); + + if (!sc.trackers.isEmpty()) + subCommands.put(SubCmds.TRACK, plugin.locale.getString("subcommands." + SubCmds.TRACK)); + } + + // CommandExecutor methods ----------------------------------------------------------------------------------------- + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) sc.sendMessage(sender, "command_only_for_players"); + else if (((Player) sender).isSleeping()) { + sc.sendMessage(sender, "command_no_sleeping"); + return true; + } + else if (args.length == 0) showOptions((Player) sender, null); + else if (args[0].equals(SELECT_TARGET)) targetSelector((Player) sender, subArgs(args)); + else if (subCommand((Player) sender, SubCmds.OPTION, args[0])) + return performCommandOption((Player) sender, subArgs(args)); + else if (subCommand((Player) sender, SubCmds.TRACK, args[0])) + return performCommandTrack((Player) sender, subArgs(args)); + else { + sc.sendMessage(sender, "wrong_usage"); + return false; + } + + return true; + } + + // TabCompleter methods -------------------------------------------------------------------------------------------- + + @Override + public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { + if (args.length == 0 || !(sender instanceof Player)) return null; + + if (args.length == 1) { + List list = new ArrayList(); + + for (SubCmds subCommand : subCommands.keySet()) { + String subCommandName = subCommands.get(subCommand); + + if (subCommandName.toLowerCase().startsWith(args[0].toLowerCase())) list.add(subCommandName); + } + + return list; + } + else if (subCommand((Player) sender, SubCmds.OPTION, args[0])) + return completeCommandOption((Player) sender, Arrays.stream(args).skip(1).toArray(String[]::new)); + else if (subCommand((Player) sender, SubCmds.TRACK, args[0])) + return completeCommandTrack((Player) sender, Arrays.stream(args).skip(1).toArray(String[]::new)); + + sc.sendMessage(sender, "wrong_usage"); + return null; + } + + // CommandUtil methods --------------------------------------------------------------------------------------------- + + @Override + public void showOptions(Player player, CompassTypes modified) { + if (modified != null) sc.sendMessage(player, "commands." + mainCommand + ".saved"); + + ItemStack book = buildInterface(player, modified); + + if (sc.config.getBoolean("interface.give_book_everytime") || !NMSUtil.openBook(player, book)) + giveBook(player, book); + } + + // Private methods ------------------------------------------------------------------------------------------------- + + private ItemStack buildInterface(Player player, CompassTypes modified) { + ItemStack book = new ItemStack(Material.WRITTEN_BOOK); + BookMeta meta = bookMeta(book, "options"); + + List types = allowedTypes(player); + List opts = allowedOptions(player); + + if (modified != null) buildInterfaceOptions(player, meta, types, opts, modified); + if (player.hasPermission("scompass.track")) buildInterfaceTracking(player, meta); + if (modified == null) buildInterfaceOptions(player, meta, types, opts, modified); + + book.setItemMeta(meta); + return book; + } + + private void buildInterfaceOptions( + Player player, BookMeta meta, List types, List opts, CompassTypes modified) { + if (!player.hasPermission("scompass.option")) return; + + if (modified != null) { + types.remove(modified); + meta.spigot().addPage(buildPage(player, modified, opts)); + } + + for (CompassTypes type : types) meta.spigot().addPage(buildPage(player, type, opts)); + } + + private void buildInterfaceTracking(Player player, BookMeta meta) { + List trackers = new ArrayList(); + Set ordered = sc.locale.getConfigurationSection( + "commands." + mainCommand + ".track.buttons").getKeys(false); + + for (String trackerID : sc.targets.trackersPriority) + if (player.hasPermission("scompass.track." + trackerID)) trackers.add(trackerID); + + for (String[] part : chunk(trackers.toArray(new String[trackers.size()]), + sc.locale.getInt("commands." + mainCommand + ".track.per_page"))) { + ArrayList content = new ArrayList(); + content.add(new TextComponent(sc.prepareMessage("commands." + mainCommand + ".header") + "\n\n")); + + for (String trackerID : part) { + AbstractTracker tracker = sc.trackers.get(trackerID); + if (tracker == null) continue; + + Map> commands = new LinkedHashMap>(); + List actions = tracker.getActionsAvailable(player, false); + + for (String actionName : ordered) { + TrackingActions action; // @formatter:off + try { action = TrackingActions.valueOf(actionName); } catch (Exception e) { continue; } + String text = sc.prepareMessage("commands." + mainCommand + ".track.buttons." + action + ".text"); + // @formatter:on + if (!actions.contains(action)) { + commands.put("{" + action + "}", ImmutableMap.of("text", inactiveCommandText(text))); + continue; + } + + commands.put("{" + action + "}", ImmutableMap.of("text", text, "hover", + sc.prepareMessage("commands." + mainCommand + ".track.buttons." + action + ".hover"), + "click", "/" + mainCommand + + " " + (tracker.requireTarget(action) != TargetSelector.NONE + ? SELECT_TARGET + : subCommands.get(SubCmds.TRACK)) + + " " + tracker.trackerName() + " " + tracker.getActionName(action))); + } + + content.add(sc.createClickableMessage(sc.prepareMessage("commands." + mainCommand + ".track.content", + ImmutableMap.of("tracker", tracker.trackerName(), "buttons", + String.join(" ", commands.keySet()))) + + "\n", commands)); + } + + meta.spigot().addPage(content.stream().toArray(BaseComponent[]::new)); + } + } + + private String inactiveCommandText(String text) { + String[] inactiveText = text.replace("&", "§").split("§"); + + String out = "§7"; + for (int i = 0; i < inactiveText.length; i++) if (inactiveText[i].length() > 1) + out += (inactiveText[i].charAt(0) == 'l') ? "§" + inactiveText[i] + "§7" : inactiveText[i].substring(1); + + return out; + } + + private BaseComponent[] buildPage(Player player, CompassTypes type, List optionsList) { + CompassModes typeMode = sc.datas.compassModeGet(player, type); + CompassOptions selected = sc.datas.compassOptionGet(player, type); + ArrayList content = new ArrayList(); + Map> commands = new LinkedHashMap>(); + + content.add(new TextComponent(sc.prepareMessage("commands." + mainCommand + ".header"))); + + for (CompassModes mode : CompassModes.values()) + commands.put("{" + mode + "}", clickableOption(type, mode, typeMode)); + + content.add(sc.createClickableMessage(sc.prepareMessage("commands." + mainCommand + ".content", + ImmutableMap.of("type", sc.locale.getString("types." + type))), commands)); + content.add(new TextComponent("\n" + sc.prepareMessage("commands." + mainCommand + ".footer") + "\n")); + + commands = new LinkedHashMap>(); + + for (String option : optionsList) { + if (option.equals(CompassModes.MODE180.toString()) || option.equals(CompassModes.MODE360.toString())) + continue; + + commands.put("{" + option + "}", clickableOption(type, option, selected)); + } + + content.add(sc.createClickableMessage(String.join("\n", commands.keySet()), commands)); + + return content.stream().toArray(BaseComponent[]::new); + } + + private void giveBook(Player player, ItemStack book) { + if (!sc.config.getBoolean("interface.give_book_everytime") + && !sc.config.getBoolean("interface.give_book_on_fail")) { + sc.sendMessage(player, "interface_failed_auto_open"); + return; + } + + long cooldown = sc.datas.cooldownBookGet(player); + + if (cooldown > 0) { + sc.sendMessage(player, "interface_book_give_cooldown", + ImmutableMap.of("delay", "" + sc.formatTime(cooldown))); + return; + } + + int slot = player.getInventory().firstEmpty(); + + if (slot == -1) { + sc.sendMessage(player, "interface_failed_auto_open_give_failed"); + return; + } + + player.getInventory().setItem(slot, book); + sc.datas.cooldownBookSet(player); + sc.sendMessage(player, "interface_failed_auto_open_give"); + } + + private boolean subCommand(Player player, SubCmds command, String argument) { + return subCommands.get(command) != null + && argument.toLowerCase().equals(subCommands.get(command).toLowerCase()) + && player.hasPermission("scompass." + command.toString().toLowerCase()) + && (command == SubCmds.OPTION || !sc.trackers.isEmpty()); + } + + private void targetSelector(Player player, String[] args) { + HashMap cmdArgs = getTrackArguments(player, args); + if (cmdArgs.get("tracker") == null || cmdArgs.get("action") == null) return; + + AbstractTracker tracker = (AbstractTracker) cmdArgs.get("tracker"); + TrackingActions action = (TrackingActions) cmdArgs.get("action"); + + switch (tracker.requireTarget(action)) { // @formatter:off + case ACTIVE: targetSelectorList(player, tracker.activeTargets(player, ""), args); break; + case AVAILABLE: targetSelectorList(player, tracker.availableTargets(player, ""), args); break; + case NEW: targetSelectorNew(player, args, false); break; + case NEWCOORDS: targetSelectorNew(player, args, true); break; + default: + } // @formatter:on + } + + private void targetSelectorFallback(Player player, List pages, String args[]) { + int pager = 0; + // @formatter:off + if (args.length > 3 && args[2].equals(SELECT_PAGER)) + try { pager = Integer.parseInt(args[3]); } catch (Exception e) {} + // @formatter:on + player.spigot().sendMessage(pages.get(pager)); + if (pages.size() == 1) return; + + Map> commands = new LinkedHashMap>(); + + String command = "/" + mainCommand + " " + SELECT_TARGET + " " + args[0] + " " + args[1] + " " + SELECT_PAGER; + + if (pager > 0) commands.put("{prev}", ImmutableMap.of( + "text", sc.prepareMessage("commands." + mainCommand + ".targets.prev.title"), + "hover", sc.prepareMessage("commands." + mainCommand + ".targets.prev.hover"), + "click", command + " " + (pager - 1))); + + if (pager < pages.size() - 1) commands.put("{next}", ImmutableMap.of( + "text", sc.prepareMessage("commands." + mainCommand + ".targets.next.title"), + "hover", sc.prepareMessage("commands." + mainCommand + ".targets.next.hover"), + "click", command + " " + (pager + 1))); + + if (!commands.isEmpty()) player.spigot().sendMessage( + sc.createClickableMessage(" " + String.join(" ", commands.keySet()) + "\n", commands)); + } + + private void targetSelectorList(Player player, List targets, String[] args) { + ItemStack book = new ItemStack(Material.WRITTEN_BOOK); + BookMeta meta = bookMeta(book, "targets"); + String head = sc.prepareMessage("commands." + mainCommand + ".targets.header") + "\n\n"; + String command = "/" + mainCommand + " " + subCommands.get(SubCmds.TRACK) + " " + String.join(" ", args); + + List pages = targetSelectorPages(targets, new TextComponent(head), command); + for (BaseComponent[] page : pages) meta.spigot().addPage(page); + book.setItemMeta(meta); + + if (!NMSUtil.openBook(player, book)) targetSelectorFallback(player, pages, args); + } + + private List targetSelectorPages(List targets, BaseComponent head, String command) { + List pages = new ArrayList(); + + for (String[] part : chunk(targets.toArray(new String[targets.size()]), + sc.locale.getInt("commands." + mainCommand + ".targets.per_page"))) { + BaseComponent[] page = new BaseComponent[part.length + 1]; + page[0] = head; + + for (int i = 0; i < part.length; i++) { + Map> commands = new LinkedHashMap>(); + + commands.put("{cmd}", ImmutableMap.of( + "text", sc.prepareMessage("commands." + mainCommand + ".targets.content", + ImmutableMap.of("target", part[i])), + "hover", sc.prepareMessage("commands." + mainCommand + ".targets.hover", + ImmutableMap.of("target", part[i])), + "click", command + " " + part[i])); + + page[i + 1] = sc.createClickableMessage("{cmd}" + "\n", commands); + } + + pages.add(page); + } + + if (pages.isEmpty()) pages.add(new BaseComponent[] { head, + new TextComponent(sc.prepareMessage("commands." + mainCommand + ".targets.no_targets")) }); + + return pages; + } + + private void targetSelectorNew(Player player, String[] args, boolean coords) { + String cancel = sc.locale.getString("commands." + mainCommand + ".targets.new.cancel"); + + Conversation conv = new Conversation(sc, player, new StringPrompt() { + @Override + public String getPromptText(ConversationContext paramConversationContext) { + return sc.prepareMessage( + "commands." + mainCommand + ".targets.new.name_" + (coords ? "coords" : "only"), + ImmutableMap.of("word", cancel)); + } + + @Override + public Prompt acceptInput(ConversationContext paramConversationContext, String paramString) { + new BukkitRunnable() { + @Override + public void run() { + if (this.isCancelled()) return; + if (paramString.equals(cancel)) + player.sendMessage(sc.prepareMessage("commands." + mainCommand + ".targets.new.cancelled")); + else player.performCommand(mainCommand + " " + subCommands.get(SubCmds.TRACK) + + " " + String.join(" ", args) + " " + paramString); + this.cancel(); + } + }.runTaskLater(sc, sc.config.getInt("delays.target_cancel")); + + return END_OF_CONVERSATION; + } + }); + + conv.setLocalEchoEnabled(false); + player.beginConversation(conv); + } + + // ---------------------------------------------------------------------------------------------- + // Utils methods + // ---------------------------------------------------------------------------------------------- + + private BookMeta bookMeta(ItemStack book, String type) { + BookMeta meta = (BookMeta) book.getItemMeta(); + meta.setTitle(sc.prepareMessage("commands." + mainCommand + ".books." + type + ".title")); + meta.setAuthor(sc.prepareMessage("commands." + mainCommand + ".books." + type + ".author")); + + ArrayList lore = new ArrayList(); + for (String row : sc.locale.getStringList("commands." + mainCommand + ".books." + type + ".lore")) + lore.add(sc.formatMessage(row)); + + meta.setLore(lore); + return meta; + } + + private List chunk(String[] input, int number) { + List parts = new ArrayList(); + + int left = input.length; + while (left > 0) { + int size = Math.min(left, number); + String[] part = new String[size]; + + System.arraycopy(input, input.length - left, part, 0, size); + parts.add(part); + + left -= size; + } + + return parts; + } + + private String[] subArgs(String[] args) { + return Arrays.stream(args).skip(1).toArray(String[]::new); + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/commands/OptionCommand.java b/src/main/java/me/arboriginal/SimpleCompass/commands/OptionCommand.java new file mode 100644 index 0000000..093c649 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/commands/OptionCommand.java @@ -0,0 +1,81 @@ +package me.arboriginal.SimpleCompass.commands; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import com.google.common.collect.ImmutableMap; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public class OptionCommand extends AbstractCommand implements CommandExecutor, TabCompleter { + // Constructor methods --------------------------------------------------------------------------------------------- + + public OptionCommand(SimpleCompass plugin) { + super(plugin, "scoption"); + } + + // CommandExecutor methods ----------------------------------------------------------------------------------------- + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sc.sendMessage(sender, "command_only_for_players"); + return true; + } + else if (((Player) sender).isSleeping()) { + sc.sendMessage(sender, "command_no_sleeping"); + return true; + } + + return performCommandOption((Player) sender, args); + } + + // TabCompleter methods -------------------------------------------------------------------------------------------- + + @Override + public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { + if (sender instanceof Player) return completeCommandOption((Player) sender, args); + return null; + } + + // SimpleCompassOptions methods ------------------------------------------------------------------------------------ + + @Override + public void showOptions(Player player, CompassTypes modified) { + sc.sendMessage(player, "commands." + mainCommand + ".header"); + + for (CompassTypes type : allowedTypes(player)) { + CompassModes typeMode = sc.datas.compassModeGet(player, type); + CompassOptions selected = sc.datas.compassOptionGet(player, type); + Map> commands = new LinkedHashMap>(); + + for (CompassModes mode : CompassModes.values()) + commands.put("{" + mode + "}", clickableOption(type, mode, typeMode)); + + player.spigot().sendMessage( + sc.createClickableMessage(sc.prepareMessage("commands." + mainCommand + ".content", + ImmutableMap.of("type", sc.locale.getString("types." + type))), commands)); + + commands = new LinkedHashMap>(); + + for (String option : allowedOptions(player)) { + if (option.equals(CompassModes.MODE180.toString()) || option.equals(CompassModes.MODE360.toString())) + continue; + + commands.put("{" + option + "}", clickableOption(type, option, selected)); + } + + player.spigot().sendMessage(sc.createClickableMessage(String.join("", commands.keySet()), commands)); + } + + sc.sendMessage(player, "commands." + mainCommand + ".footer"); + + if (modified != null) sc.sendMessage(player, "commands." + mainCommand + ".saved"); + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/commands/TrackCommand.java b/src/main/java/me/arboriginal/SimpleCompass/commands/TrackCommand.java new file mode 100644 index 0000000..e0ec20a --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/commands/TrackCommand.java @@ -0,0 +1,48 @@ +package me.arboriginal.SimpleCompass.commands; + +import java.util.List; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public class TrackCommand extends AbstractCommand implements CommandExecutor, TabCompleter { + // Constructor methods --------------------------------------------------------------------------------------------- + + public TrackCommand(SimpleCompass plugin) { + super(plugin, "sctrack"); + } + + // CommandExecutor methods ----------------------------------------------------------------------------------------- + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sc.sendMessage(sender, "command_only_for_players"); + return true; + } + + if (((Player) sender).isSleeping()) { + sc.sendMessage(sender, "command_no_sleeping"); + return true; + } + + return performCommandTrack((Player) sender, args); + } + + // TabCompleter methods -------------------------------------------------------------------------------------------- + + @Override + public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { + if (sender instanceof Player) return completeCommandTrack((Player) sender, args); + return null; + } + + // CommandUtil methods --------------------------------------------------------------------------------------------- + + @Override + public void showOptions(Player player, CompassTypes modified) {} +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/compasses/AbstractCompass.java b/src/main/java/me/arboriginal/SimpleCompass/compasses/AbstractCompass.java new file mode 100644 index 0000000..e6451c5 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/compasses/AbstractCompass.java @@ -0,0 +1,186 @@ +package me.arboriginal.SimpleCompass.compasses; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; +import me.arboriginal.SimpleCompass.plugin.AbstractTracker; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public abstract class AbstractCompass { + protected SimpleCompass sc; + protected CompassTypes type; + protected BukkitRunnable task = null; + protected String warning = ""; + + public enum CompassTypes { + ACTIONBAR, BOSSBAR, + } + + public enum CompassModes { + MODE180, MODE360, + } + + public Player owner; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public AbstractCompass(SimpleCompass plugin, Player player, CompassTypes compassTypes) { + sc = plugin; + type = compassTypes; + owner = player; + + init(); + refresh(); + } + + // Abstract methods ------------------------------------------------------------------------------------------------ + + public abstract void display(String datas); + + // Default methods ------------------------------------------------------------------------------------------------- + + public void delete() { + sc.tasks.clear(TasksTypes.REFRESH_STATUS, owner); + + if (task != null) task.cancel(); + if (sc.compasses.hasRequiredItems(owner, type, false)) return; + + String message = sc.prepareMessage("warnPlayerNoMoreFuel"); + if (message.isEmpty()) return; + + warning = message; + display(warning); + } + + public void init() {} + + public void refresh() { + display(buildCompassDatas()); + } + + // Private methods ------------------------------------------------------------------------------------------------- + + private String buildCompassDatas() { + double rotation = (owner.getEyeLocation().getYaw() - 180) % 360; + if (rotation < 0) rotation += 360; + + CompassModes mode = sc.datas.compassModeGet(owner, type); + + String prefix = "compass." + type + "." + mode; + String sep = sc.config.getString(prefix + ".separator_value"); + String cSep = sc.config.getString(prefix + ".separator_color"); + String cOn = sc.config.getString(prefix + ".active_color"); + String cOff = sc.config.getString(prefix + ".inactive_color"); + String nOn = sc.config.getString(prefix + ".active_north_color"); + String nOff = sc.config.getString(prefix + ".north_color"); + String west = sc.config.getString(prefix + ".cardinals.west"); + String north = sc.config.getString(prefix + ".cardinals.north"); + String east = sc.config.getString(prefix + ".cardinals.east"); + String south = sc.config.getString(prefix + ".cardinals.south"); + String datas = sep + "♤" + sep + "♡" + sep + "♢" + sep + "♧"; + int start = (int) Math.round(rotation * datas.length() / 360); + char face = getFacing(); + + datas = datas.substring(start) + datas.substring(0, start); + + if (mode == CompassModes.MODE180) { + int strip = (int) Math.ceil(datas.length() / 4); + datas = datas.substring(strip - 1, datas.length() - strip + 1); + } + + return sc.config.getString(prefix + ".before") + cSep + injectActivatedTrackers(datas, cSep) // @formatter:off + .replace("♤", ((face == 'W') ? cOn : cOff) + west + cSep) + .replace("♡", ((face == 'N') ? nOn : nOff) + north + cSep) + .replace("♢", ((face == 'E') ? cOn : cOff) + east + cSep) + .replace("♧", ((face == 'S') ? cOn : cOff) + south + cSep) + + sc.config.getString(prefix + ".after"); // @formatter:on + } + + private char getFacing() { + try { + if (owner.getClass().getMethod("myMethodToFind", (Class[]) null) != null) + return owner.getFacing().toString().charAt(0); + } + catch (Exception e) {} + // Use this as a fallback for Spigot version (like 1.12) which doesn't support player.getFacing() + return Arrays.asList('S', 'W', 'N', 'E').get(Math.round(owner.getLocation().getYaw() / 90f) & 0x3); + } + + private HashMap>> getActiveTargets() { + String cacheKey = "trackers." + type; + // @formatter:off + @SuppressWarnings("unchecked") + HashMap>> trackers + = (HashMap>>) sc.cache.get(owner.getUniqueId(), cacheKey); + // @formatter:on + if (trackers == null) { + trackers = sc.targets.getTargetsCoords(owner); + sc.cache.set(owner.getUniqueId(), cacheKey, trackers, sc.config.getInt("delays.trackers_list")); + } + + return trackers; + } + + private String injectActivatedTrackers(String compass, String sepColor) { + HashMap>> targets = getActiveTargets(); + if (targets.isEmpty()) return compass; + + Location refPos = owner.getEyeLocation(); + + HashMap placeholders = new HashMap(); + + for (String trackerID : sc.targets.trackersPriority) { + AbstractTracker tracker = sc.trackers.get(trackerID); + if (tracker == null) continue; + + int hlMaxAngle = tracker.settings.getInt("settings.hl_angle", 0); + String hlMarker = null, hlSymbol = null; + + if (hlMaxAngle > 0) { + hlMarker = tracker.settings.getString("settings.hl_temp", null); + hlSymbol = tracker.settings.getString("settings.hl_symbol", null); + if (hlMarker != null && hlSymbol != null) placeholders.put(hlMarker, hlSymbol + sepColor); + } + + for (String targetType : targets.keySet()) { + ArrayList coords = targets.get(targetType).get(trackerID); + if (coords == null || coords.isEmpty()) continue; + + boolean active = targetType.equals("on"); + String marker = tracker.settings.getString("settings." + (active ? "" : "inactive_") + "temp"); + String symbol = tracker.settings.getString("settings." + (active ? "" : "inactive_") + "symbol"); + placeholders.put(marker, symbol + sepColor); + + for (double[] target : coords) { + Vector blockDirection = new Location(owner.getWorld(), target[0], refPos.getY(), target[1]) + .subtract(refPos).toVector().normalize(); + + Vector lookAt = refPos.getDirection().setY(0); + boolean viewable = (lookAt.dot(blockDirection) > 0); + double angle = Math.toDegrees(blockDirection.angle(lookAt.crossProduct(new Vector(0, 1, 0)))); + String tMarker = marker; + + if (!viewable) angle = (angle > 90) ? 180 : 0; + else if (active && hlMarker != null && hlSymbol != null && angle > 90 - hlMaxAngle + && angle < 90 + hlMaxAngle) + tMarker = hlMarker; + + int start = compass.length() - (int) Math.round(2 * angle * compass.length() / 360); + + compass = (start < 2) ? tMarker + compass.substring(start + 1) + : compass.substring(0, start - 1) + tMarker + compass.substring(start); + } + } + } + + for (String placeholder : placeholders.keySet()) + compass = compass.replaceAll(placeholder, placeholders.get(placeholder)); + + return compass; + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/compasses/ActionbarCompass.java b/src/main/java/me/arboriginal/SimpleCompass/compasses/ActionbarCompass.java new file mode 100644 index 0000000..fae055a --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/compasses/ActionbarCompass.java @@ -0,0 +1,40 @@ +package me.arboriginal.SimpleCompass.compasses; + +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; + +public class ActionbarCompass extends AbstractCompass { + // Constructor methods --------------------------------------------------------------------------------------------- + + public ActionbarCompass(SimpleCompass plugin, Player player) { + super(plugin, player, CompassTypes.ACTIONBAR); + } + + // SimpleCompass methods ------------------------------------------------------------------------------------------- + + @Override + public void display(String datas) { + owner.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(datas)); + } + + @Override + public void refresh() { + super.refresh(); + + if (sc.config.getBoolean("compass.ACTIONBAR.maintain_when_not_moving") && task == null) { + task = new BukkitRunnable() { + @Override + public void run() { + if (isCancelled()) return; + refresh(); + } + }; + + Long delay = sc.config.getLong("compass.ACTIONBAR.maintain_delay"); + task.runTaskTimer(sc, delay, delay); + } + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/compasses/BossbarCompass.java b/src/main/java/me/arboriginal/SimpleCompass/compasses/BossbarCompass.java new file mode 100644 index 0000000..97b141a --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/compasses/BossbarCompass.java @@ -0,0 +1,129 @@ +package me.arboriginal.SimpleCompass.compasses; + +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; +import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public class BossbarCompass extends AbstractCompass { + public BossBar bossbar; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public BossbarCompass(SimpleCompass plugin, Player player) { + super(plugin, player, CompassTypes.BOSSBAR); + } + + // SimpleCompass methods ------------------------------------------------------------------------------------------- + + @Override + public void delete() { + super.delete(); + sc.tasks.set(TasksTypes.REMOVEWARNING, owner, this); + } + + @Override + public void display(String datas) { + bossbar.setTitle(datas); + bossbar.setProgress(getProgress()); + } + + @Override + public void refresh() { + super.refresh(); + + if (sc.config.getBoolean("compass.BOSSBAR.disappear_when_not_moving")) { + if (task != null) task.cancel(); + + bossbar.setVisible(true); + + task = new BukkitRunnable() { + @Override + public void run() { + if (isCancelled()) return; + bossbar.setVisible(false); + this.cancel(); + } + }; + + task.runTaskLaterAsynchronously(sc, sc.config.getInt("compass.BOSSBAR.disappear_delay")); + } + } + + @Override + public void init() { + super.init(); + + bossbar = Bukkit.createBossBar("", + BarColor.valueOf(sc.config.getString("compass.BOSSBAR.attributes.color")), + BarStyle.valueOf(sc.config.getString("compass.BOSSBAR.attributes.style"))); + + bossbar.addPlayer(owner); + bossbar.setProgress(getProgress()); + bossbar.setVisible(true); + } + + // Specific methods ------------------------------------------------------------------------------------------------ + + private void alterColor(double durability) { + Object levels = sc.config.get("compass.BOSSBAR.attributes.elytra_durability.levels"); + if (levels == null || !(levels instanceof Map)) return; + + durability *= 100; + + for (Object value : ((Map) levels).keySet()) if (durability < (int) value) { + bossbar.setColor(BarColor.valueOf((String) ((Map) levels).get(value))); + return; + } + + bossbar.setColor(BarColor.valueOf(sc.config.getString("compass.BOSSBAR.attributes.color"))); + } + + @SuppressWarnings("deprecation") + private int elytraDurabilityOldMethod(ItemStack chestplate) { + try { + if (chestplate.getClass().getMethod("getDurability", (Class[]) null) != null) + return (int) chestplate.getDurability(); + } + catch (Exception e) {} + + return -1; + } + + private double getProgress() { + String cacheKey = "compass." + type; + Double progress = (Double) sc.cache.get(owner.getUniqueId(), cacheKey); + if (progress != null) return progress; + + if (sc.config.getBoolean("compass.BOSSBAR.attributes.elytra_durability.wearing") // @formatter:off + || (sc.config.getBoolean("compass.BOSSBAR.attributes.elytra_durability.gliding") && owner.isGliding())) { + ItemStack chestplate = owner.getInventory().getChestplate(); // @formatter:on + + if (chestplate != null && chestplate.getType() == Material.ELYTRA + && !chestplate.getItemMeta().isUnbreakable()) { + Map metas = chestplate.getItemMeta().serialize(); + + int damages = (metas.containsKey("Damage") && metas.get("Damage") instanceof Integer) + ? (int) metas.get("Damage") + : elytraDurabilityOldMethod(chestplate); + + if (damages > -1) { + progress = Math.max(0, 1 - damages / ((double) chestplate.getType().getMaxDurability())); + alterColor(progress); + } + } + } + + if (progress == null) progress = sc.config.getDouble("compass.BOSSBAR.attributes.progress"); + + sc.cache.set(owner.getUniqueId(), cacheKey, progress, sc.config.getInt("delays.elytra_durability") * 1000); + return progress; + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/managers/CompassManager.java b/src/main/java/me/arboriginal/SimpleCompass/managers/CompassManager.java new file mode 100644 index 0000000..570a315 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/managers/CompassManager.java @@ -0,0 +1,245 @@ +package me.arboriginal.SimpleCompass.managers; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; +import org.bukkit.configuration.MemorySection; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.scheduler.BukkitRunnable; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; +import me.arboriginal.SimpleCompass.compasses.ActionbarCompass; +import me.arboriginal.SimpleCompass.compasses.BossbarCompass; +import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public class CompassManager { + private HashMap> compasses; + + public enum RequirementsSections { + HOTBAR, INVENTORY, MAIN_HAND, OFF_HAND, + } + + private SimpleCompass sc; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public CompassManager(SimpleCompass plugin) { + sc = plugin; + compasses = new HashMap>(); + for (CompassTypes type : CompassTypes.values()) compasses.put(type, new HashMap()); + } + + // Misc methods ---------------------------------------------------------------------------------------------------- + + public void commandTrigger(String command) { + if (sc.config.getList("commands_trigger_refresh").contains(command.split(" ")[0])) + for (Player player : sc.getServer().getOnlinePlayers()) sc.tasks.set(TasksTypes.REFRESH_STATUS, player); + } + + public void unload() { + removeCompass(); + } + + // Compass methods ------------------------------------------------------------------------------------------------- + + public void createCompass(CompassTypes type, Player player) { + UUID uid = player.getUniqueId(); + AbstractCompass compass = getCompass(type, uid); + if (compass != null) return; + + switch (type) { // @formatter:off + case ACTIONBAR: compass = new ActionbarCompass(sc, player); break; + case BOSSBAR: compass = new BossbarCompass(sc, player); break; + } // @formatter:on + + if (compass != null) { + BukkitRunnable task = sc.tasks.get(TasksTypes.REMOVEWARNING, uid); + if (task != null) task.run(); + compasses.get(type).put(uid, compass); + } + } + + public AbstractCompass getCompass(CompassTypes type, UUID uid) { + return compasses.get(type).get(uid); + } + + public void refreshCompass(Player player, CompassTypes type) { + refreshCompassState(player, type); + refreshCompassDatas(player, type); + } + + public void removeCompass() { + for (CompassTypes type : CompassTypes.values()) removeCompass(type); + } + + public void removeCompass(CompassTypes type) { + Iterator it = compasses.get(type).keySet().iterator(); + while (it.hasNext()) { + AbstractCompass compass = getCompass(type, it.next()); + if (compass != null) compass.delete(); + it.remove(); + } + } + + public void removeCompass(Player player) { + for (CompassTypes type : CompassTypes.values()) removeCompass(type, player); + } + + public void removeCompass(CompassTypes type, Player player) { + removeCompass(type, player.getUniqueId()); + } + + public void removeCompass(CompassTypes type, UUID uid) { + AbstractCompass compass = getCompass(type, uid); + if (compass == null) return; + compass.delete(); + compasses.get(type).remove(uid); + } + + // Compass state methods ------------------------------------------------------------------------------------------- + + public boolean getCompassState(Player player, CompassTypes type) { + if (!player.hasPermission("scompass.use") || !player.hasPermission("scompass.use." + type)) return false; + + boolean active = false; + + switch (sc.datas.compassOptionGet(player, type)) { // @formatter:off + case ALWAYS: active = true; break; + case VEHICLE: active = player.isInsideVehicle(); break; + case ELYTRA: active = player.isGliding(); break; + case ELYTRA_VEHICLE: active = (player.isInsideVehicle() || player.isGliding()); break; + default: active = false; + } // @formatter:on + + return active && hasRequiredItems(player, type, true); + } + + public void refreshCompassState() { + for (Player player : sc.getServer().getOnlinePlayers()) refreshCompassState(player); + } + + public void refreshCompassState(CompassTypes type) { + for (Player player : sc.getServer().getOnlinePlayers()) refreshCompassState(player, type); + } + + public void refreshCompassState(Player player) { + for (CompassTypes type : CompassTypes.values()) refreshCompassState(player, type); + } + + public void refreshCompassState(Player player, CompassTypes type) { + if (getCompassState(player, type)) createCompass(type, player); + else removeCompass(type, player); + } + + // Compass item requirements methods ------------------------------------------------------------------------------- + + ItemStack consumeItem(Player player, CompassTypes type, ItemStack stack) { + stack.setAmount(stack.getAmount() - 1); + sc.datas.cooldownConsumeSet(player, type); + return stack; + } + + public boolean hasRequiredItems(Player player, CompassTypes type, boolean consume) { + if (((MemorySection) sc.config.get("compass." + type + ".require.items")).getKeys(false).isEmpty()) return true; + + List lores = sc.config.getStringList("ignored_lores"); + PlayerInventory inv = player.getInventory(); + ItemStack stack; + + consume &= shouldConsume(player, type); + + for (RequirementsSections section : RequirementsSections.values()) { + List items = sc.config.getStringList("compass." + type + ".require.items." + section); + if (items.isEmpty()) continue; + + switch (section) { + case OFF_HAND: + stack = inv.getItemInOffHand(); + + if (stack != null && isValidItem(stack, items, lores)) { + if (consume) inv.setItemInOffHand(consumeItem(player, type, stack)); + return true; + } + break; + + case MAIN_HAND: + stack = inv.getItemInMainHand(); + + if (stack != null && isValidItem(stack, items, lores)) { + if (consume) inv.setItemInMainHand(consumeItem(player, type, stack)); + return true; + } + break; + + case HOTBAR: + case INVENTORY: // @formatter:off + for (int i = (section == RequirementsSections.HOTBAR ? 0 : 9); + i <= (section == RequirementsSections.HOTBAR ? 8 : 35); i++) { // @formatter:on + stack = inv.getItem(i); + if (stack == null) continue; + + if (isValidItem(stack, items, lores)) { + if (consume) inv.setItem(i, consumeItem(player, type, stack)); + return true; + } + } + break; + } + } + + return false; + } + + public boolean isValidItem(ItemStack stack, List requiredItems, List ignoredLores) { + if (!requiredItems.contains(stack.getType().toString())) return false; + if (ignoredLores.isEmpty()) return true; + + List itemLores = stack.getItemMeta().getLore(); + if (itemLores == null) return true; + + for (Object lore : stack.getItemMeta().getLore()) if (ignoredLores.contains(lore)) return false; + return true; + } + + public boolean shouldConsume(Player player, CompassTypes type) { + return sc.config.getBoolean("compass." + type + ".require.consume") + && !player.hasPermission("scompass.use.free") + && sc.datas.cooldownConsumeGet(player, type) < 1; + } + + // Compass data methods -------------------------------------------------------------------------------------------- + + public void refreshCompassDatas() { + for (CompassTypes type : CompassTypes.values()) refreshCompassDatas(type); + } + + public void refreshCompassDatas(CompassTypes type) { + for (UUID uid : compasses.get(type).keySet()) refreshCompassDatas(type, uid); + } + + public void refreshCompassDatas(CompassTypes type, UUID uid) { + AbstractCompass compass = getCompass(type, uid); + if (compass == null) return; + + if (!((MemorySection) sc.config.get("compass." + type + ".require.items")).getKeys(false).isEmpty() + && shouldConsume(compass.owner, type) && !hasRequiredItems(compass.owner, type, true)) + removeCompass(type, compass.owner); + else compass.refresh(); + } + + public void refreshCompassDatas(Player player) { + refreshCompassDatas(player.getUniqueId()); + } + + public void refreshCompassDatas(Player player, CompassTypes type) { + refreshCompassDatas(type, player.getUniqueId()); + } + + public void refreshCompassDatas(UUID uid) { + for (CompassTypes type : CompassTypes.values()) refreshCompassDatas(type, uid); + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/managers/DataManager.java b/src/main/java/me/arboriginal/SimpleCompass/managers/DataManager.java new file mode 100644 index 0000000..42926b7 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/managers/DataManager.java @@ -0,0 +1,210 @@ +package me.arboriginal.SimpleCompass.managers; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import me.arboriginal.SimpleCompass.commands.AbstractCommand.CompassOptions; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; +import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; +import me.arboriginal.SimpleCompass.utils.CacheUtil; + +public class DataManager { + private SimpleCompass sc; + private File file; + + public YamlConfiguration users; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public DataManager(SimpleCompass plugin) { + sc = plugin; + users = new YamlConfiguration(); + file = new File(sc.getDataFolder(), "usersDatas.yml"); + + if (file.exists()) users = YamlConfiguration.loadConfiguration(file); + else saveUserDatas(); + } + + // General methods ------------------------------------------------------------------------------------------------- + + public String getKey(Player player, String key) { + return player.getUniqueId() + "." + key; + } + + public boolean saveUserDatas() { + try { + if (!file.exists()) file.createNewFile(); + users.save(file); + return true; + } + catch (IOException e) { + sc.getLogger().severe(sc.prepareMessage("file_not_writable")); + } + + return false; + } + + // Cooldown methods ------------------------------------------------------------------------------------------------ + + public Long cooldownGet(Player player, String cooldown) { + String dataKey = cooldownKey(player, cooldown); + + if (users.contains(dataKey)) { + Long left = users.getLong(dataKey) - CacheUtil.now(); + if (left > 0) return left; + } + + return 0L; + } + + public String cooldownKey(Player player, String cooldown) { + return getKey(player, "cooldowns." + cooldown); + } + + public void cooldownSet(Player player, String cooldown, int delay) { + users.set(cooldownKey(player, cooldown), CacheUtil.now() + delay * 1000); + saveUserDatas(); + } + + // Book cooldown + + public String cooldownBook() { + return "interface_book"; + } + + public Long cooldownBookGet(Player player) { + return cooldownGet(player, cooldownBook()); + } + + public void cooldownBookSet(Player player) { + cooldownSet(player, cooldownBook(), sc.config.getInt("interface.give_book_cooldown")); + } + + // Consume cooldown + + public String cooldownConsume(CompassTypes type) { + return "consume_" + type; + } + + public Long cooldownConsumeGet(Player player, CompassTypes type) { + return cooldownGet(player, cooldownConsume(type)); + } + + public void cooldownConsumeSet(Player player, CompassTypes type) { + cooldownSet(player, cooldownConsume(type), sc.config.getInt("compass." + type + ".require.duration")); + } + + // Compass options methods ----------------------------------------------------------------------------------------- + + public CompassOptions compassOptionGet(Player player, CompassTypes type) { + String key = compassOptionKey(player, type); + return CompassOptions.valueOf(users.contains(key) ? users.getString(key) + : sc.config.getString("compass." + type + ".default.option")); + } + + public String compassOptionKey(Player player, CompassTypes type) { + return getKey(player, type + ".option"); + } + + public void compassOptionSet(Player player, CompassTypes type, CompassOptions option) { + if (sc.config.getBoolean("single_compass_mode") && option != CompassOptions.DISABLED) + for (CompassTypes otherType : CompassTypes.values()) if (type != otherType) { + users.set(compassOptionKey(player, otherType), CompassOptions.DISABLED.toString()); + sc.compasses.removeCompass(otherType, player); + } + + users.set(compassOptionKey(player, type), option.toString()); + saveUserDatas(); + + sc.tasks.set(TasksTypes.valueOf("REFRESH_" + type), player); + } + + public void compassOptionToggle(Player player) { + String key = getKey(player, "toggle"); + + ConfigurationSection previous = users.getConfigurationSection(key); + for (CompassTypes type : CompassTypes.values()) { + CompassOptions option = compassOptionGet(player, type); + + if (previous == null) { + users.set(key + "." + type, option.toString()); + users.set(compassOptionKey(player, type), CompassOptions.DISABLED.toString()); + } + else users.set(compassOptionKey(player, type), previous.get(type.toString())); + } + + if (previous == null) sc.sendMessage(player, "toggle_state_saved"); + else { + users.set(key, null); + sc.sendMessage(player, "toggle_state_restored"); + } + + sc.tasks.set(TasksTypes.REFRESH_STATUS, player); + saveUserDatas(); + } + + // Compass modes methods ------------------------------------------------------------------------------------------- + + public CompassModes compassModeGet(Player player, CompassTypes type) { + String key = compassModeKey(player, type); + return CompassModes.valueOf(users.contains(key) ? users.getString(key) + : sc.config.getString("compass." + type + ".default.mode")); + } + + public String compassModeKey(Player player, CompassTypes type) { + return getKey(player, type + ".mode"); + } + + public void compassModeSet(Player player, CompassTypes type, CompassModes mode) { + users.set(compassModeKey(player, type), mode.toString()); + saveUserDatas(); + + sc.tasks.set(TasksTypes.valueOf("REFRESH_" + type), player); + } + + // Tracker targets methods ----------------------------------------------------------------------------------------- + + public boolean activeTargetAdd(Player player, String type, String name) { + List list = activeTargetsList(player, type); + if (list.contains(name)) return false; + + list.add(name); + activeTargetsSave(player, type, list); + return true; + } + + public boolean activeTargetDel(Player player, String type, String name) { + List list = activeTargetsList(player, type); + if (!list.contains(name)) return false; + + list.remove(name); + activeTargetsSave(player, type, list); + return true; + } + + public String activeTargetsKey(Player player, String type) { + return getKey(player, "active_targets." + type); + } + + public List activeTargetsList(Player player, String type) { + String key = activeTargetsKey(player, type); + List list = new ArrayList(); + + if (users.getList(key) != null) for (String target : users.getStringList(key)) list.add(target); + + return list; + } + + public void activeTargetsSave(Player player, String type, List list) { + users.set(activeTargetsKey(player, type), list); + saveUserDatas(); + sc.tasks.set(TasksTypes.REFRESH_ACTIONBAR, player); + sc.tasks.set(TasksTypes.REFRESH_BOSSBAR, player); + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/managers/TargetManager.java b/src/main/java/me/arboriginal/SimpleCompass/managers/TargetManager.java new file mode 100644 index 0000000..244f7df --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/managers/TargetManager.java @@ -0,0 +1,173 @@ +package me.arboriginal.SimpleCompass.managers; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; +import org.bukkit.entity.Player; +import com.google.common.collect.ImmutableMap; +import me.arboriginal.SimpleCompass.plugin.AbstractTracker; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public class TargetManager { + private SimpleCompass sc; + public String[] trackersPriority; + + public HashMap>> activeTargets; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public TargetManager(SimpleCompass plugin) { + sc = plugin; + activeTargets = new HashMap>>(); + + for (String trackerID : sc.trackers.keySet()) activeTargets.put(trackerID, new HashMap>()); + + trackersPriority = new String[sc.trackers.size()]; + if (sc.trackers.size() == 0) return; + + List priority = sc.config.getStringList("trackers_priorities"); + for (int i = 0; i < priority.size(); i++) trackersPriority[i] = priority.get(i); + } + + // Trackers methods ------------------------------------------------------------------------------------------------ + + public boolean canUseTracker(Player player, String trackerID) { + return player.hasPermission("scompass.track.*") || player.hasPermission("scompass.track." + trackerID); + } + + public List getAvailableTrackers(Player player) { + List list = new ArrayList(); + for (String trackerID : sc.trackers.keySet()) if (canUseTracker(player, trackerID)) list.add(trackerID); + return list; + } + + public AbstractTracker getTrackerByName(String name) { + for (String trackerID : sc.trackers.keySet()) { + AbstractTracker tracker = sc.trackers.get(trackerID); + if (name.toLowerCase().equals(tracker.trackerName().toLowerCase())) return tracker; + } + + return null; + } + + public List getTrackersList(Player player, String startWith) { + List list = new ArrayList(); + + for (String trackerID : sc.targets.getAvailableTrackers(player)) { + String name = sc.trackers.get(trackerID).trackerName(); + if (name.toLowerCase().startsWith(startWith.toLowerCase())) list.add(name); + } + + return list; + } + + // Targets methods ------------------------------------------------------------------------------------------------- + + public void activateTarget(Player player, String type, String name) { + UUID uid = player.getUniqueId(); + + if (!activeTargets.get(type).containsKey(uid)) activeTargets.get(type).put(uid, new ArrayList()); + if (activeTargets.get(type).get(uid).contains(name)) return; + + activeTargets.get(type).get(uid).add(name); + sc.datas.activeTargetAdd(player, type, name); + } + + public void disableTarget(Player player, String type, String name) { + UUID uid = player.getUniqueId(); + + if (!activeTargets.get(type).containsKey(uid)) return; + if (!activeTargets.get(type).get(uid).contains(name)) return; + + activeTargets.get(type).get(uid).remove(name); + sc.datas.activeTargetDel(player, type, name); + } + + public HashMap>> getTargetsCoords(Player player) { + HashMap>> list // @formatter:off + = new HashMap>>(); + // @formatter:on + list.put("on", new HashMap>()); + list.put("off", new HashMap>()); + + HashMap> stop = new HashMap>(); + + UUID uid = player.getUniqueId(); + + List invalids = new ArrayList(); + + for (String trackerID : sc.trackers.keySet()) { + AbstractTracker tracker = sc.trackers.get(trackerID); + if (tracker == null) continue; + + HashMap sublistOn = new HashMap(); + + if (activeTargets.get(trackerID).containsKey(uid)) { + ArrayList closest = new ArrayList(); + + Iterator it = activeTargets.get(trackerID).get(uid).iterator(); + while (it.hasNext()) { + String name = it.next(); + double[] coords = tracker.get(player, name); + if (coords == null) invalids.add(trackerID + ":" + name); + if (coords == null || tracker.playerIsClose(player, coords)) closest.add(name); + else sublistOn.put(name, coords); + } + + if (!sublistOn.isEmpty()) list.get("on").put(trackerID, new ArrayList(sublistOn.values())); + if (!closest.isEmpty()) stop.put(tracker, closest); + } + + if (tracker.settings.getBoolean("settings.inactive_target", false)) { + ArrayList sublistOff = new ArrayList(); + + for (String name : tracker.availableTargets(player, "")) { + if (sublistOn.containsKey(name)) continue; + double[] coords = tracker.get(player, name); + if (coords != null) sublistOff.add(coords); + } + + if (!sublistOff.isEmpty()) list.get("off").put(trackerID, sublistOff); + } + } + + if (!stop.isEmpty()) { + stop.forEach((tracker, stopped) -> { + stopped.forEach(name -> { + tracker.disable(player, name); + if (!invalids.contains(tracker.trackerID() + ":" + name)) tracker.sendMessage(player, + "target_auto_disabled", ImmutableMap.of("tracker", tracker.trackerName(), "target", name)); + }); + }); + } + + return list; + } + + public boolean loadTargets() { + boolean hasLoadedTrackers = false; + for (Player player : sc.getServer().getOnlinePlayers()) if (loadTargets(player)) hasLoadedTrackers = true; + return hasLoadedTrackers; + } + + public boolean loadTargets(Player player) { + boolean hasLoadedTrackers = false; + + for (String trackerID : sc.trackers.keySet()) { + List targets = sc.datas.activeTargetsList(player, trackerID); + if (!targets.isEmpty()) hasLoadedTrackers = true; + for (String name : targets) activateTarget(player, trackerID, name); + } + + return hasLoadedTrackers; + } + + public void unloadTargets(Player player) { + UUID uid = player.getUniqueId(); + + for (String trackerID : sc.trackers.keySet()) + if (activeTargets.get(trackerID).containsKey(uid)) activeTargets.get(trackerID).remove(uid); + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/managers/TaskManager.java b/src/main/java/me/arboriginal/SimpleCompass/managers/TaskManager.java new file mode 100644 index 0000000..f982424 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/managers/TaskManager.java @@ -0,0 +1,154 @@ +package me.arboriginal.SimpleCompass.managers; + +import java.util.HashMap; +import java.util.UUID; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; +import me.arboriginal.SimpleCompass.compasses.BossbarCompass; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public class TaskManager { + private SimpleCompass sc; + + private HashMap> tasks; + + public enum TasksTypes { + FIX_UUID, REFRESH_ACTIONBAR, REFRESH_BOSSBAR, REFRESH_STATUS, REMOVEWARNING, + } + + // Constructor methods --------------------------------------------------------------------------------------------- + + public TaskManager(SimpleCompass plugin) { + sc = plugin; + tasks = new HashMap>(); + for (TasksTypes type : TasksTypes.values()) tasks.put(type, new HashMap()); + } + + // Tasks methods --------------------------------------------------------------------------------------------------- + + public void clear() { + for (TasksTypes type : TasksTypes.values()) clear(type); + } + + public void clear(Player player) { + clear(player.getUniqueId()); + } + + public void clear(UUID uid) { + for (TasksTypes type : TasksTypes.values()) clear(type, uid); + } + + public void clear(TasksTypes type) { + for (UUID uid : tasks.get(type).keySet()) clear(type, uid); + } + + public void clear(TasksTypes type, Player player) { + clear(type, player.getUniqueId()); + } + + public void clear(TasksTypes type, UUID uid) { + clear(type, uid, get(type, uid)); + } + + public void clear(TasksTypes type, UUID uid, BukkitRunnable task) { + if (task == null) task = get(type, uid); + if (task != null) { + task.cancel(); + tasks.get(type).remove(uid); + } + } + + public BukkitRunnable get(TasksTypes type, UUID uid) { + return tasks.get(type).get(uid); + } + + public void set(TasksTypes type, Player player) { + set(type, player, null); + } + + public void set(TasksTypes type, Player player, Object data) { + UUID uid = player.getUniqueId(); + + if (!sc.isReady) { + if (data != null && data instanceof BossbarCompass) ((BossbarCompass) data).bossbar.removeAll(); + clear(type, uid); + return; + } + + BukkitRunnable task = null; + + switch (type) { + case FIX_UUID: + task = new BukkitRunnable() { + @Override + public void run() { + if (isCancelled() || sc.compasses.getCompass(CompassTypes.BOSSBAR, uid) == null) return; + sc.compasses.removeCompass(CompassTypes.BOSSBAR, player); + sc.compasses.refreshCompassState(player); + clear(type, uid, this); + + if (sc.trackers.isEmpty()) return; + sc.trackers.forEach((trackerID, tracker) -> { + for (String name : tracker.autoloadTargets(player, "")) + tracker.activate(player, name, false); + }); + } + }; + + task.runTaskLaterAsynchronously(sc, sc.config.getInt("delays.fix_uuid")); + break; + + case REFRESH_ACTIONBAR: + case REFRESH_BOSSBAR: + CompassTypes compassType = CompassTypes.valueOf(type.toString().substring(8)); + + task = new BukkitRunnable() { + @Override + public void run() { + if (isCancelled()) return; + sc.compasses.refreshCompass(player, compassType); + clear(type, uid, this); + } + }; + + task.runTaskLaterAsynchronously(sc, sc.config.getInt("delays.option_take_effect")); + break; + + case REFRESH_STATUS: + task = new BukkitRunnable() { + @Override + public void run() { + if (isCancelled()) return; + sc.compasses.refreshCompassState(player); + clear(type, uid, this); + } + }; + + task.runTaskLaterAsynchronously(sc, + (data == null || !(data instanceof Integer)) ? sc.config.getInt("delays.refresh_status") + : (int) data); + break; + + case REMOVEWARNING: + if (data == null || !(data instanceof BossbarCompass)) break; + + task = new BukkitRunnable() { + @Override + public void run() { + if (isCancelled()) return; + ((BossbarCompass) data).bossbar.removeAll(); + this.cancel(); + } + }; + + task.runTaskLaterAsynchronously(sc, sc.config.getInt("compass.BOSSBAR.warnPlayerNoMoreFuel") * 20); + break; + } + + if (task != null) { + clear(type, uid); + tasks.get(type).put(uid, task); + } + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/plugin/AbstractTracker.java b/src/main/java/me/arboriginal/SimpleCompass/plugin/AbstractTracker.java new file mode 100644 index 0000000..c3ae53b --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/plugin/AbstractTracker.java @@ -0,0 +1,402 @@ +package me.arboriginal.SimpleCompass.plugin; + +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.MemorySection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import com.google.common.collect.ImmutableMap; + +public abstract class AbstractTracker { + protected SimpleCompass sc; + protected File sf; + protected URL res; + + public enum TrackingActions { + ADD, ACCEPT, ASK, DEL, DENY, HELP, START, STOP, + } + + public enum TargetSelector { + ACTIVE, AVAILABLE, NEW, NEWCOORDS, NONE, + } + + public FileConfiguration settings; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public AbstractTracker(SimpleCompass plugin) { + sc = plugin; + sf = new File(sc.getDataFolder(), "trackers/" + getClass().getSimpleName() + ".yml"); + res = getClass().getResource("/settings.yml"); + } + + // Tracker methods ------------------------------------------------------------------------------------------------- + + public abstract String trackerID(); + + public String github() { + return null; + } + + public String trackerName() { + return settings.getString("locales." + sc.config.getString("language") + ".name"); + } + + public String version() { + return "?"; + } + + // Initialization and update methods ------------------------------------------------------------------------------- + + /** + * At this state, config has not been read from user file, + * so DO NOT USE sc.config here, and DO NOT call methods which use this. + */ + public boolean init() { + if (res == null) { + sc.getLogger().warning("settings.yml missing in " + sf.getAbsolutePath()); + return false; + } + + settings = YamlConfiguration.loadConfiguration(sf); + settings.options().copyDefaults(true); + + InputStream is; + + try { + is = res.openStream(); + } + catch (Exception e) { + sc.getLogger().warning("Can't write default settings to " + sf.getAbsolutePath()); + return false; + } + + settings.setDefaults(YamlConfiguration.loadConfiguration(new InputStreamReader(is))); + + try { + settings.save(sf); + } + catch (Exception e) { + sc.getLogger().severe("Can't write to " + sf.getAbsolutePath()); + return false; + } + + return true; + } + + public void checkUpdate(CommandSender sender) { + if (!settings.getBoolean("settings.check_update", true)) return; + + String github = github(); + + if (github == null) { + sendMessage(sender, "tracker_check_update_available", + ImmutableMap.of("tracker", trackerName(), "version", "new", "current", version())); + return; + } + + String version = sc.githubVersion(github); + + if (version == null) + sendMessage(sender, "tracker_check_update_failed", ImmutableMap.of("tracker", trackerName())); + else { + String current = version(); + if (!version.equals(current)) + sendMessage(sender, "tracker_check_update_available", + ImmutableMap.of("tracker", trackerName(), "version", version, "current", current)); + } + } + + // Utils methods --------------------------------------------------------------------------------------------------- + + public void sendMessage(CommandSender sender, String key) { + sendMessage(sender, key, null); + } + + public void sendMessage(CommandSender sender, String key, Map placeholders) { + if (key.isEmpty()) return; + String message = prepareMessage(key, placeholders); + if (!message.isEmpty()) sender.sendMessage(message); + } + + public String prepareMessage(String key) { + return prepareMessage(key, null); + } + + public String prepareMessage(String key, Map placeholders) { + String message = settings.getString("locales." + sc.config.getString("language") + "." + key); + if (message == null) message = sc.locale.getString(key); + if (message == null) return ""; + + if (placeholders != null) for (Iterator i = placeholders.keySet().iterator(); i.hasNext();) { + String placeholder = i.next(); + message = message.replace("{" + placeholder + "}", placeholders.get(placeholder)); + } + + return sc.formatMessage(message.replace("{prefix}", sc.locale.getString("prefix"))); + } + + // Actions methods ------------------------------------------------------------------------------------------------- + + public TrackingActions getActionByName(String name) { + for (TrackingActions action : TrackingActions.values()) + if (name.equalsIgnoreCase(getActionName(action))) return action; + return null; + } + + public String getActionName(TrackingActions action) { + return sc.locale.getString("actions." + action); + } + + public List getActionsAvailable(Player player, boolean keepUnavailable) { + List list = new ArrayList(); + if (player.hasPermission("scompass.help")) list.add(TrackingActions.HELP); + return list; + } + + public boolean limitReached(Player player, TrackingActions action, boolean showError, Integer current) { + if (!settings.contains("settings.limits." + action)) return false; + int limit = settings.getInt("settings.limits." + action), count; + + if (current == null) { + UUID uid = player.getUniqueId(); + + count = sc.targets.activeTargets.get(trackerID()).containsKey(uid) + ? sc.targets.activeTargets.get(trackerID()).get(uid).size() + : 0; + } + else count = current; + + if (count < limit) return false; + + if (showError) sendMessage(player, "commands.sctrack.limits." + action, + ImmutableMap.of("limit", "" + limit, "tracker", trackerName())); + + return true; + } + + public TargetSelector requireTarget(TrackingActions action) { + switch (action) { // @formatter:off + case ASK: + case DEL: + case START: return TargetSelector.AVAILABLE; + case STOP: return TargetSelector.ACTIVE; + case ADD: return TargetSelector.NEW; + default: return TargetSelector.NONE; + } // @formatter:on + } + + // Targets methods ------------------------------------------------------------------------------------------------- + + public boolean activate(Player player, String name, boolean showError) { + if (limitReached(player, TrackingActions.START, showError, null)) return false; + sc.targets.activateTarget(player, trackerID(), name); + return true; + } + + public List activeTargets(Player player, String startWith) { + List list = new ArrayList(); + + for (String candidate : sc.datas.activeTargetsList(player, trackerID())) + if (startWith.isEmpty() || candidate.toLowerCase().startsWith(startWith.toLowerCase())) list.add(candidate); + + return list; + } + + public List availableTargets(Player player, String startWith) { + List list = new ArrayList(); + String root = key(player); + + if (datas().contains(root)) ((MemorySection) datas().get(root)).getKeys(false).forEach(candidate -> { + if (startWith.isEmpty() || candidate.toLowerCase().startsWith(startWith.toLowerCase())) + list.add(candidate); + }); + + return list; + } + + public List autoloadTargets(Player player, String startWith) { + List list = new ArrayList(); + + if (settings.getBoolean("settings.autoload_target", false)) { + String perm = "scompass.track.auto." + trackerID() + "."; + for (String name : availableTargets(player, startWith)) + if (player.hasPermission(perm + "*") || player.hasPermission(perm + name)) list.add(name); + } + + return list; + } + + public boolean del(Player player, String name) { + String key = key(player, name); + + if (datas().contains(key)) { + disable(player, name); + return save(key, null); + } + + return false; + } + + public void disable(Player player, String name) { + sc.targets.disableTarget(player, trackerID(), name); + } + + public double[] get(Player player, String name) { + String key = key(player, name); + + if (datas().contains(key + ".x") && datas().contains(key + ".z")) + return new double[] { datas().getDouble(key + ".x"), datas().getDouble(key + ".z") }; + + return null; + } + + public double[] getCoords(Player player, String[] args) { + double[] coords = null; + + if (args.length == 5) try { + coords = new double[] { Double.parseDouble(args[3]), Double.parseDouble(args[4]) }; + } + catch (Exception e) {} + + if (coords == null) coords = new double[] { player.getLocation().getX(), player.getLocation().getZ() }; + + return coords; + } + + public List list(Player player, TrackingActions action, String startWith) { + if (action == null) return availableTargets(player, startWith); + + List list = new ArrayList(); + + switch (action) { // @formatter:off + case ACCEPT: + case ADD: + case DENY: break; + + case ASK: + case DEL: + case START: list.addAll(availableTargets(player, startWith)); break; + default: list.addAll(activeTargets(player, startWith)); break; + } // @formatter:on + + return list; + } + + public List listFiltered(Player player, List list) { + if (player.hasPermission("scompass.track." + trackerID() + ".defined.*")) return list; + + List filtered = new ArrayList(); + for (String name : list) + if (player.hasPermission("scompass.track." + trackerID() + ".defined." + name)) filtered.add(name); + + return filtered; + } + + public boolean set(Player player, String name, double[] coords) { + String key = key(player, name); + if (datas().contains(key)) return false; + + String root = key(player); + int current = datas().contains(root) + ? datas().getConfigurationSection(root).getKeys(false).size() + : 0; + + if (limitReached(player, TrackingActions.ADD, true, current)) return false; + + boolean success = (save(key + ".x", coords[0]) && save(key + ".z", coords[1])); + if (success) return true; + + save(key, null); + return false; + } + + public boolean playerIsClose(Player player, double[] coords) { + int dist = settings.getInt("settings.auto_disabled", 0); + return (dist > 0 && player.getLocation().distance( + new Location(player.getWorld(), coords[0], player.getLocation().getY(), coords[1])) < dist); + } + + // Command methods ------------------------------------------------------------------------------------------------- + + public List commandSuggestions(Player player, String[] args, HashMap parsed) { + List list = new ArrayList<>(); + if (args.length < 1 || args.length > 3) return list; + + switch (args.length) { + case 2: + for (TrackingActions action : getActionsAvailable(player, false)) { + String name = getActionName(action); + if (name.toLowerCase().startsWith(args[1].toLowerCase())) list.add(name); + } + break; + + case 3: + list.addAll(list(player, (TrackingActions) parsed.get("action"), args[2])); + break; + } + + return list; + } + + public String help(Player player, String command) { + String s = prepareMessage("commands.sctrack.help.separator") + "\n"; + String h = s + prepareMessage("commands.sctrack.help.header", ImmutableMap.of("tracker", trackerName())) + s; + + List list = new ArrayList(); + list.add("noargs"); + + HashMap placeholders = new HashMap(); + placeholders.put("command", command); + placeholders.put("tracker", trackerName()); + + for (TrackingActions action : getActionsAvailable(player, true)) if (action != TrackingActions.HELP) { + list.add(action.toString()); + placeholders.put(action.toString(), sc.locale.getString("actions." + action)); + } + + for (String key : list) h += prepareMessage("help." + key, placeholders) + "\n"; + return h + s; + } + + public void parseArguments(Player player, String[] args, HashMap parsed) { + TrackingActions action = getActionByName(args[1]); + if (action == null || !getActionsAvailable(player, false).contains(action)) return; + parsed.put("action", action); + if (args.length == 2) return; + if (get(player, args[2]) != null) parsed.put("target", args[2]); + } + + public abstract boolean perform(Player player, String command, TrackingActions action, String target, + String[] args); + + // Storage methods ------------------------------------------------------------------------------------------------- + + public MemorySection datas() { + return sc.datas.users; + } + + public String key(Player player) { + return key(player, null); + } + + public String key(Player player, String name) { + return sc.datas.getKey(player, trackerID() + (name == null ? "" : "." + name)); + } + + public boolean save(String key, Object value) { + datas().set(key, value); + return sc.datas.saveUserDatas(); + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/plugin/Listeners.java b/src/main/java/me/arboriginal/SimpleCompass/plugin/Listeners.java new file mode 100644 index 0000000..e7b75b3 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/plugin/Listeners.java @@ -0,0 +1,143 @@ +package me.arboriginal.SimpleCompass.plugin; + +import java.util.HashMap; +import java.util.UUID; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityPickupItemEvent; +import org.bukkit.event.entity.EntityToggleGlideEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerCommandSendEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerSwapHandItemsEvent; +import org.bukkit.event.server.ServerCommandEvent; +import org.bukkit.event.vehicle.VehicleEnterEvent; +import org.bukkit.event.vehicle.VehicleExitEvent; +import org.bukkit.inventory.InventoryHolder; +import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; +import me.arboriginal.SimpleCompass.utils.CacheUtil; + +public class Listeners implements Listener { + public SimpleCompass sc; + public HashMap locks; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public Listeners(SimpleCompass plugin) { + sc = plugin; + locks = new HashMap(); + } + + // Listener methods ------------------------------------------------------------------------------------------------ + + @EventHandler + public void onEntityPickupItem(EntityPickupItemEvent event) { + if (event.isCancelled() || !isPlayer(event.getEntity())) return; + sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) event.getEntity(), sc.config.getInt("delays.pickup_refresh")); + } + + @EventHandler + public void onEntityToggleGlide(EntityToggleGlideEvent event) { + if (event.isCancelled() || !isPlayer(event.getEntity())) return; + sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) event.getEntity()); + } + + @EventHandler + public void onInventoryClose(InventoryCloseEvent event) { + InventoryHolder holder = event.getInventory().getHolder(); + if (!(holder instanceof Player) || !isPlayer((Player) holder)) return; + sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) holder); + } + + @EventHandler + public void onInventoryOpen(InventoryOpenEvent event) { + if (!event.isCancelled()) sc.tasks.clear(TasksTypes.REFRESH_STATUS, (Player) event.getPlayer()); + } + + @EventHandler + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { + if (!event.isCancelled()) sc.compasses.commandTrigger(event.getMessage().substring(1)); + } + + @EventHandler + public void onPlayerCommandSend(PlayerCommandSendEvent event) { + if (isPlayer(event.getPlayer())) sc.tasks.set(TasksTypes.REFRESH_STATUS, event.getPlayer()); + } + + @EventHandler + public void onPlayerDeath(PlayerDeathEvent event) { + if (isPlayer(event.getEntity())) sc.compasses.removeCompass((Player) event.getEntity()); + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + + sc.cache.init(player.getUniqueId()); + sc.targets.loadTargets(player); + sc.tasks.set(TasksTypes.REFRESH_STATUS, player); + sc.tasks.set(TasksTypes.FIX_UUID, player); + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + if (event.isCancelled()) return; + + Player player = event.getPlayer(); + UUID uid = player.getUniqueId(); + Long now = CacheUtil.now(); + + if (locks.containsKey(uid) && locks.get(uid) > now) return; + + locks.put(uid, now + sc.config.getInt("delays.update_compass")); + sc.compasses.refreshCompassDatas(player); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + UUID uid = player.getUniqueId(); + + locks.remove(uid); + sc.tasks.clear(player); + sc.targets.unloadTargets(player); + sc.cache.clear(uid); + } + + @EventHandler + public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) { + if (!event.isCancelled()) sc.tasks.set(TasksTypes.REFRESH_STATUS, event.getPlayer()); + } + + @EventHandler + public void onVehicleEnter(VehicleEnterEvent event) { + if (event.isCancelled() || !isPlayer(event.getEntered())) return; + sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) event.getEntered()); + } + + @EventHandler + public void onVehicleExit(VehicleExitEvent event) { + if (event.isCancelled() || !isPlayer(event.getExited())) return; + sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) event.getExited()); + } + + @EventHandler + public void onServerCommand(ServerCommandEvent event) { + if (!event.isCancelled()) sc.compasses.commandTrigger(event.getCommand()); + } + + // ----------------------------------------------------------------------------------------------- + // Private methods + // ----------------------------------------------------------------------------------------------- + + private boolean isPlayer(Entity entity) { + return (entity instanceof Player) && !entity.hasMetadata("NPC"); + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/plugin/SimpleCompass.java b/src/main/java/me/arboriginal/SimpleCompass/plugin/SimpleCompass.java new file mode 100644 index 0000000..ad19ae0 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/plugin/SimpleCompass.java @@ -0,0 +1,370 @@ +package me.arboriginal.SimpleCompass.plugin; + +import java.io.File; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import org.apache.commons.lang.time.DurationFormatUtils; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import me.arboriginal.SimpleCompass.commands.InterfaceCommand; +import me.arboriginal.SimpleCompass.commands.OptionCommand; +import me.arboriginal.SimpleCompass.commands.TrackCommand; +import me.arboriginal.SimpleCompass.managers.CompassManager; +import me.arboriginal.SimpleCompass.managers.DataManager; +import me.arboriginal.SimpleCompass.managers.TargetManager; +import me.arboriginal.SimpleCompass.managers.TaskManager; +import me.arboriginal.SimpleCompass.utils.CacheUtil; +import me.arboriginal.SimpleCompass.utils.ConfigUtil; +import me.arboriginal.SimpleCompass.utils.LangUtil; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; + +public class SimpleCompass extends JavaPlugin implements TabCompleter { + public FileConfiguration config, locale; + public CacheUtil cache; + public DataManager datas; + public TaskManager tasks; + public TargetManager targets; + public Listeners listeners; + public CompassManager compasses = null; + public boolean isReady = false; + + public HashMap trackers; + + // JavaPlugin methods ---------------------------------------------------------------------------------------------- + + @Override + public void onDisable() { + super.onDisable(); + + isReady = false; + compasses.unload(); + tasks.clear(); + } + + @Override + public void onEnable() { + super.onEnable(); + + try { + getServer().spigot(); + } + catch (Exception e) { + getServer().getPluginManager().disablePlugin(this); + getLogger().severe("This plugin only works on Spigot servers!"); + // No need to go on, it will not work + return; + } + + loadTrackers(); + reloadConfig(); + checkUpdate(getServer().getConsoleSender()); + + if (!trackers.isEmpty()) getCommand("scompass-track").setExecutor(new TrackCommand(this)); + + getCommand("scompass-option").setExecutor(new OptionCommand(this)); + getCommand("scompass").setExecutor(new InterfaceCommand(this)); + + listeners = new Listeners(this); + getServer().getPluginManager().registerEvents(listeners, this); + } + + @Override + public void onLoad() { + super.onLoad(); + cache = new CacheUtil(this); + } + + @Override + public void reloadConfig() { + super.reloadConfig(); + cache.reset(); + + saveDefaultConfig(); + + isReady = false; + config = getConfig(); + config.options().copyDefaults(true); + locale = new LangUtil(this).getLocale(config.getString("language")); + + for (ConfigUtil.ConfigError error : new ConfigUtil(this).validate(config)) + getLogger().warning(prepareMessage(error.errorKey, error.placeholders)); + + saveConfig(); + + if (compasses != null) compasses.unload(); + + datas = new DataManager(this); + tasks = new TaskManager(this); + targets = new TargetManager(this); + compasses = new CompassManager(this); + + targets.loadTargets(); + compasses.refreshCompassState(); + + isReady = true; + } + + // JavaPlugin methods: Basic commands ------------------------------------------------------------------------------ + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + switch (command.getName().toLowerCase()) { + case "scompass-reload": + reloadConfig(); + + Iterator it = trackers.keySet().iterator(); + while (it.hasNext()) { + String trackerID = it.next(); + + if (!trackers.get(trackerID).init()) { + it.remove(); + sendMessage(sender, "tracker_disabled", ImmutableMap.of("tracker", trackerID)); + } + } + + sendMessage(sender, "configuration_reloaded"); + checkUpdate(sender); + return true; + + case "scompass-toggle": + if (sender instanceof Player) datas.compassOptionToggle((Player) sender); + else sendMessage(sender, "command_only_for_players"); + return true; + } + + return super.onCommand(sender, command, label, args); + } + + // Public methods -------------------------------------------------------------------------------------------------- + + public TextComponent createClickableMessage(String text, Map> commands) { + TextComponent textComponent = new TextComponent(); + + for (String command : commands.keySet()) text = text.replace(command, "§k" + command + "§r"); + + for (BaseComponent component : TextComponent.fromLegacyText(text)) { + if (component instanceof TextComponent) { + Map command = commands.get(((TextComponent) component).getText().trim()); + + if (command != null) { + if (command.containsKey("text")) ((TextComponent) component).setText("§r" + command.get("text")); + + if (command.containsKey("click")) + component.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, command.get("click"))); + + if (command.containsKey("hover")) + component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + TextComponent.fromLegacyText(command.get("hover")))); + } + } + + textComponent.addExtra(component); + } + + return textComponent; + } + + public String formatMessage(String message) { + return ChatColor.translateAlternateColorCodes('&', message); + } + + public String formatTime(long time) { + String[] parts = DurationFormatUtils.formatDuration(time, "HH:mm:ss").split(":"); + String hour = locale.getString("time_display.hour"); + String minute = locale.getString("time_display.minute"); + String second = locale.getString("time_display.second"); + String human = ""; + + if (time < 60000) human = Math.max(Integer.parseInt(parts[2]), 1) + second; + else { + if (time >= 3600000) human = parts[0] + hour + " "; + + human += (time > config.getInt("min_time_to_display_seconds") * 1000) + ? parts[1] + minute + " " + parts[2] + second + : (Integer.parseInt(parts[1]) + 1) + minute; + } + + return human.replaceFirst("^0+(?!$)", ""); + } + + public String githubVersion(String repository) { + String version = (String) cache.versionGet(repository); + if (version != null) return version; + + String url = "https://api.github.com/repos/" + repository + "/releases"; + + try { + HttpURLConnection connexion = (HttpURLConnection) new URL(url).openConnection(); + connexion.addRequestProperty("User-Agent", "SimpleCompass"); + JsonElement element = new JsonParser().parse(new InputStreamReader(connexion.getInputStream())); + + version = element.getAsJsonArray().get(0).getAsJsonObject().get("tag_name").getAsString(); + } + catch (Exception e) {} + + cache.versionSet(repository, version, config.getInt("delays.update_version_cache")); + return version; + } + + public String prepareMessage(String key) { + return prepareMessage(key, null); + } + + public String prepareMessage(String key, Map placeholders) { + String message = locale.getString(key); + + if (placeholders != null) { + for (Iterator i = placeholders.keySet().iterator(); i.hasNext();) { + String placeholder = i.next(); + + message = message.replace("{" + placeholder + "}", placeholders.get(placeholder)); + } + } + + return formatMessage(message.replace("{prefix}", locale.getString("prefix"))); + } + + public void sendMessage(CommandSender sender, String key) { + sendMessage(sender, key, null); + } + + public void sendMessage(CommandSender sender, String key, Map placeholders) { + if (key.isEmpty()) return; + + String message = prepareMessage(key, placeholders); + + if (!message.isEmpty()) sender.sendMessage(message); + } + + // Private methods ------------------------------------------------------------------------------------------------- + + private void checkUpdate(CommandSender sender) { + if (!config.getBoolean("check_update")) return; + String version = githubVersion("arboriginal/SimpleCompass"); + + if (version == null) sendMessage(sender, "plugin_check_update_failed"); + else { + String current = getDescription().getVersion(); + if (!version.equals(current)) sendMessage(sender, "plugin_check_update_available", + ImmutableMap.of("version", version, "current", current)); + } + + if (trackers.isEmpty()) return; + trackers.forEach((trackerID, tracker) -> { + tracker.checkUpdate(sender); + }); + } + + private void loadTrackers() { + File dir = new File(getDataFolder(), "trackers"); + if (!dir.exists()) dir.mkdirs(); + + if (!dir.exists() || !dir.isDirectory()) { + getLogger().severe("Unable to create trackers folder..."); + return; + } + + trackers = new HashMap(); + for (final File file : dir.listFiles()) { + if (file.isDirectory() || !file.getName().endsWith(".jar")) continue; + + Exception error = loadTrackerFile(file); + + if (error == null) + getLogger().info("Tracker §6{tracker}§r successfully loaded".replace("{tracker}", file.getName())); + else getLogger().severe("Error loading tracker " + file.getName() + ": " + error.getMessage()); + } + } + + private Exception loadTrackerException(URLClassLoader loader, JarFile jar, String message) { + if (loader != null) try { + loader.close(); + } + catch (Exception e) {} + + if (jar != null) try { + jar.close(); + } + catch (Exception e) {} + + return new Exception(message); + } + + private Exception loadTrackerFile(File file) { + URLClassLoader loader = null; + JarFile jar = null; + + try { + loader = new URLClassLoader(new URL[] { new URL("jar:" + file.toURI().toURL() + "!/") }, getClassLoader()); + } + catch (Exception e) { + return loadTrackerException(loader, jar, "Can't initialize a class loader from " + file.getName()); + } + + Enumeration entries = null; + + try { + jar = new JarFile(file.getAbsolutePath()); + entries = jar.entries(); + } + catch (Exception e) {} + + if (entries == null) return loadTrackerException(loader, jar, "Can't read content of " + file.getName()); + + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (entry.isDirectory() || !entry.getName().endsWith(".class")) continue; + + String className = entry.getName().substring(0, entry.getName().length() - 6).replace('/', '.'); + Object tracker = null; + + try { + tracker = Class.forName(className, true, loader).getConstructor(this.getClass()).newInstance(this); + } + catch (NoClassDefFoundError e) { + return loadTrackerException(loader, jar, + "Can't find class " + className + " in " + file.getName() + "..."); + } + catch (Exception e) { + return loadTrackerException(loader, jar, + "Can't load class " + className + " from " + file.getName() + "..."); + } + + if (!(tracker instanceof AbstractTracker)) continue; + String trackrID = ((AbstractTracker) tracker).trackerID(); + + if (trackers.containsKey(trackrID)) return loadTrackerException(loader, jar, + "Tracker {tracker} is using the ID {id} which is already used by {other}..." + .replace("{tracker}", file.getName()).replace("id", trackrID) + .replace("{other}", trackers.get(trackrID).getClass().getSimpleName())); + + if (!((AbstractTracker) tracker).init()) return loadTrackerException(loader, jar, + "Tracker {tracker} failed on init...".replace("{tracker}", file.getName()).replace("id", trackrID)); + + trackers.put(trackrID, (AbstractTracker) tracker); + loadTrackerException(loader, jar, ""); + return null; + } + + return loadTrackerException(loader, jar, "No tracker found in the jar file..."); + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/utils/CacheUtil.java b/src/main/java/me/arboriginal/SimpleCompass/utils/CacheUtil.java new file mode 100644 index 0000000..dc97a50 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/utils/CacheUtil.java @@ -0,0 +1,103 @@ +package me.arboriginal.SimpleCompass.utils; + +import java.io.File; +import java.util.HashMap; +import java.util.UUID; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public class CacheUtil { + private SimpleCompass sc; + private File vcf; + private FileConfiguration vcc; + private HashMap> datas; + + public static final int PERMANENT = -1; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public CacheUtil(SimpleCompass plugin) { + sc = plugin; + vcf = new File(sc.getDataFolder(), "versionCache.yml"); + + if (!vcf.exists()) try { + if (!sc.getDataFolder().exists()) sc.getDataFolder().mkdirs(); + vcf.createNewFile(); + } + catch (Exception e) { + sc.getLogger().warning("Can't write to version cache file"); + } + + vcc = YamlConfiguration.loadConfiguration(vcf); + reset(); + } + + // Static methods -------------------------------------------------------------------------------------------------- + + public static long now() { + return System.currentTimeMillis(); + } + + // Public methods -------------------------------------------------------------------------------------------------- + + public void clear(UUID uid) { + datas.remove(uid); + } + + public void clear(UUID uid, String key) { + datas.get(uid).remove(key); + } + + public Object get(UUID uid, String key) { + if (!datas.containsKey(uid)) return null; + Data data = datas.get(uid).get(key); + return (data != null && (data.expire == PERMANENT || data.expire > now())) ? data.value : null; + } + + public void init(UUID uid) { + datas.put(uid, new HashMap()); + } + + public void reset() { + datas = new HashMap>(); + for (Player player : sc.getServer().getOnlinePlayers()) init(player.getUniqueId()); + } + + public void set(UUID uid, String key, Object value, int duration) { + if (!datas.containsKey(uid)) init(uid); + datas.get(uid).put(key, new Data((duration == PERMANENT) ? PERMANENT : now() + duration, value)); + } + + // Public methods: Version update check cache ---------------------------------------------------------------------- + + public Object versionGet(String key) { + long expire = vcc.getLong("version." + key + ".expire", 0); + return (expire > now()) ? vcc.get("version." + key + ".value", null) : null; + } + + public void versionSet(String key, Object value, int duration) { + vcc.set("version." + key + ".expire", now() + duration * 60000); + vcc.set("version." + key + ".value", value); + + try { + vcc.save(vcf); + } + catch (Exception e) { + sc.getLogger().warning("Can't write to version cache file"); + } + } + + // Private classes ------------------------------------------------------------------------------------------------- + + private static class Data { + public long expire; + public Object value; + + Data(long expiration, Object datas) { + expire = expiration; + value = datas; + } + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/utils/ConfigUtil.java b/src/main/java/me/arboriginal/SimpleCompass/utils/ConfigUtil.java new file mode 100644 index 0000000..489556c --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/utils/ConfigUtil.java @@ -0,0 +1,258 @@ +package me.arboriginal.SimpleCompass.utils; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import org.apache.commons.lang.StringUtils; +import org.bukkit.Material; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarStyle; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.MemoryConfiguration; +import org.bukkit.configuration.file.FileConfiguration; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import me.arboriginal.SimpleCompass.commands.AbstractCommand.CompassOptions; +import me.arboriginal.SimpleCompass.commands.AbstractCommand.SubCmds; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; +import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; +import me.arboriginal.SimpleCompass.managers.CompassManager.RequirementsSections; +import me.arboriginal.SimpleCompass.plugin.AbstractTracker; +import me.arboriginal.SimpleCompass.plugin.AbstractTracker.TrackingActions; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public class ConfigUtil { + private List errors; + private SimpleCompass sc; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public ConfigUtil(SimpleCompass plugin) { + sc = plugin; + } + + // Public methods -------------------------------------------------------------------------------------------------- + + public List validate(FileConfiguration configuration) { + clearErrors(); + + List modified = new ArrayList(); + + modified.addAll(validateCustomNames(TrackingActions.values(), "actions")); + modified.addAll(validateCustomNames(SubCmds.values(), "subcommands")); + + if (!modified.isEmpty()) + addError("invalid_names", ImmutableMap.of("modified", String.join(" ,", modified))); + + validateTrackerSettings(); + validateBossbarAttributes(); + + for (CompassTypes type : CompassTypes.values()) { + validateDefaultSettings(type); + + for (CompassModes mode : CompassModes.values()) validateCardinals(type, mode); + + boolean hasRequirements = false; + + for (RequirementsSections section : RequirementsSections.values()) + if (!validateRequiredItems(type, section).isEmpty()) hasRequirements = true; + + if (!hasRequirements) { + fixValue("compass." + type + ".require.items", new MemoryConfiguration()); + fixValue("compass." + type + ".require.consume", false); + } + } + + return errors; + } + + public void clearErrors() { + errors = new ArrayList(); + } + + // Private methods ------------------------------------------------------------------------------------------------- + + private void addError(String errorKey) { + addError(errorKey, null); + } + + private void addError(String errorKey, Map placeholders) { + errors.add(new ConfigError(errorKey, placeholders)); + } + + private void fixValue(String key) { + fixValue(key, sc.config.getDefaults().get(key)); + } + + private void fixValue(String key, Object value) { + sc.config.set(key, value); + } + + private void validateBossbarAttributes() { + try { + BarColor.valueOf(sc.config.getString("compass.BOSSBAR.attributes.color")); + } + catch (Exception e) { + addError("invalid_bossbar_color"); + fixValue("compass.BOSSBAR.attributes.color"); + } + + try { + BarStyle.valueOf(sc.config.getString("compass.BOSSBAR.attributes.style")); + } + catch (Exception e) { + addError("invalid_bossbar_style"); + fixValue("compass.BOSSBAR.attributes.style"); + } + + ConfigurationSection levels = sc.config + .getConfigurationSection("compass.BOSSBAR.attributes.elytra_durability.levels"); + + if (levels == null) return; + + TreeMap sortedLevel = new TreeMap(); + + for (String level : levels.getKeys(false)) { + try { + BarColor.valueOf(levels.get(level).toString()); + sortedLevel.put(Integer.parseInt(level), levels.get(level).toString()); + } + catch (Exception e) {} + } + + if (levels.getKeys(false).size() != sortedLevel.size()) addError("invalid_bossbar_color_level"); + + fixValue("compass.BOSSBAR.attributes.elytra_durability.levels", sortedLevel); + } + + private void validateCardinals(CompassTypes type, CompassModes mode) { + String key = type + "." + mode; + String fillChar = sc.config.getString("compass." + key + ".cardinals.filling_char"); + + if (fillChar.isEmpty()) return; + + List cardinals = ImmutableList.of("east", "north", "south", "west"); + + int maxLength = 0; + + for (String cardinal : cardinals) + maxLength = Math.max(maxLength, sc.config.getString("compass." + key + ".cardinals." + cardinal).length()); + + for (String cardinal : cardinals) { + String word = sc.config.getString("compass." + key + ".cardinals." + cardinal); + + if (word.length() < maxLength) { + word = StringUtils.repeat(fillChar, (int) Math.floor((double) (maxLength - word.length()) / 2)) + word + + StringUtils.repeat(fillChar, (int) Math.ceil((double) (maxLength - word.length()) / 2)); + + fixValue("compass." + key + ".cardinals." + cardinal, word); + addError("cardinal_length", ImmutableMap.of("key", key, "cardinal", cardinal)); + } + } + } + + private List validateCustomNames(Object[] values, String section) { + List modified = new ArrayList(); + + for (Object obj : values) { + String key = section + "." + obj; + + if (sc.locale.getString(key).contains(" ")) { + sc.locale.getString(sc.locale.getString(key).replaceAll(" ", "")); + modified.add(key); + } + } + + return modified; + } + + private void validateDefaultSettings(CompassTypes type) { + try { + CompassOptions.valueOf(sc.config.getString("compass." + type + ".default.option")); + } + catch (Exception e) { + addError("invalid_choice", ImmutableMap.of("type", "" + type, "key", "option")); + fixValue("compass." + type + ".default.option"); + } + + try { + CompassModes.valueOf(sc.config.getString("compass." + type + ".default.mode")); + } + catch (Exception e) { + addError("invalid_choice", ImmutableMap.of("type", "" + type, "key", "mode")); + fixValue("compass." + type + ".default.mode"); + } + } + + private List validateRequiredItems(CompassTypes type, RequirementsSections section) { + List list = sc.config.getStringList("compass." + type + ".require.items." + section); + List items = new ArrayList(); + + if (list.size() == 0) return items; + + if (list.contains("AIR")) { + fixValue("compass." + type + ".require.items." + section, items); + return items; + } + + for (String item : list) { + try { + Material.valueOf(item); + items.add(item); + } + catch (Exception e) {} + } + + if (list.size() > items.size()) { + addError("invalid_items", ImmutableMap.of("section", "" + section, "type", "" + type, + "ignored", "" + (list.size() - items.size()))); + fixValue("compass." + type + ".require.items." + section, items); + } + + return items; + } + + private void validateTrackerSettings() { + Iterator it = sc.trackers.keySet().iterator(); + + while (it.hasNext()) { + String trackerID = it.next(); + + if (!((AbstractTracker) sc.trackers.get(trackerID)).trackerName().toLowerCase().matches("^[a-z0-9]+$")) { + it.remove(); + sc.sendMessage(sc.getServer().getConsoleSender(), "tracker_disabled_invalid_name", + ImmutableMap.of("tracker", trackerID)); + } + } + + List userPriorities = sc.config.getStringList("trackers_priorities"); + List readPriorities = new ArrayList(); + + for (String priority : sc.config.getStringList("trackers_priorities")) { + if (!sc.trackers.containsKey(priority)) userPriorities.remove(priority); + else if (!readPriorities.contains(priority)) readPriorities.add(priority); + } + + if (readPriorities.size() != sc.trackers.size()) { + fixValue("trackers_priorities"); + addError("invalid_priorities"); + } + + for (String tracker : sc.trackers.keySet()) if (!userPriorities.contains(tracker)) userPriorities.add(tracker); + fixValue("trackers_priorities", userPriorities); + } + + // Private classes ------------------------------------------------------------------------------------------------- + + public static class ConfigError { + public final String errorKey; + public final Map placeholders; + + public ConfigError(String k, Map p) { + errorKey = k; + placeholders = p; + } + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/utils/LangUtil.java b/src/main/java/me/arboriginal/SimpleCompass/utils/LangUtil.java new file mode 100644 index 0000000..b496501 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/utils/LangUtil.java @@ -0,0 +1,106 @@ +package me.arboriginal.SimpleCompass.utils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import com.google.common.base.Charsets; +import me.arboriginal.SimpleCompass.plugin.SimpleCompass; + +public class LangUtil { + private SimpleCompass sc; + + // Constructor methods --------------------------------------------------------------------------------------------- + + public LangUtil(SimpleCompass plugin) { + sc = plugin; + } + + // Public methods -------------------------------------------------------------------------------------------------- + + public FileConfiguration getLocale(String language) { + FileConfiguration locale; + boolean newFile; + + String langRes = "lang/" + language + ".yml"; + String langRdef = "lang/en.yml"; + File langFile = new File(sc.getDataFolder(), langRes); + + if (newFile = !langFile.exists()) { + String logMsg = null; + + sc.getLogger().warning("Lang file for « " + language + " » doesn't exist."); + + if (sc.getResource(langRes) != null) { + logMsg = "Lang file for « " + language + " » copied from plugin."; + } + else { + sc.getLogger().warning("Lang « " + language + " » doesn't exist in the plugin either."); + + try { + writeResourceToFile(sc.getResource(langRdef), langFile); + + logMsg = "A new lang file for « " + language + " » has been generated, based on english."; + langRes = null; + } + catch (Exception e) { + sc.getLogger().severe("Lang file for « " + language + " » cannot be generated."); + + logMsg = "Fallback to default lang file."; + langRes = langRdef; + } + } + + copyResourceToFile(langRes, langFile); + sc.getLogger().info(logMsg); + } + + locale = YamlConfiguration.loadConfiguration(langFile); + + if (!newFile) saveConfigToFile(locale, langFile, langRdef); + + return locale; + } + + // Private methods ------------------------------------------------------------------------------------------------- + + private void copyResourceToFile(String resource, File file) { + if (resource != null) { + sc.saveResource(resource, false); + + file = new File(sc.getDataFolder(), resource); + } + } + + private void saveConfigToFile(FileConfiguration config, File file, String defaultRes) { + config.setDefaults(YamlConfiguration.loadConfiguration( + new InputStreamReader(sc.getResource(defaultRes), Charsets.UTF_8))); + // This ensure sentences added in next versions are stored in the file with their default values + config.options().copyDefaults(true); + + try { + config.save(file); + } + catch (Exception e) { + sc.getLogger().warning("The language file cannot be updated in your plugin folder. " + + "You need to check by yourself if you didn't missed some sentences you want to translate. " + + "Default language will be used for them."); + } + } + + private void writeResourceToFile(InputStream in, File file) throws Exception { + file.getParentFile().mkdirs(); + + OutputStream out = new FileOutputStream(file); + byte[] buf = new byte[1024]; + int len; + + while ((len = in.read(buf)) > 0) out.write(buf, 0, len); + + out.close(); + in.close(); + } +} diff --git a/src/main/java/me/arboriginal/SimpleCompass/utils/NMSUtil.java b/src/main/java/me/arboriginal/SimpleCompass/utils/NMSUtil.java new file mode 100644 index 0000000..66b6ae6 --- /dev/null +++ b/src/main/java/me/arboriginal/SimpleCompass/utils/NMSUtil.java @@ -0,0 +1,71 @@ +package me.arboriginal.SimpleCompass.utils; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public final class NMSUtil { + private static final String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; + + // Public methods -------------------------------------------------------------------------------------------------- + + public static boolean openBook(Player player, ItemStack book) { + try { // 1.14 new method + player.getClass().getMethod("openBook", ItemStack.class).invoke(player, book); + return true; + } + catch (Exception e) {} + // Fallback for 1.13... + int heldSlot = player.getInventory().getHeldItemSlot(); + ItemStack current = player.getInventory().getItem(heldSlot); + boolean success = false; + + player.getInventory().setItem(heldSlot, book); + + try { + Object key = getNMSClass("MinecraftKey").getConstructor(String.class).newInstance("minecraft:book_open"); + Class bb = getBufferClass("ByteBuf"), ic = int.class, pds = getNMSClass("PacketDataSerializer"); + // @formatter:off + success = sendPacket(player, getNMSClass("PacketPlayOutCustomPayload").getConstructor(key.getClass(), pds) + .newInstance(key, pds.getConstructor(getBufferClass("ByteBuf")) + .newInstance(bb.getMethod("writerIndex", ic).invoke(bb.getMethod("setByte", ic, ic) + .invoke(getBufferClass("Unpooled").getMethod("buffer", ic).invoke(null, 256), 0, 0), 1)))); + } catch (Exception e) {} + // @formatter:on + player.getInventory().setItem(heldSlot, current); + return success; + } + + // Private methods ------------------------------------------------------------------------------------------------- + + private static Class getBufferClass(String name) { + return getClass(name, "io.netty.buffer"); + } + + private static Class getNMSClass(String name) { + return getClass(name, "net.minecraft.server." + version); + } + + private static Class getClass(String name, String namespace) { + try { + return Class.forName(namespace + "." + name); + } + catch (Exception e) { + return null; + } + } + + private static boolean sendPacket(Player player, Object packet) { + try { + Object handle = player.getClass().getMethod("getHandle").invoke(player); + Object target = handle.getClass().getField("playerConnection").get(handle); + + target.getClass().getMethod("sendPacket", getNMSClass("Packet")).invoke(target, packet); + + return true; + } + catch (Exception e) {} + + return false; + } +} diff --git a/src/config.yml b/src/main/resources/config.yml similarity index 90% rename from src/config.yml rename to src/main/resources/config.yml index 2bb13df..4047d6b 100644 --- a/src/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,16 @@ -# You can find the default config with description of parameters here: -# https://github.com/arboriginal/SimpleCompass/blob/master/src/config.yml +# ---------------------------------------------------------------------------------------------------------------------- +# ${project.artifactId}, version ${project.version} - Configuration file. +# . +# You will find an explanation of all parameters here: +# https://github.com/arboriginal/${project.artifactId}/blob/master/src/main/resources/config.yml +# . +# Personal message: I'd love to have videos showing and explaining the plugin in use, but I'm not good at making vids... +# If you are able to make one, send me the link (preferred on Youtube) and I will include it (with credit and link) +# on the plugin page. English language is IMHO the most important, because it will be understandable by the most, +# but if you want to make a video in another language, I will include it too. +# . +# Remember to drink water, eat at least 5 fruits & vegetables a day and to be crazy all days, life is a big joke! ;) +# ---------------------------------------------------------------------------------------------------------------------- language: en # Choose lang file you want to use, actually, only en and fr exists, but you can set what you want: # If this lang file doesn't exist, a new one is created (copy of english, so you can edit it). @@ -91,8 +102,8 @@ compass: after: " §8] ==--" cardinals: # Those four cardinal points should have the same length for a better precision. If not, they will be filled with "filling_char". north: "North" - east: "East" - west: "West" + east: "East " + west: "West " south: "South" filling_char: " " # If they don't have the same length, this character will be used to fill the short ones. Put an empty string to disable. @@ -107,8 +118,8 @@ compass: after: " §8] ==--" cardinals: north: "North" - east: "East" - west: "West" + east: "East " + west: "West " south: "South" filling_char: " " diff --git a/lang/en.yml b/src/main/resources/lang/en.yml similarity index 90% rename from lang/en.yml rename to src/main/resources/lang/en.yml index 5901f9b..5a1f855 100644 --- a/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -1,12 +1,21 @@ +# ---------------------------------------------------------------------------------------------------------------------- +# ${project.artifactId}, version ${project.version} - Localization file. +# . # In all messages, you can use colors with « & » followed by a number / letter: # from 0 (black) to r (reset). See this link: https://wiki.ess3.net/mc/ # (You can still use the classic notation with « § » symbol instead of « & ».) +# . +# BEWARE: When you see « {word} », this is a placeholder! +# So you have to let it like that (not translated, not customised), +# Otherwise, the plugin will not be able to substitute the dynamic value it represents. +# . +# If you don't remember where a message is used, you can read the online version which contains details here: +# https://github.com/arboriginal/SimpleCompass/blob/master/src/main/resources/lang/en.yml +# ---------------------------------------------------------------------------------------------------------------------- +prefix: "&8[&eSimpleCompass&8] " # Prefix which can be used in all messages, can be an empty string to disable it globally... -prefix: "&8[&eSimpleCompass&8] " # But you can also decide to remove the {prefix} part in specific messages. - -# BEWARE: When you see « {word} », this is a placeholder! So you have to let it like that (not translated, not customised), -# Otherwise, the plugin will not be able to substitute the dynamic value it represents. +# But you can also decide to remove the {prefix} part in specific messages. # Message displayed when using the reload command configuration_reloaded: "{prefix}&aConfiguration successfully reloaded" @@ -74,6 +83,10 @@ interface_failed_auto_open_give_failed: "{prefix}&eInterface book cannot be auto # In case of the book interface cannot be opened automaticaly and the book cannot be given to the player because of the cooldown interface_book_give_cooldown: "{prefix}&cYou have to wait {delay} before another book interface will be available!" +# Messages displayed when using the command /scompass-toggle +toggle_state_saved: "{prefix}&6Compass settings put aside." +toggle_state_restored: "{prefix}&6Compass settings restored." + # You can define your own action names here (choose something short and understandable by your players) actions: ACCEPT: accept diff --git a/lang/fr.yml b/src/main/resources/lang/fr.yml similarity index 91% rename from lang/fr.yml rename to src/main/resources/lang/fr.yml index 1b58e0f..9f37457 100644 --- a/lang/fr.yml +++ b/src/main/resources/lang/fr.yml @@ -1,12 +1,21 @@ +# ---------------------------------------------------------------------------------------------------------------------- +# ${project.artifactId}, version ${project.version} - Fichier de traductions. +# . # Dans tous les messages, tu peux utiliser les couleurs avec « & » suivi d'un chiffre / lettre : # de 0 (noir) à r (reset). Voir ce lien : https://wiki.ess3.net/mc/ # (Tu peux également utiliser la notation classique avec le symbole « § » à la place de « & ».) +# . +# ATTENTION : Quand tu vois « {word} », c'est un masque de remplacement ! +# Donc tu dois le laisser tel quel (non traduit, non personnalisé), +# Sinon, le plugin ne sera pas capable de substituer la value dynamique qu'il représente. +# . +# Si tu ne te sais plus où un message est utilisé, tu peux consulter la version en ligne qui contient des details ici : +# https://github.com/arboriginal/SimpleCompass/blob/master/src/main/resources/lang/fr.yml +# ---------------------------------------------------------------------------------------------------------------------- +prefix: "&8[&eSimpleCompass&8] " # Préfixe qui peut être utilisé dans tous les messages, peut être une chaine vide pour le désactiver globalement... -prefix: "&8[&eSimpleCompass&8] " # Mais tu peux aussi le décider de retirer la partie {prefix} dans des messages spécifiques. - -# ATTENTION : Quand tu vois « {word} », c'est un masque de remplacement ! Donc tu dois le laisser tel quel (non traduit, non personnalisé), -# Sinon, le plugin ne sera pas capable de substituer la value dynamique qu'il représente. +# Mais tu peux aussi le décider de retirer la partie {prefix} dans des messages spécifiques. # Message affiché quand la commande reload est utilisée configuration_reloaded: "{prefix}&aConfiguration rechargée" @@ -74,6 +83,10 @@ interface_failed_auto_open_give_failed: "{prefix}&eL'interface ne peut être ouv # Au cas où l'interface sous forme de livre ne peut être ouverte automatiquement et que le livre n'a pu être donné car le joueur doit attendre interface_book_give_cooldown: "{prefix}&cTu dois attendre {delay} avant qu'un autre livre-interface soit disponible !" +# Messages affichés lors de l'utilisation de la commande /scompass-toggle +toggle_state_saved: "{prefix}&6Réglages de boussole mis de côté." +toggle_state_restored: "{prefix}&6Réglages de boussole restauré." + # Tu peux définir tes propres noms d'action ici (choisis quelque chose de court et compréhensible pour les joueurs) actions: ACCEPT: accepter diff --git a/src/plugin.yml b/src/main/resources/plugin.yml similarity index 85% rename from src/plugin.yml rename to src/main/resources/plugin.yml index 42f538c..4f9379f 100644 --- a/src/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,19 +1,18 @@ -name: SimpleCompass -description: Simple compass to help player who don't have sense of direction. -version: 1.0 +name: ${project.name} +description: ${project.description} +version: ${project.version} author: arboriginal -website: https://www.spigotmc.org/resources/simplecompass.63140/ -dev-url: https://github.com/arboriginal/SimpleCompass +website: https://www.spigotmc.org/resources/${spigot-id}/ +dev-url: https://github.com/arboriginal/${project.artifactId} -depend: [] -softdepend: [] +main: ${project.groupId}.${project.artifactId}.${spigot-main} +api-version: ${spigot-api} -api-version: 1.13 +depend: [ ] +softdepend: [ ] database: false -main: me.arboriginal.SimpleCompass.plugin.SimpleCompass - commands: scompass: description: Use the SimpleCompass interface @@ -24,6 +23,11 @@ commands: permission: scompass.reload aliases: screload + scompass-toggle: + description: Quickly toggle ON/OFF your compass(es) + permission: scompass.toggle + aliases: sctoggle + scompass-option: description: Choose personal options for SimpleCompass permission: scompass.option @@ -57,6 +61,7 @@ permissions: scompass.use: true scompass.use.*: true scompass.use.free: true + scompass.toggle: true scompass.option: true scompass.option.*: true scompass.track.*: true @@ -69,6 +74,10 @@ permissions: description: Allows to display the command help. default: true + scompass.toggle: # Technically works without scompass.use, but have no interest without... + description: Allows to use /scompass-toggle command. + default: true + scompass.use.*: description: Allows to use all compass types. default: false diff --git a/src/me/arboriginal/SimpleCompass/commands/AbstractCommand.java b/src/me/arboriginal/SimpleCompass/commands/AbstractCommand.java deleted file mode 100644 index b22828c..0000000 --- a/src/me/arboriginal/SimpleCompass/commands/AbstractCommand.java +++ /dev/null @@ -1,251 +0,0 @@ -package me.arboriginal.SimpleCompass.commands; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.bukkit.entity.Player; -import com.google.common.collect.ImmutableMap; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; -import me.arboriginal.SimpleCompass.plugin.AbstractTracker; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; -import me.arboriginal.SimpleCompass.plugin.AbstractTracker.TrackingActions; - -public abstract class AbstractCommand { - protected SimpleCompass sc; - protected String mainCommand; - protected Map subCommands = new HashMap(); - - public enum SubCmds { - OPTION, TRACK, - } - - public enum CompassOptions { - ALWAYS, ELYTRA, ELYTRA_VEHICLE, VEHICLE, DISABLED, - } - - //----------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public AbstractCommand(SimpleCompass plugin, String command) { - sc = plugin; - mainCommand = command; - } - - //----------------------------------------------------------------------------------------------- - // Abstract methods - // ---------------------------------------------------------------------------------------------- - - protected abstract void showOptions(Player player, CompassTypes modified); - - // ---------------------------------------------------------------------------------------------- - // Public methods > Options - // ---------------------------------------------------------------------------------------------- - - public CompassTypes modifyOption(Player player, CompassTypes type, String value) { - if (value.equals(CompassModes.MODE180.toString()) || value.equals(CompassModes.MODE360.toString())) - sc.datas.compassModeSet(player, type, CompassModes.valueOf(value)); - else - sc.datas.compassOptionSet(player, type, CompassOptions.valueOf(value)); - return type; - } - - public boolean performCommandOption(Player player, String[] args) { - if (!hasAccessOption(player, args, true)) return false; - - CompassTypes modified = null; - - switch (args.length) { - case 0: - break; - - case 1: - if (allowedOptions(player).size() != 1) { - sc.sendMessage(player, "missing_type"); - return false; - } - - modified = modifyOption(player, CompassTypes.valueOf(args[1]), allowedOptions(player).get(0)); - break; - - case 2: - modified = modifyOption(player, CompassTypes.valueOf(args[1]), args[0]); - break; - - default: - return false; - } - - showOptions(player, modified); - - return true; - } - - // ---------------------------------------------------------------------------------------------- - // Protected methods > Options - // ---------------------------------------------------------------------------------------------- - - protected List completeCommandOption(Player player, String[] args) { - switch (args.length) { - case 1: - return getFilteredList(allowedOptions(player), args[0]); - - case 2: - if (allowedOptions(player).contains(args[0])) return getFilteredList(allowedTypes(player), args[1]); - } - - return null; - } - - protected List allowedOptions(Player player) { - List list = new ArrayList<>(); - - for (CompassOptions option : CompassOptions.values()) - if (player.hasPermission("scompass.option." + option)) list.add(option.toString()); - - for (CompassModes mode : CompassModes.values()) list.add(mode.toString()); - - return list; - } - - protected List allowedTypes(Player player) { - List list = new ArrayList(); - - for (CompassTypes type : CompassTypes.values()) if (player.hasPermission("scompass.use." + type)) list.add(type); - - return list; - } - - protected boolean hasAccessOption(Player player, String[] args, boolean showError) { - if (args.length > 2 || allowedOptions(player).isEmpty() || allowedTypes(player).isEmpty()) { - if (showError) sc.sendMessage(player, "wrong_usage"); - return false; - } - - if (args.length > 0 && !allowedOptions(player).contains(args[0])) { - if (showError) sc.sendMessage(player, "invalid_option", ImmutableMap.of("option", args[0])); - return false; - } - - if (args.length > 1 && !isAllowedTypes(player, args[1])) { - if (showError) sc.sendMessage(player, "invalid_type", ImmutableMap.of("type", args[0])); - return false; - } - - return true; - } - - protected boolean isAllowedTypes(Player player, String value) { - for (CompassTypes type : allowedTypes(player)) if (type.toString().equalsIgnoreCase(value)) return true; - - return false; - } - - // ---------------------------------------------------------------------------------------------- - // Public methods > Trackers - // ---------------------------------------------------------------------------------------------- - - public boolean performCommandTrack(Player player, String[] args) { - HashMap cmdArgs = getTrackArguments(player, args); - AbstractTracker tracker = (AbstractTracker) cmdArgs.get("tracker"); - TrackingActions action = (TrackingActions) cmdArgs.get("action"); - String target = (String) cmdArgs.get("target"); - - if (tracker == null) { - sc.sendMessage(player, "wrong_usage"); - return false; - } - - if (action == null) { - List list = tracker.list(player, null, ""); - - if (list == null || list.isEmpty()) - tracker.sendMessage(player, "list_empty"); - else - tracker.sendMessage(player, "list", ImmutableMap.of("list", String.join(", ", list))); - - return true; - } - - if (action.equals(TrackingActions.HELP) && args.length == 2 && player.hasPermission("scompass.help")) { - String help = tracker.help(player, - mainCommand + (subCommands.containsKey(SubCmds.TRACK) ? " " + subCommands.get(SubCmds.TRACK) : "")); - - if (help != null && !help.isEmpty()) player.sendMessage(help); - - return true; - } - - return tracker.perform(player, "sctrack", action, target, args); - } - - // ---------------------------------------------------------------------------------------------- - // Protected methods > Trackers - // ---------------------------------------------------------------------------------------------- - - protected List completeCommandTrack(Player player, String[] args) { - HashMap parsed = getTrackArguments((Player) player, args); - - if (args.length == 1) return sc.targets.getTrackersList((Player) player, args[0]); - - AbstractTracker tracker = (AbstractTracker) parsed.get("tracker"); - - if (tracker != null) return tracker.commandSuggestions((Player) player, args, parsed); - - return null; - } - - protected List getActionsAvailable(Player player, String trackerID) { - if (!sc.targets.canUseTracker(player, trackerID)) return null; - return sc.trackers.get(trackerID).getActionsAvailable(player, false); - } - - protected HashMap getTrackArguments(Player player, String[] args) { - HashMap parsed = new HashMap(); - - if (args.length == 0) return parsed; - - AbstractTracker tracker = sc.targets.getTrackerByName(args[0]); - - if (tracker == null || !sc.targets.getAvailableTrackers(player).contains(tracker.trackerID())) - return parsed; - - parsed.put("tracker", tracker); - - if (args.length == 1) return parsed; - - tracker.parseArguments(player, args, parsed); - - return parsed; - } - - // ---------------------------------------------------------------------------------------------- - // Utils methods - // ---------------------------------------------------------------------------------------------- - - protected ImmutableMap clickableOption(CompassTypes type, Object option, Object selected) { - String optionType = (option instanceof CompassModes) ? "modes" : "options"; - String optionName = sc.locale.getString(optionType + "." + option); - - return ImmutableMap.of( - "text", sc.prepareMessage("commands." + mainCommand + ".options." - + (option.toString().equals(selected.toString()) ? "active" : "inactive"), - ImmutableMap.of("option", optionName)), - "hover", sc.prepareMessage("commands." + mainCommand + ".options.hover", - ImmutableMap.of("option", optionName, "type", sc.locale.getString("types." + type))), - "click", - "/" + mainCommand + (subCommands.containsKey(SubCmds.OPTION) ? " " + subCommands.get(SubCmds.OPTION) : "") - + " " + option + " " + type); - } - - protected List getFilteredList(List inputList, String startWith) { - List list = new ArrayList(); - - for (Object candidate : inputList) - if (candidate.toString().toLowerCase().startsWith(startWith.toLowerCase())) list.add(candidate.toString()); - - return list; - } -} diff --git a/src/me/arboriginal/SimpleCompass/commands/InterfaceCommand.java b/src/me/arboriginal/SimpleCompass/commands/InterfaceCommand.java deleted file mode 100644 index 2819f2d..0000000 --- a/src/me/arboriginal/SimpleCompass/commands/InterfaceCommand.java +++ /dev/null @@ -1,437 +0,0 @@ -package me.arboriginal.SimpleCompass.commands; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.bukkit.Material; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.bukkit.conversations.Conversation; -import org.bukkit.conversations.ConversationContext; -import org.bukkit.conversations.Prompt; -import org.bukkit.conversations.StringPrompt; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.BookMeta; -import org.bukkit.scheduler.BukkitRunnable; -import com.google.common.collect.ImmutableMap; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; -import me.arboriginal.SimpleCompass.plugin.AbstractTracker; -import me.arboriginal.SimpleCompass.plugin.AbstractTracker.TargetSelector; -import me.arboriginal.SimpleCompass.plugin.AbstractTracker.TrackingActions; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; -import me.arboriginal.SimpleCompass.utils.NMSUtil; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; - -public class InterfaceCommand extends AbstractCommand implements CommandExecutor, TabCompleter { - private static final String SELECT_TARGET = "*S313C7:74R637*", SELECT_PAGER = "*S313C7:P463R*"; - //----------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public InterfaceCommand(SimpleCompass plugin) { - super(plugin, "scompass"); - - subCommands.put(SubCmds.OPTION, plugin.locale.getString("subcommands." + SubCmds.OPTION)); - - if (!sc.trackers.isEmpty()) - subCommands.put(SubCmds.TRACK, plugin.locale.getString("subcommands." + SubCmds.TRACK)); - } - - // ---------------------------------------------------------------------------------------------- - // CommandExecutor methods - // ---------------------------------------------------------------------------------------------- - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) - sc.sendMessage(sender, "command_only_for_players"); - else if (((Player) sender).isSleeping()) { - sc.sendMessage(sender, "command_no_sleeping"); - return true; - } - else if (args.length == 0) - showOptions((Player) sender, null); - else if (args[0].equals(SELECT_TARGET)) - targetSelector((Player) sender, subArgs(args)); - else if (subCommand((Player) sender, SubCmds.OPTION, args[0])) - return performCommandOption((Player) sender, subArgs(args)); - else if (subCommand((Player) sender, SubCmds.TRACK, args[0])) - return performCommandTrack((Player) sender, subArgs(args)); - else { - sc.sendMessage(sender, "wrong_usage"); - return false; - } - - return true; - } - - // ---------------------------------------------------------------------------------------------- - // CommandUtil methods - // ---------------------------------------------------------------------------------------------- - - @Override - public void showOptions(Player player, CompassTypes modified) { - if (modified != null) sc.sendMessage(player, "commands." + mainCommand + ".saved"); - - ItemStack book = buildInterface(player, modified); - - if (sc.config.getBoolean("interface.give_book_everytime") || !NMSUtil.openBook(player, book)) - giveBook(player, book); - } - - // ---------------------------------------------------------------------------------------------- - // TabCompleter methods - // ---------------------------------------------------------------------------------------------- - - @Override - public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { - if (args.length == 0 || !(sender instanceof Player)) return null; - - if (args.length == 1) { - List list = new ArrayList(); - - for (SubCmds subCommand : subCommands.keySet()) { - String subCommandName = subCommands.get(subCommand); - - if (subCommandName.toLowerCase().startsWith(args[0].toLowerCase())) list.add(subCommandName); - } - - return list; - } - else if (subCommand((Player) sender, SubCmds.OPTION, args[0])) - return completeCommandOption((Player) sender, Arrays.stream(args).skip(1).toArray(String[]::new)); - else if (subCommand((Player) sender, SubCmds.TRACK, args[0])) - return completeCommandTrack((Player) sender, Arrays.stream(args).skip(1).toArray(String[]::new)); - else { - sc.sendMessage(sender, "wrong_usage"); - return null; - } - } - - // ---------------------------------------------------------------------------------------------- - // Private methods - // ---------------------------------------------------------------------------------------------- - - private ItemStack buildInterface(Player player, CompassTypes modified) { - ItemStack book = new ItemStack(Material.WRITTEN_BOOK); - BookMeta meta = bookMeta(book, "options"); - - List types = allowedTypes(player); - List opts = allowedOptions(player); - - if (modified != null) buildInterfaceOptions(player, meta, types, opts, modified); - if (player.hasPermission("scompass.track")) buildInterfaceTracking(player, meta); - if (modified == null) buildInterfaceOptions(player, meta, types, opts, modified); - - book.setItemMeta(meta); - return book; - } - - private void buildInterfaceOptions( - Player player, BookMeta meta, List types, List opts, CompassTypes modified) { - if (!player.hasPermission("scompass.option")) return; - - if (modified != null) { - types.remove(modified); - meta.spigot().addPage(buildPage(player, modified, opts)); - } - - for (CompassTypes type : types) meta.spigot().addPage(buildPage(player, type, opts)); - } - - private void buildInterfaceTracking(Player player, BookMeta meta) { - List trackers = new ArrayList(); - Set ordered = sc.locale.getConfigurationSection( - "commands." + mainCommand + ".track.buttons").getKeys(false); - - for (String trackerID : sc.targets.trackersPriority) - if (player.hasPermission("scompass.track." + trackerID)) trackers.add(trackerID); - - for (String[] part : chunk(trackers.toArray(new String[trackers.size()]), - sc.locale.getInt("commands." + mainCommand + ".track.per_page"))) { - ArrayList content = new ArrayList(); - content.add(new TextComponent(sc.prepareMessage("commands." + mainCommand + ".header") + "\n\n")); - - for (String trackerID : part) { - AbstractTracker tracker = sc.trackers.get(trackerID); - if (tracker == null) continue; - - Map> commands = new LinkedHashMap>(); - List actions = tracker.getActionsAvailable(player, false); - - for (String actionName : ordered) { // @formatter:off - TrackingActions action; - try { action = TrackingActions.valueOf(actionName); } catch (Exception e) { continue; } - String text = sc.prepareMessage("commands." + mainCommand + ".track.buttons." + action + ".text"); - - if (!actions.contains(action)) { - commands.put("{" + action + "}", ImmutableMap.of("text", inactiveCommandText(text))); - continue; - } - - commands.put("{" + action + "}", ImmutableMap.of( - "text", text, - "hover", sc.prepareMessage("commands." + mainCommand + ".track.buttons." + action + ".hover"), - "click", "/" + mainCommand - + " " + (!tracker.requireTarget(action).equals(TargetSelector.NONE) - ? SELECT_TARGET : subCommands.get(SubCmds.TRACK)) - + " " + tracker.trackerName() + " " + tracker.getActionName(action))); - } // @formatter:on - - content.add(sc.createClickableMessage(sc.prepareMessage("commands." + mainCommand + ".track.content", - ImmutableMap.of("tracker", tracker.trackerName(), "buttons", String.join(" ", commands.keySet()))) - + "\n", commands)); - } - - meta.spigot().addPage(content.stream().toArray(BaseComponent[]::new)); - } - } - - private String inactiveCommandText(String text) { - String[] inactiveText = text.replace("&", "§").split("§"); - String out = "§7"; - - for (int i = 0; i < inactiveText.length; i++) - if (inactiveText[i].length() > 1) - out += (inactiveText[i].charAt(0) == 'l') ? "§" + inactiveText[i] + "§7" : inactiveText[i].substring(1); - - return out; - } - - private BaseComponent[] buildPage(Player player, CompassTypes type, List optionsList) { - CompassModes typeMode = sc.datas.compassModeGet(player, type); - CompassOptions selected = sc.datas.compassOptionGet(player, type); - ArrayList content = new ArrayList(); - Map> commands = new LinkedHashMap>(); - - content.add(new TextComponent(sc.prepareMessage("commands." + mainCommand + ".header"))); - - for (CompassModes mode : CompassModes.values()) - commands.put("{" + mode + "}", clickableOption(type, mode, typeMode)); - - content.add(sc.createClickableMessage(sc.prepareMessage("commands." + mainCommand + ".content", - ImmutableMap.of("type", sc.locale.getString("types." + type))), commands)); - content.add(new TextComponent("\n" + sc.prepareMessage("commands." + mainCommand + ".footer") + "\n")); - - commands = new LinkedHashMap>(); - - for (String option : optionsList) { - if (option.equals(CompassModes.MODE180.toString()) || option.equals(CompassModes.MODE360.toString())) continue; - - commands.put("{" + option + "}", clickableOption(type, option, selected)); - } - - content.add(sc.createClickableMessage(String.join("\n", commands.keySet()), commands)); - - return content.stream().toArray(BaseComponent[]::new); - } - - private void giveBook(Player player, ItemStack book) { - if (!sc.config.getBoolean("interface.give_book_everytime") - && !sc.config.getBoolean("interface.give_book_on_fail")) { - sc.sendMessage(player, "interface_failed_auto_open"); - return; - } - - long cooldown = sc.datas.cooldownBookGet(player); - - if (cooldown > 0) { - sc.sendMessage(player, "interface_book_give_cooldown", ImmutableMap.of("delay", "" + sc.formatTime(cooldown))); - return; - } - - int slot = player.getInventory().firstEmpty(); - - if (slot == -1) { - sc.sendMessage(player, "interface_failed_auto_open_give_failed"); - return; - } - - player.getInventory().setItem(slot, book); - sc.datas.cooldownBookSet(player); - sc.sendMessage(player, "interface_failed_auto_open_give"); - } - - private boolean subCommand(Player player, SubCmds command, String argument) { - return subCommands.get(command) != null - && argument.toLowerCase().equals(subCommands.get(command).toLowerCase()) - && player.hasPermission("scompass." + command.toString().toLowerCase()) - && (command.equals(SubCmds.OPTION) || !sc.trackers.isEmpty()); - } - - private void targetSelector(Player player, String[] args) { - HashMap cmdArgs = getTrackArguments(player, args); // @formatter:off - if (cmdArgs.get("tracker") == null || cmdArgs.get("action") == null) return; - AbstractTracker tracker = (AbstractTracker) cmdArgs.get("tracker"); - TrackingActions action = (TrackingActions) cmdArgs.get("action"); // @formatter:on - - switch (tracker.requireTarget(action)) { - case ACTIVE: - targetSelectorList(player, tracker.activeTargets(player, ""), args); - break; - - case AVAILABLE: - targetSelectorList(player, tracker.availableTargets(player, ""), args); - break; - - case NEW: - targetSelectorNew(player, args, false); - break; - - case NEWCOORDS: - targetSelectorNew(player, args, true); - break; - - default: - break; - } - } - - private void targetSelectorFallback(Player player, List pages, String args[]) { - int pager = 0; // @formatter:off - if (args.length > 3 && args[2].equals(SELECT_PAGER)) - try { pager = Integer.parseInt(args[3]); } catch (Exception e) {} - - player.spigot().sendMessage(pages.get(pager)); if (pages.size() == 1) return; - - String command = "/" + mainCommand + " " + SELECT_TARGET + " " + args[0] + " " + args[1] + " " + SELECT_PAGER; - Map> commands = new LinkedHashMap>(); - - if (pager > 0) - commands.put("{prev}", ImmutableMap.of( - "text", sc.prepareMessage("commands." + mainCommand + ".targets.prev.title"), - "hover", sc.prepareMessage("commands." + mainCommand + ".targets.prev.hover"), - "click", command + " " + (pager - 1))); - if (pager < pages.size() - 1) - commands.put("{next}", ImmutableMap.of( - "text", sc.prepareMessage("commands." + mainCommand + ".targets.next.title"), - "hover", sc.prepareMessage("commands." + mainCommand + ".targets.next.hover"), - "click", command + " " + (pager + 1))); - // @formatter:on - if (!commands.isEmpty()) player.spigot().sendMessage( - sc.createClickableMessage(" " + String.join(" ", commands.keySet()) + "\n", commands)); - } - - private void targetSelectorList(Player player, List targets, String[] args) { - ItemStack book = new ItemStack(Material.WRITTEN_BOOK); - BookMeta meta = bookMeta(book, "targets"); - String head = sc.prepareMessage("commands." + mainCommand + ".targets.header") + "\n\n"; - String command = "/" + mainCommand + " " + subCommands.get(SubCmds.TRACK) + " " + String.join(" ", args); - - List pages = targetSelectorPages(targets, new TextComponent(head), command); - for (BaseComponent[] page : pages) meta.spigot().addPage(page); - book.setItemMeta(meta); - - if (!NMSUtil.openBook(player, book)) targetSelectorFallback(player, pages, args); - } - - private List targetSelectorPages(List targets, BaseComponent head, String command) { - List pages = new ArrayList(); - - for (String[] part : chunk(targets.toArray(new String[targets.size()]), - sc.locale.getInt("commands." + mainCommand + ".targets.per_page"))) { - BaseComponent[] page = new BaseComponent[part.length + 1]; - page[0] = head; - - for (int i = 0; i < part.length; i++) { - Map> commands = new LinkedHashMap>(); - - commands.put("{cmd}", ImmutableMap.of( - "text", sc.prepareMessage("commands." + mainCommand + ".targets.content", - ImmutableMap.of("target", part[i])), - "hover", sc.prepareMessage("commands." + mainCommand + ".targets.hover", - ImmutableMap.of("target", part[i])), - "click", command + " " + part[i])); - - page[i + 1] = sc.createClickableMessage("{cmd}" + "\n", commands); - } - - pages.add(page); - } - - if (pages.isEmpty()) pages.add(new BaseComponent[] { head, - new TextComponent(sc.prepareMessage("commands." + mainCommand + ".targets.no_targets")) }); - - return pages; - } - - private void targetSelectorNew(Player player, String[] args, boolean coords) { - String cancel = sc.locale.getString("commands." + mainCommand + ".targets.new.cancel"); - - Conversation conv = new Conversation(sc, player, new StringPrompt() { - @Override - public String getPromptText(ConversationContext paramConversationContext) { - return sc.prepareMessage("commands." + mainCommand + ".targets.new.name_" + (coords ? "coords" : "only"), - ImmutableMap.of("word", cancel)); - } - - @Override - public Prompt acceptInput(ConversationContext paramConversationContext, String paramString) { - new BukkitRunnable() { - @Override - public void run() { - if (this.isCancelled()) return; - if (paramString.equals(cancel)) - player.sendMessage(sc.prepareMessage("commands." + mainCommand + ".targets.new.cancelled")); - else - player.performCommand(mainCommand + " " + subCommands.get(SubCmds.TRACK) - + " " + String.join(" ", args) + " " + paramString); - this.cancel(); - } - }.runTaskLater(sc, sc.config.getInt("delays.target_cancel")); - - return END_OF_CONVERSATION; - } - }); - - conv.setLocalEchoEnabled(false); - player.beginConversation(conv); - } - - // ---------------------------------------------------------------------------------------------- - // Utils methods - // ---------------------------------------------------------------------------------------------- - - private BookMeta bookMeta(ItemStack book, String type) { - BookMeta meta = (BookMeta) book.getItemMeta(); - meta.setTitle(/* */sc.prepareMessage("commands." + mainCommand + ".books." + type + ".title")); - meta.setAuthor(/**/sc.prepareMessage("commands." + mainCommand + ".books." + type + ".author")); - - ArrayList lore = new ArrayList(); - for (String row : sc.locale.getStringList("commands." + mainCommand + ".books." + type + ".lore")) - lore.add(sc.formatMessage(row)); - - meta.setLore(lore); - return meta; - } - - private List chunk(String[] input, int number) { - List parts = new ArrayList(); - int left = input.length; - - while (left > 0) { - int size = Math.min(left, number); - String[] part = new String[size]; - - System.arraycopy(input, input.length - left, part, 0, size); - parts.add(part); - - left -= size; - } - - return parts; - } - - private String[] subArgs(String[] args) { - return Arrays.stream(args).skip(1).toArray(String[]::new); - } -} diff --git a/src/me/arboriginal/SimpleCompass/commands/OptionCommand.java b/src/me/arboriginal/SimpleCompass/commands/OptionCommand.java deleted file mode 100644 index b313d26..0000000 --- a/src/me/arboriginal/SimpleCompass/commands/OptionCommand.java +++ /dev/null @@ -1,89 +0,0 @@ -package me.arboriginal.SimpleCompass.commands; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.bukkit.entity.Player; -import com.google.common.collect.ImmutableMap; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public class OptionCommand extends AbstractCommand implements CommandExecutor, TabCompleter { - //----------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public OptionCommand(SimpleCompass plugin) { - super(plugin, "scoption"); - } - - // ---------------------------------------------------------------------------------------------- - // CommandExecutor methods - // ---------------------------------------------------------------------------------------------- - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - sc.sendMessage(sender, "command_only_for_players"); - return true; - } - else if (((Player) sender).isSleeping()) { - sc.sendMessage(sender, "command_no_sleeping"); - return true; - } - - return performCommandOption((Player) sender, args); - } - - // ---------------------------------------------------------------------------------------------- - // TabCompleter methods - // ---------------------------------------------------------------------------------------------- - - @Override - public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { - if (sender instanceof Player) return completeCommandOption((Player) sender, args); - - return null; - } - - // ---------------------------------------------------------------------------------------------- - // SimpleCompassOptions methods - // ---------------------------------------------------------------------------------------------- - - @Override - public void showOptions(Player player, CompassTypes modified) { - sc.sendMessage(player, "commands." + mainCommand + ".header"); - - for (CompassTypes type : allowedTypes(player)) { - CompassModes typeMode = sc.datas.compassModeGet(player, type); - CompassOptions selected = sc.datas.compassOptionGet(player, type); - Map> commands = new LinkedHashMap>(); - - for (CompassModes mode : CompassModes.values()) - commands.put("{" + mode + "}", clickableOption(type, mode, typeMode)); - - player.spigot().sendMessage( - sc.createClickableMessage(sc.prepareMessage("commands." + mainCommand + ".content", - ImmutableMap.of("type", sc.locale.getString("types." + type))), commands)); - - commands = new LinkedHashMap>(); - - for (String option : allowedOptions(player)) { - if (option.equals(CompassModes.MODE180.toString()) || option.equals(CompassModes.MODE360.toString())) continue; - - commands.put("{" + option + "}", clickableOption(type, option, selected)); - } - - player.spigot().sendMessage(sc.createClickableMessage(String.join("", commands.keySet()), commands)); - } - - sc.sendMessage(player, "commands." + mainCommand + ".footer"); - - if (modified != null) sc.sendMessage(player, "commands." + mainCommand + ".saved"); - } -} diff --git a/src/me/arboriginal/SimpleCompass/commands/TrackCommand.java b/src/me/arboriginal/SimpleCompass/commands/TrackCommand.java deleted file mode 100644 index 428f8d6..0000000 --- a/src/me/arboriginal/SimpleCompass/commands/TrackCommand.java +++ /dev/null @@ -1,56 +0,0 @@ -package me.arboriginal.SimpleCompass.commands; - -import java.util.List; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.bukkit.entity.Player; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public class TrackCommand extends AbstractCommand implements CommandExecutor, TabCompleter { - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public TrackCommand(SimpleCompass plugin) { - super(plugin, "sctrack"); - } - - // ---------------------------------------------------------------------------------------------- - // CommandExecutor methods - // ---------------------------------------------------------------------------------------------- - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - sc.sendMessage(sender, "command_only_for_players"); - return true; - } - else if (((Player) sender).isSleeping()) { - sc.sendMessage(sender, "command_no_sleeping"); - return true; - } - - return performCommandTrack((Player) sender, args); - } - - // ---------------------------------------------------------------------------------------------- - // TabCompleter methods - // ---------------------------------------------------------------------------------------------- - - @Override - public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { - if (sender instanceof Player) return completeCommandTrack((Player) sender, args); - - return null; - } - - //---------------------------------------------------------------------------------------------- - // CommandUtil methods - // ---------------------------------------------------------------------------------------------- - - @Override - public void showOptions(Player player, CompassTypes modified) {} -} diff --git a/src/me/arboriginal/SimpleCompass/compasses/AbstractCompass.java b/src/me/arboriginal/SimpleCompass/compasses/AbstractCompass.java deleted file mode 100644 index 371868c..0000000 --- a/src/me/arboriginal/SimpleCompass/compasses/AbstractCompass.java +++ /dev/null @@ -1,196 +0,0 @@ -package me.arboriginal.SimpleCompass.compasses; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; -import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; -import me.arboriginal.SimpleCompass.plugin.AbstractTracker; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public abstract class AbstractCompass { - protected SimpleCompass sc; - protected CompassTypes type; - protected BukkitRunnable task = null; - protected String warning = ""; - - public enum CompassTypes { - ACTIONBAR, BOSSBAR, - } - - public enum CompassModes { - MODE180, MODE360, - } - - public Player owner; - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public AbstractCompass(SimpleCompass plugin, Player player, CompassTypes compassTypes) { - sc = plugin; - type = compassTypes; - owner = player; - - init(); - refresh(); - } - - // ---------------------------------------------------------------------------------------------- - // Abstract methods - // ---------------------------------------------------------------------------------------------- - - public abstract void display(String datas); - - // ---------------------------------------------------------------------------------------------- - // Default methods - // ---------------------------------------------------------------------------------------------- - - public void delete() { - sc.tasks.clear(TasksTypes.REFRESH_STATUS, owner); - - if (task != null) task.cancel(); - if (sc.compasses.hasRequiredItems(owner, type, false)) return; - - String message = sc.prepareMessage("warnPlayerNoMoreFuel"); - if (message.isEmpty()) return; - - warning = message; - display(warning); - } - - public void init() {} - - public void refresh() { - display(buildCompassDatas()); - } - - // ---------------------------------------------------------------------------------------------- - // Private methods - // ---------------------------------------------------------------------------------------------- - - private String buildCompassDatas() { - double rotation = (owner.getEyeLocation().getYaw() - 180) % 360; - - if (rotation < 0) rotation += 360; - - CompassModes mode = sc.datas.compassModeGet(owner, type); - - String prefix = "compass." + type + "." + mode; - String sep = sc.config.getString(prefix + ".separator_value"); - String cSep = sc.config.getString(prefix + ".separator_color"); - String cOn = sc.config.getString(prefix + ".active_color"); - String cOff = sc.config.getString(prefix + ".inactive_color"); - String nOn = sc.config.getString(prefix + ".active_north_color"); - String nOff = sc.config.getString(prefix + ".north_color"); - String west = sc.config.getString(prefix + ".cardinals.west"); - String north = sc.config.getString(prefix + ".cardinals.north"); - String east = sc.config.getString(prefix + ".cardinals.east"); - String south = sc.config.getString(prefix + ".cardinals.south"); - String datas = sep + "♤" + sep + "♡" + sep + "♢" + sep + "♧"; - int start = (int) Math.round(rotation * datas.length() / 360); - char face = getFacing(); - - datas = datas.substring(start) + datas.substring(0, start); - - if (mode.equals(CompassModes.MODE180)) { - int strip = (int) Math.ceil(datas.length() / 4); - datas = datas.substring(strip - 1, datas.length() - strip + 1); - } - - datas = injectActivatedTrackers(datas, cSep); - - return sc.config.getString(prefix + ".before") + cSep - + datas // @formatter:off - .replace("♤", ((face == 'W') ? cOn : cOff) + west + cSep) - .replace("♡", ((face == 'N') ? nOn : nOff) + north + cSep) - .replace("♢", ((face == 'E') ? cOn : cOff) + east + cSep) - .replace("♧", ((face == 'S') ? cOn : cOff) + south + cSep) - + sc.config.getString(prefix + ".after"); // @formatter:on - } - - private char getFacing() { - try { - if (owner.getClass().getMethod("myMethodToFind", (Class[]) null) != null) - return owner.getFacing().toString().charAt(0); - } - catch (Exception e) {} - // Use this as a fallback for Spigot version (like 1.12) which doesn't support player.getFacing() - return Arrays.asList('S', 'W', 'N', 'E').get(Math.round(owner.getLocation().getYaw() / 90f) & 0x3); - } - - private HashMap>> getActiveTargets() { // @formatter:off - String cacheKey = "trackers." + type; - @SuppressWarnings("unchecked") - HashMap>> trackers - = (HashMap>>) sc.cache.get(owner.getUniqueId(), cacheKey); - - if (trackers == null) { - trackers = sc.targets.getTargetsCoords(owner); - sc.cache.set(owner.getUniqueId(), cacheKey, trackers, sc.config.getInt("delays.trackers_list")); - } - - return trackers; - } // @formatter:on - - private String injectActivatedTrackers(String compass, String sepColor) { - HashMap>> targets = getActiveTargets(); - if (targets.isEmpty()) return compass; - - Location refPos = owner.getEyeLocation(); - - HashMap placeholders = new HashMap(); - - for (String trackerID : sc.targets.trackersPriority) { - AbstractTracker tracker = sc.trackers.get(trackerID); - if (tracker == null) continue; - int hlMaxAngle = tracker.settings.getInt("settings.hl_angle", 0); - String hlMarker = null, hlSymbol = null; - - if (hlMaxAngle > 0) { - hlMarker = tracker.settings.getString("settings.hl_temp", null); - hlSymbol = tracker.settings.getString("settings.hl_symbol", null); - if (hlMarker != null && hlSymbol != null) placeholders.put(hlMarker, hlSymbol + sepColor); - } - - for (String targetType : targets.keySet()) { - ArrayList coords = targets.get(targetType).get(trackerID); - if (coords == null || coords.isEmpty()) continue; - boolean active = targetType.equals("on"); - - String marker = tracker.settings.getString("settings." + (active ? "" : "inactive_") + "temp"); - String symbol = tracker.settings.getString("settings." + (active ? "" : "inactive_") + "symbol"); - placeholders.put(marker, symbol + sepColor); - - for (double[] target : coords) { - Vector blockDirection = new Location(owner.getWorld(), target[0], refPos.getY(), target[1]) - .subtract(refPos).toVector().normalize(); - - Vector lookAt = refPos.getDirection().setY(0); - boolean viewable = (lookAt.dot(blockDirection) > 0); - double angle = Math.toDegrees(blockDirection.angle(lookAt.crossProduct(new Vector(0, 1, 0)))); - String tMarker = marker; - - if (!viewable) - angle = (angle > 90) ? 180 : 0; - else if (active && hlMarker != null && hlSymbol != null && angle > 90 - hlMaxAngle && angle < 90 + hlMaxAngle) - tMarker = hlMarker; - - int start = compass.length() - (int) Math.round(2 * angle * compass.length() / 360); - - compass = (start < 2) ? tMarker + compass.substring(start + 1) - : compass.substring(0, start - 1) + tMarker + compass.substring(start); - } - } - } - - for (String placeholder : placeholders.keySet()) - compass = compass.replaceAll(placeholder, placeholders.get(placeholder)); - - return compass; - } -} diff --git a/src/me/arboriginal/SimpleCompass/compasses/ActionbarCompass.java b/src/me/arboriginal/SimpleCompass/compasses/ActionbarCompass.java deleted file mode 100644 index 03bfb46..0000000 --- a/src/me/arboriginal/SimpleCompass/compasses/ActionbarCompass.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.arboriginal.SimpleCompass.compasses; - -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; - -public class ActionbarCompass extends AbstractCompass { - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public ActionbarCompass(SimpleCompass plugin, Player player) { - super(plugin, player, CompassTypes.ACTIONBAR); - } - - // ---------------------------------------------------------------------------------------------- - // SimpleCompass methods - // ---------------------------------------------------------------------------------------------- - - @Override - public void display(String datas) { - owner.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(datas)); - } - - @Override - public void refresh() { - super.refresh(); - - if (sc.config.getBoolean("compass.ACTIONBAR.maintain_when_not_moving") && task == null) { - task = new BukkitRunnable() { - @Override - public void run() { - if (isCancelled()) return; - refresh(); - } - }; - - Long delay = sc.config.getLong("compass.ACTIONBAR.maintain_delay"); - - task.runTaskTimer(sc, delay, delay); - } - } -} diff --git a/src/me/arboriginal/SimpleCompass/compasses/BossbarCompass.java b/src/me/arboriginal/SimpleCompass/compasses/BossbarCompass.java deleted file mode 100644 index 9178b30..0000000 --- a/src/me/arboriginal/SimpleCompass/compasses/BossbarCompass.java +++ /dev/null @@ -1,141 +0,0 @@ -package me.arboriginal.SimpleCompass.compasses; - -import java.util.Map; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.boss.BossBar; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; -import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public class BossbarCompass extends AbstractCompass { - public BossBar bossbar; - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public BossbarCompass(SimpleCompass plugin, Player player) { - super(plugin, player, CompassTypes.BOSSBAR); - } - - // ---------------------------------------------------------------------------------------------- - // SimpleCompass methods - // ---------------------------------------------------------------------------------------------- - - @Override - public void delete() { - super.delete(); - sc.tasks.set(TasksTypes.REMOVEWARNING, owner, this); - } - - @Override - public void display(String datas) { - bossbar.setTitle(datas); - bossbar.setProgress(getProgress()); - } - - @Override - public void refresh() { - super.refresh(); - - if (sc.config.getBoolean("compass.BOSSBAR.disappear_when_not_moving")) { - if (task != null) task.cancel(); - - bossbar.setVisible(true); - - task = new BukkitRunnable() { - @Override - public void run() { - if (isCancelled()) return; - bossbar.setVisible(false); - this.cancel(); - } - }; - - task.runTaskLaterAsynchronously(sc, sc.config.getInt("compass.BOSSBAR.disappear_delay")); - } - } - - @Override - public void init() { - super.init(); - - bossbar = Bukkit.createBossBar("", - BarColor.valueOf(sc.config.getString("compass.BOSSBAR.attributes.color")), - BarStyle.valueOf(sc.config.getString("compass.BOSSBAR.attributes.style"))); - - bossbar.addPlayer(owner); - bossbar.setProgress(getProgress()); - bossbar.setVisible(true); - } - - // ---------------------------------------------------------------------------------------------- - // Specific methods - // ---------------------------------------------------------------------------------------------- - - private void alterColor(double durability) { - Object levels = sc.config.get("compass.BOSSBAR.attributes.elytra_durability.levels"); - - if (levels == null || !(levels instanceof Map)) return; - - durability *= 100; - - for (Object value : ((Map) levels).keySet()) { - if (durability < (int) value) { - bossbar.setColor(BarColor.valueOf((String) ((Map) levels).get(value))); - return; - } - } - - bossbar.setColor(BarColor.valueOf(sc.config.getString("compass.BOSSBAR.attributes.color"))); - } - - @SuppressWarnings("deprecation") - private int elytraDurabilityOldMethod(ItemStack chestplate) { - try { - if (chestplate.getClass().getMethod("getDurability", (Class[]) null) != null) - return (int) chestplate.getDurability(); - } - catch (Exception e) {} - - return -1; - } - - private double getProgress() { - String cacheKey = "compass." + type; - Double progress = (Double) sc.cache.get(owner.getUniqueId(), cacheKey); - - if (progress != null) return progress; - - if (/**/sc.config.getBoolean("compass.BOSSBAR.attributes.elytra_durability.wearing") - || (sc.config.getBoolean("compass.BOSSBAR.attributes.elytra_durability.gliding") && owner.isGliding())) { - ItemStack chestplate = owner.getInventory().getChestplate(); - - if (chestplate != null && chestplate.getType().equals(Material.ELYTRA) - && !chestplate.getItemMeta().isUnbreakable()) { - Map metas = chestplate.getItemMeta().serialize(); - - int damages = (metas.containsKey("Damage") && metas.get("Damage") instanceof Integer) - ? (int) metas.get("Damage") - : elytraDurabilityOldMethod(chestplate); - - if (damages > -1) { - progress = Math.max(0, 1 - damages / ((double) chestplate.getType().getMaxDurability())); - - alterColor(progress); - } - } - } - - if (progress == null) progress = sc.config.getDouble("compass.BOSSBAR.attributes.progress"); - - sc.cache.set(owner.getUniqueId(), cacheKey, progress, sc.config.getInt("delays.elytra_durability") * 1000); - - return progress; - } -} diff --git a/src/me/arboriginal/SimpleCompass/managers/CompassManager.java b/src/me/arboriginal/SimpleCompass/managers/CompassManager.java deleted file mode 100644 index 5a5aa78..0000000 --- a/src/me/arboriginal/SimpleCompass/managers/CompassManager.java +++ /dev/null @@ -1,289 +0,0 @@ -package me.arboriginal.SimpleCompass.managers; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; -import org.bukkit.configuration.MemorySection; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.scheduler.BukkitRunnable; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; -import me.arboriginal.SimpleCompass.compasses.ActionbarCompass; -import me.arboriginal.SimpleCompass.compasses.BossbarCompass; -import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public class CompassManager { - public enum RequirementsSections { - HOTBAR, INVENTORY, MAIN_HAND, OFF_HAND, - } - - private SimpleCompass sc; - private HashMap> compasses; - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public CompassManager(SimpleCompass plugin) { - sc = plugin; - compasses = new HashMap>(); - - for (CompassTypes type : CompassTypes.values()) compasses.put(type, new HashMap()); - } - - // ---------------------------------------------------------------------------------------------- - // Misc methods - // ---------------------------------------------------------------------------------------------- - - public void commandTrigger(String command) { - if (sc.config.getList("commands_trigger_refresh").contains(command.split(" ")[0])) - for (Player player : sc.getServer().getOnlinePlayers()) sc.tasks.set(TasksTypes.REFRESH_STATUS, player); - } - - public void unload() { - removeCompass(); - } - - // ---------------------------------------------------------------------------------------------- - // Compass methods - // ---------------------------------------------------------------------------------------------- - - public void createCompass(CompassTypes type, Player player) { - UUID uid = player.getUniqueId(); - AbstractCompass compass = getCompass(type, uid); - - if (compass != null) return; - - switch (type) { - case ACTIONBAR: - compass = new ActionbarCompass(sc, player); - break; - - case BOSSBAR: - compass = new BossbarCompass(sc, player); - break; - } - - if (compass != null) { - BukkitRunnable task = sc.tasks.get(TasksTypes.REMOVEWARNING, uid); - - if (task != null) task.run(); - - compasses.get(type).put(uid, compass); - } - } - - public AbstractCompass getCompass(CompassTypes type, UUID uid) { - return compasses.get(type).get(uid); - } - - public void refreshCompass(Player player, CompassTypes type) { - refreshCompassState(player, type); - refreshCompassDatas(player, type); - } - - public void removeCompass() { - for (CompassTypes type : CompassTypes.values()) removeCompass(type); - } - - public void removeCompass(CompassTypes type) { - Iterator it = compasses.get(type).keySet().iterator(); - while (it.hasNext()) { - AbstractCompass compass = getCompass(type, it.next()); - if (compass != null) compass.delete(); - it.remove(); - } - } - - public void removeCompass(Player player) { - for (CompassTypes type : CompassTypes.values()) removeCompass(type, player); - } - - public void removeCompass(CompassTypes type, Player player) { - removeCompass(type, player.getUniqueId()); - } - - public void removeCompass(CompassTypes type, UUID uid) { - AbstractCompass compass = getCompass(type, uid); - if (compass == null) return; - compass.delete(); - compasses.get(type).remove(uid); - } - - // ---------------------------------------------------------------------------------------------- - // Compass state methods - // ---------------------------------------------------------------------------------------------- - - public boolean getCompassState(Player player, CompassTypes type) { - if (!player.hasPermission("scompass.use") || !player.hasPermission("scompass.use." + type)) return false; - - boolean active = false; - - switch (sc.datas.compassOptionGet(player, type)) { - case ALWAYS: - active = true; - break; - - case VEHICLE: - active = player.isInsideVehicle(); - break; - - case ELYTRA: - active = player.isGliding(); - break; - - case ELYTRA_VEHICLE: - active = (player.isInsideVehicle() || player.isGliding()); - break; - - default: - active = false; - } - - return active && hasRequiredItems(player, type, true); - } - - public void refreshCompassState() { - for (Player player : sc.getServer().getOnlinePlayers()) refreshCompassState(player); - } - - public void refreshCompassState(CompassTypes type) { - for (Player player : sc.getServer().getOnlinePlayers()) refreshCompassState(player, type); - } - - public void refreshCompassState(Player player) { - for (CompassTypes type : CompassTypes.values()) refreshCompassState(player, type); - } - - public void refreshCompassState(Player player, CompassTypes type) { - if (getCompassState(player, type)) - createCompass(type, player); - else - removeCompass(type, player); - } - - // ---------------------------------------------------------------------------------------------- - // Compass item requirements methods - // ---------------------------------------------------------------------------------------------- - - ItemStack consumeItem(Player player, CompassTypes type, ItemStack stack) { - stack.setAmount(stack.getAmount() - 1); - sc.datas.cooldownConsumeSet(player, type); - - return stack; - } - - public boolean hasRequiredItems(Player player, CompassTypes type, boolean consume) { - if (((MemorySection) sc.config.get("compass." + type + ".require.items")).getKeys(false).isEmpty()) return true; - - List lores = sc.config.getList("ignored_lores"); - PlayerInventory inv = player.getInventory(); - ItemStack stack; - - consume &= shouldConsume(player, type); - - for (RequirementsSections section : RequirementsSections.values()) { - List items = sc.config.getList("compass." + type + ".require.items." + section, new ArrayList()); - - if (items.isEmpty()) continue; - - switch (section) { - case OFF_HAND: - stack = inv.getItemInOffHand(); - - if (stack != null && isValidItem(stack, items, lores)) { - if (consume) inv.setItemInOffHand(consumeItem(player, type, stack)); - return true; - } - break; - - case MAIN_HAND: - stack = inv.getItemInMainHand(); - - if (stack != null && isValidItem(stack, items, lores)) { - if (consume) inv.setItemInMainHand(consumeItem(player, type, stack)); - return true; - } - break; - - case HOTBAR: - case INVENTORY: - for (int i = (section.equals(RequirementsSections.HOTBAR) ? 0 : 9); i <= (section - .equals(RequirementsSections.HOTBAR) ? 8 : 35); i++) { - stack = inv.getItem(i); - - if (stack == null) continue; - - if (isValidItem(stack, items, lores)) { - if (consume) inv.setItem(i, consumeItem(player, type, stack)); - return true; - } - } - break; - } - } - - return false; - } - - public boolean isValidItem(ItemStack stack, List requiredItems, List ignoredLores) { - if (!requiredItems.contains(stack.getType().toString())) return false; - if (ignoredLores.isEmpty()) return true; - - List itemLores = stack.getItemMeta().getLore(); - - if (itemLores == null) return true; - - for (Object lore : stack.getItemMeta().getLore()) - if (ignoredLores.contains(lore)) return false; - - return true; - } - - public boolean shouldConsume(Player player, CompassTypes type) { - return sc.config.getBoolean("compass." + type + ".require.consume") - && !player.hasPermission("scompass.use.free") - && sc.datas.cooldownConsumeGet(player, type) < 1; - } - - // ---------------------------------------------------------------------------------------------- - // Compass data methods - // ---------------------------------------------------------------------------------------------- - - public void refreshCompassDatas() { - for (CompassTypes type : CompassTypes.values()) refreshCompassDatas(type); - } - - public void refreshCompassDatas(CompassTypes type) { - for (UUID uid : compasses.get(type).keySet()) refreshCompassDatas(type, uid); - } - - public void refreshCompassDatas(CompassTypes type, UUID uid) { - AbstractCompass compass = getCompass(type, uid); - - if (compass == null) return; - - if (!((MemorySection) sc.config.get("compass." + type + ".require.items")).getKeys(false).isEmpty() - && shouldConsume(compass.owner, type) && !hasRequiredItems(compass.owner, type, true)) - removeCompass(type, compass.owner); - else - compass.refresh(); - } - - public void refreshCompassDatas(Player player) { - refreshCompassDatas(player.getUniqueId()); - } - - public void refreshCompassDatas(Player player, CompassTypes type) { - refreshCompassDatas(type, player.getUniqueId()); - } - - public void refreshCompassDatas(UUID uid) { - for (CompassTypes type : CompassTypes.values()) refreshCompassDatas(type, uid); - } -} diff --git a/src/me/arboriginal/SimpleCompass/managers/DataManager.java b/src/me/arboriginal/SimpleCompass/managers/DataManager.java deleted file mode 100644 index 2e0682d..0000000 --- a/src/me/arboriginal/SimpleCompass/managers/DataManager.java +++ /dev/null @@ -1,203 +0,0 @@ -package me.arboriginal.SimpleCompass.managers; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import me.arboriginal.SimpleCompass.commands.AbstractCommand.CompassOptions; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; -import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; -import me.arboriginal.SimpleCompass.utils.CacheUtil; - -public class DataManager { - private SimpleCompass sc; - private File file; - - public YamlConfiguration users; - - //----------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public DataManager(SimpleCompass plugin) { - sc = plugin; - users = new YamlConfiguration(); - file = new File(sc.getDataFolder(), "usersDatas.yml"); - - if (file.exists()) - users = YamlConfiguration.loadConfiguration(file); - else - saveUserDatas(); - } - - // ---------------------------------------------------------------------------------------------- - // General methods - // ---------------------------------------------------------------------------------------------- - - public String getKey(Player player, String key) { - return player.getUniqueId() + "." + key; - } - - public boolean saveUserDatas() { - try { - if (!file.exists()) file.createNewFile(); - - users.save(file); - return true; - } - catch (IOException e) { - sc.getLogger().severe(sc.prepareMessage("file_not_writable")); - } - - return false; - } - - // ---------------------------------------------------------------------------------------------- - // Cooldown methods - // ---------------------------------------------------------------------------------------------- - - public Long cooldownGet(Player player, String cooldown) { - String dataKey = cooldownKey(player, cooldown); - - if (users.contains(dataKey)) { - Long left = users.getLong(dataKey) - CacheUtil.now(); - - if (left > 0) return left; - } - - return 0L; - } - - public String cooldownKey(Player player, String cooldown) { - return getKey(player, "cooldowns." + cooldown); - } - - public void cooldownSet(Player player, String cooldown, int delay) { - users.set(cooldownKey(player, cooldown), CacheUtil.now() + delay * 1000); - saveUserDatas(); - } - - // Book cooldown - - public String cooldownBook() { - return "interface_book"; - } - - public Long cooldownBookGet(Player player) { - return cooldownGet(player, cooldownBook()); - } - - public void cooldownBookSet(Player player) { - cooldownSet(player, cooldownBook(), sc.config.getInt("interface.give_book_cooldown")); - } - - // Consume cooldown - - public String cooldownConsume(CompassTypes type) { - return "consume_" + type; - } - - public Long cooldownConsumeGet(Player player, CompassTypes type) { - return cooldownGet(player, cooldownConsume(type)); - } - - public void cooldownConsumeSet(Player player, CompassTypes type) { - cooldownSet(player, cooldownConsume(type), sc.config.getInt("compass." + type + ".require.duration")); - } - - // ---------------------------------------------------------------------------------------------- - // Compass options methods - // ---------------------------------------------------------------------------------------------- - - public CompassOptions compassOptionGet(Player player, CompassTypes type) { - String key = compassOptionKey(player, type); - - return CompassOptions.valueOf(users.contains(key) ? users.getString(key) - : sc.config.getString("compass." + type + ".default.option")); - } - - public String compassOptionKey(Player player, CompassTypes type) { - return getKey(player, type + ".option"); - } - - public void compassOptionSet(Player player, CompassTypes type, CompassOptions option) { - if (sc.config.getBoolean("single_compass_mode") && !option.equals(CompassOptions.DISABLED)) - for (CompassTypes otherType : CompassTypes.values()) if (!type.equals(otherType)) { - users.set(compassOptionKey(player, otherType), CompassOptions.DISABLED.toString()); - sc.compasses.removeCompass(otherType, player); - } - - users.set(compassOptionKey(player, type), option.toString()); - saveUserDatas(); - - sc.tasks.set(TasksTypes.valueOf("REFRESH_" + type), player); - } - - // ---------------------------------------------------------------------------------------------- - // Compass modes methods - // ---------------------------------------------------------------------------------------------- - - public CompassModes compassModeGet(Player player, CompassTypes type) { - String key = compassModeKey(player, type); - - return CompassModes.valueOf(users.contains(key) ? users.getString(key) - : sc.config.getString("compass." + type + ".default.mode")); - } - - public String compassModeKey(Player player, CompassTypes type) { - return getKey(player, type + ".mode"); - } - - public void compassModeSet(Player player, CompassTypes type, CompassModes mode) { - users.set(compassModeKey(player, type), mode.toString()); - saveUserDatas(); - - sc.tasks.set(TasksTypes.valueOf("REFRESH_" + type), player); - } - - // ---------------------------------------------------------------------------------------------- - // Tracker targets methods - // ---------------------------------------------------------------------------------------------- - - public boolean activeTargetAdd(Player player, String type, String name) { - List list = activeTargetsList(player, type); - if (list.contains(name)) return false; - - list.add(name); - activeTargetsSave(player, type, list); - return true; - } - - public boolean activeTargetDel(Player player, String type, String name) { - List list = activeTargetsList(player, type); - if (!list.contains(name)) return false; - - list.remove(name); - activeTargetsSave(player, type, list); - return true; - } - - public String activeTargetsKey(Player player, String type) { - return getKey(player, "active_targets." + type); - } - - public List activeTargetsList(Player player, String type) { - String key = activeTargetsKey(player, type); - List list = new ArrayList(); - - if (users.getList(key) != null) for (String target : users.getStringList(key)) list.add(target); - - return list; - } - - public void activeTargetsSave(Player player, String type, List list) { - users.set(activeTargetsKey(player, type), list); - saveUserDatas(); - sc.tasks.set(TasksTypes.REFRESH_ACTIONBAR, player); - sc.tasks.set(TasksTypes.REFRESH_BOSSBAR, player); - } -} diff --git a/src/me/arboriginal/SimpleCompass/managers/TargetManager.java b/src/me/arboriginal/SimpleCompass/managers/TargetManager.java deleted file mode 100644 index 0d79970..0000000 --- a/src/me/arboriginal/SimpleCompass/managers/TargetManager.java +++ /dev/null @@ -1,187 +0,0 @@ -package me.arboriginal.SimpleCompass.managers; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; -import org.bukkit.entity.Player; -import com.google.common.collect.ImmutableMap; -import me.arboriginal.SimpleCompass.plugin.AbstractTracker; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public class TargetManager { - private SimpleCompass sc; - - public String[] trackersPriority; - - public HashMap>> activeTargets; - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public TargetManager(SimpleCompass plugin) { - sc = plugin; - activeTargets = new HashMap>>(); - - for (String trackerID : sc.trackers.keySet()) - activeTargets.put(trackerID, new HashMap>()); - - trackersPriority = new String[sc.trackers.size()]; - if (sc.trackers.size() == 0) return; - - List priority = sc.config.getStringList("trackers_priorities"); - for (int i = 0; i < priority.size(); i++) trackersPriority[i] = priority.get(i); - } - - // ---------------------------------------------------------------------------------------------- - // Trackers methods - // ---------------------------------------------------------------------------------------------- - - public boolean canUseTracker(Player player, String trackerID) { - return player.hasPermission("scompass.track.*") || player.hasPermission("scompass.track." + trackerID); - } - - public List getAvailableTrackers(Player player) { - List list = new ArrayList(); - for (String trackerID : sc.trackers.keySet()) if (canUseTracker(player, trackerID)) list.add(trackerID); - return list; - } - - public AbstractTracker getTrackerByName(String name) { - for (String trackerID : sc.trackers.keySet()) { - AbstractTracker tracker = sc.trackers.get(trackerID); - - if (name.toLowerCase().equals(tracker.trackerName().toLowerCase())) return tracker; - } - - return null; - } - - public List getTrackersList(Player player, String startWith) { - List list = new ArrayList(); - - for (String trackerID : sc.targets.getAvailableTrackers(player)) { - String name = sc.trackers.get(trackerID).trackerName(); - - if (name.toLowerCase().startsWith(startWith.toLowerCase())) list.add(name); - } - - return list; - } - - // ---------------------------------------------------------------------------------------------- - // Targets methods - // ---------------------------------------------------------------------------------------------- - - public void activateTarget(Player player, String type, String name) { - UUID uid = player.getUniqueId(); - - if (!activeTargets.get(type).containsKey(uid)) activeTargets.get(type).put(uid, new ArrayList()); - if (activeTargets.get(type).get(uid).contains(name)) return; - - activeTargets.get(type).get(uid).add(name); - sc.datas.activeTargetAdd(player, type, name); - } - - public void disableTarget(Player player, String type, String name) { - UUID uid = player.getUniqueId(); - - if (!activeTargets.get(type).containsKey(uid)) return; - if (!activeTargets.get(type).get(uid).contains(name)) return; - - activeTargets.get(type).get(uid).remove(name); - sc.datas.activeTargetDel(player, type, name); - } - - public HashMap>> getTargetsCoords(Player player) { - HashMap>> list = new HashMap>>(); - list.put("on", new HashMap>()); - list.put("off", new HashMap>()); - - HashMap> stop = new HashMap>(); - UUID uid = player.getUniqueId(); - - List invalids = new ArrayList(); - - for (String trackerID : sc.trackers.keySet()) { - AbstractTracker tracker = sc.trackers.get(trackerID); - if (tracker == null) continue; - - HashMap sublistOn = new HashMap(); - - if (activeTargets.get(trackerID).containsKey(uid)) { - ArrayList closest = new ArrayList(); - - Iterator it = activeTargets.get(trackerID).get(uid).iterator(); - while (it.hasNext()) { - String name = it.next(); - double[] coords = tracker.get(player, name); - if (coords == null) invalids.add(trackerID + ":" + name); - if (coords == null || tracker.playerIsClose(player, coords)) - closest.add(name); - else - sublistOn.put(name, coords); - } - - if (!sublistOn.isEmpty()) list.get("on").put(trackerID, new ArrayList(sublistOn.values())); - if (!closest.isEmpty()) stop.put(tracker, closest); - } - - if (tracker.settings.getBoolean("settings.inactive_target", false)) { - ArrayList sublistOff = new ArrayList(); - - for (String name : tracker.availableTargets(player, "")) { - if (sublistOn.containsKey(name)) continue; - double[] coords = tracker.get(player, name); - if (coords != null) sublistOff.add(coords); - } - - if (!sublistOff.isEmpty()) list.get("off").put(trackerID, sublistOff); - } - } - - if (!stop.isEmpty()) { - stop.forEach((tracker, stopped) -> { - stopped.forEach(name -> { - tracker.disable(player, name); - if (!invalids.contains(tracker.trackerID() + ":" + name)) - tracker.sendMessage(player, "target_auto_disabled", - ImmutableMap.of("tracker", tracker.trackerName(), "target", name)); - }); - }); - } - - return list; - } - - public boolean loadTargets() { - boolean hasLoadedTrackers = false; - - for (Player player : sc.getServer().getOnlinePlayers()) if (loadTargets(player)) hasLoadedTrackers = true; - - return hasLoadedTrackers; - } - - public boolean loadTargets(Player player) { - boolean hasLoadedTrackers = false; - - for (String trackerID : sc.trackers.keySet()) { - List targets = sc.datas.activeTargetsList(player, trackerID); - - if (!targets.isEmpty()) hasLoadedTrackers = true; - - for (String name : targets) activateTarget(player, trackerID, name); - } - - return hasLoadedTrackers; - } - - public void unloadTargets(Player player) { - UUID uid = player.getUniqueId(); - - for (String trackerID : sc.trackers.keySet()) - if (activeTargets.get(trackerID).containsKey(uid)) activeTargets.get(trackerID).remove(uid); - } -} diff --git a/src/me/arboriginal/SimpleCompass/managers/TaskManager.java b/src/me/arboriginal/SimpleCompass/managers/TaskManager.java deleted file mode 100644 index 921d71d..0000000 --- a/src/me/arboriginal/SimpleCompass/managers/TaskManager.java +++ /dev/null @@ -1,156 +0,0 @@ -package me.arboriginal.SimpleCompass.managers; - -import java.util.HashMap; -import java.util.UUID; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; -import me.arboriginal.SimpleCompass.compasses.BossbarCompass; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public class TaskManager { - private SimpleCompass sc; - private HashMap> tasks; - - public enum TasksTypes { - FIX_UUID, REFRESH_ACTIONBAR, REFRESH_BOSSBAR, REFRESH_STATUS, REMOVEWARNING, - } - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public TaskManager(SimpleCompass plugin) { - sc = plugin; - tasks = new HashMap>(); - - for (TasksTypes type : TasksTypes.values()) tasks.put(type, new HashMap()); - } - - // ---------------------------------------------------------------------------------------------- - // Tasks methods - // ---------------------------------------------------------------------------------------------- - - public void clear() { - for (TasksTypes type : TasksTypes.values()) clear(type); - } - - public void clear(Player player) { - clear(player.getUniqueId()); - } - - public void clear(UUID uid) { - for (TasksTypes type : TasksTypes.values()) clear(type, uid); - } - - public void clear(TasksTypes type) { - for (UUID uid : tasks.get(type).keySet()) clear(type, uid); - } - - public void clear(TasksTypes type, Player player) { - clear(type, player.getUniqueId()); - } - - public void clear(TasksTypes type, UUID uid) { - clear(type, uid, get(type, uid)); - } - - public void clear(TasksTypes type, UUID uid, BukkitRunnable task) { - if (task == null) task = get(type, uid); - if (task != null) { - task.cancel(); - tasks.get(type).remove(uid); - } - } - - public BukkitRunnable get(TasksTypes type, UUID uid) { - return tasks.get(type).get(uid); - } - - public void set(TasksTypes type, Player player) { - set(type, player, null); - } - - public void set(TasksTypes type, Player player, Object data) { - UUID uid = player.getUniqueId(); - - if (!sc.isReady) { - if (data != null && data instanceof BossbarCompass) ((BossbarCompass) data).bossbar.removeAll(); - clear(type, uid); - return; - } - - BukkitRunnable task = null; - - switch (type) { - case FIX_UUID: - task = new BukkitRunnable() { - @Override - public void run() { - if (isCancelled() || sc.compasses.getCompass(CompassTypes.BOSSBAR, uid) == null) return; - sc.compasses.removeCompass(CompassTypes.BOSSBAR, player); - sc.compasses.refreshCompassState(player); - clear(type, uid, this); - - if (sc.trackers.isEmpty()) return; - sc.trackers.forEach((trackerID, tracker) -> { - for (String name : tracker.autoloadTargets(player, "")) tracker.activate(player, name, false); - }); - } - }; - - task.runTaskLaterAsynchronously(sc, sc.config.getInt("delays.fix_uuid")); - break; - - case REFRESH_ACTIONBAR: - case REFRESH_BOSSBAR: - CompassTypes compassType = CompassTypes.valueOf(type.toString().substring(8)); - - task = new BukkitRunnable() { - @Override - public void run() { - if (isCancelled()) return; - sc.compasses.refreshCompass(player, compassType); - clear(type, uid, this); - } - }; - - task.runTaskLaterAsynchronously(sc, sc.config.getInt("delays.option_take_effect")); - break; - - case REFRESH_STATUS: - task = new BukkitRunnable() { - @Override - public void run() { - if (isCancelled()) return; - sc.compasses.refreshCompassState(player); - clear(type, uid, this); - } - }; - - task.runTaskLaterAsynchronously(sc, - (data == null || !(data instanceof Integer)) ? sc.config.getInt("delays.refresh_status") : (int) data); - break; - - case REMOVEWARNING: - if (data == null || !(data instanceof BossbarCompass)) break; - - task = new BukkitRunnable() { - @Override - public void run() { - if (isCancelled()) return; - ((BossbarCompass) data).bossbar.removeAll(); - this.cancel(); - } - }; - - task.runTaskLaterAsynchronously(sc, sc.config.getInt("compass.BOSSBAR.warnPlayerNoMoreFuel") * 20); - break; - } - - if (task != null) { - clear(type, uid); - tasks.get(type).put(uid, task); - } - } -} diff --git a/src/me/arboriginal/SimpleCompass/plugin/AbstractTracker.java b/src/me/arboriginal/SimpleCompass/plugin/AbstractTracker.java deleted file mode 100644 index 290b1c8..0000000 --- a/src/me/arboriginal/SimpleCompass/plugin/AbstractTracker.java +++ /dev/null @@ -1,435 +0,0 @@ -package me.arboriginal.SimpleCompass.plugin; - -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import org.bukkit.Location; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.MemorySection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import com.google.common.collect.ImmutableMap; - -public abstract class AbstractTracker { - protected SimpleCompass sc; - protected File sf; - protected URL res; - - public enum TrackingActions { - ADD, ACCEPT, ASK, DEL, DENY, HELP, START, STOP, - } - - public enum TargetSelector { - ACTIVE, AVAILABLE, NEW, NEWCOORDS, NONE, - } - - public FileConfiguration settings; - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public AbstractTracker(SimpleCompass plugin) { - sc = plugin; - sf = new File(sc.getDataFolder(), "trackers/" + getClass().getSimpleName() + ".yml"); - res = getClass().getResource("/settings.yml"); - } - - // ---------------------------------------------------------------------------------------------- - // Tracker methods - // ---------------------------------------------------------------------------------------------- - - public abstract String trackerID(); - - public String github() { - return null; - } - - public String trackerName() { - return settings.getString("locales." + sc.config.getString("language") + ".name"); - } - - public String version() { - return "?"; - } - - // ---------------------------------------------------------------------------------------------- - // Initialization and update methods - // ---------------------------------------------------------------------------------------------- - - /** - * At this state, config has not been read from user file, - * so DO NOT USE sc.config here, and DO NOT call methods which use this. - */ - public boolean init() { - if (res == null) { - sc.getLogger().warning("settings.yml missing in " + sf.getAbsolutePath()); - return false; - } - - settings = YamlConfiguration.loadConfiguration(sf); - settings.options().copyDefaults(true); - - InputStream is; - - try { - is = res.openStream(); - } - catch (Exception e) { - sc.getLogger().warning("Can't write default settings to " + sf.getAbsolutePath()); - return false; - } - - settings.setDefaults(YamlConfiguration.loadConfiguration(new InputStreamReader(is))); - - try { - settings.save(sf); - } - catch (Exception e) { - sc.getLogger().severe("Can't write to " + sf.getAbsolutePath()); - return false; - } - - return true; - } - - public void checkUpdate(CommandSender sender) { - if (!settings.getBoolean("settings.check_update", true)) return; - - String github = github(); - - if (github == null) { - sendMessage(sender, "tracker_check_update_available", - ImmutableMap.of("tracker", trackerName(), "version", "new", "current", version())); - return; - } - - String version = sc.githubVersion(github); - - if (version == null) - sendMessage(sender, "tracker_check_update_failed", ImmutableMap.of("tracker", trackerName())); - else { - String current = version(); - if (!version.equals(current)) - sendMessage(sender, "tracker_check_update_available", - ImmutableMap.of("tracker", trackerName(), "version", version, "current", current)); - } - } - - // ---------------------------------------------------------------------------------------------- - // Utils methods - // ---------------------------------------------------------------------------------------------- - - public void sendMessage(CommandSender sender, String key) { - sendMessage(sender, key, null); - } - - public void sendMessage(CommandSender sender, String key, Map placeholders) { - if (key.isEmpty()) return; - String message = prepareMessage(key, placeholders); - if (!message.isEmpty()) sender.sendMessage(message); - } - - public String prepareMessage(String key) { - return prepareMessage(key, null); - } - - public String prepareMessage(String key, Map placeholders) { - String message = settings.getString("locales." + sc.config.getString("language") + "." + key); - if (message == null) message = sc.locale.getString(key); - if (message == null) return ""; - - if (placeholders != null) { - for (Iterator i = placeholders.keySet().iterator(); i.hasNext();) { - String placeholder = i.next(); - message = message.replace("{" + placeholder + "}", placeholders.get(placeholder)); - } - } - - return sc.formatMessage(message.replace("{prefix}", sc.locale.getString("prefix"))); - } - - // ---------------------------------------------------------------------------------------------- - // Actions methods - // ---------------------------------------------------------------------------------------------- - - public TrackingActions getActionByName(String name) { - for (TrackingActions action : TrackingActions.values()) - if (name.equalsIgnoreCase(getActionName(action))) return action; - - return null; - } - - public String getActionName(TrackingActions action) { - return sc.locale.getString("actions." + action); - } - - public List getActionsAvailable(Player player, boolean keepUnavailable) { - List list = new ArrayList(); - if (player.hasPermission("scompass.help")) list.add(TrackingActions.HELP); - return list; - } - - public boolean limitReached(Player player, TrackingActions action, boolean showError, Integer current) { - if (!settings.contains("settings.limits." + action)) return false; - int limit = settings.getInt("settings.limits." + action), count; - - if (current == null) { - UUID uid = player.getUniqueId(); - - count = sc.targets.activeTargets.get(trackerID()).containsKey(uid) - ? sc.targets.activeTargets.get(trackerID()).get(uid).size() - : 0; - } - else - count = current; - - if (count < limit) return false; - - if (showError) sendMessage(player, "commands.sctrack.limits." + action, - ImmutableMap.of("limit", "" + limit, "tracker", trackerName())); - - return true; - } - - public TargetSelector requireTarget(TrackingActions action) { - switch (action) { - case ADD: - return TargetSelector.NEW; - - case ASK: - case DEL: - case START: - return TargetSelector.AVAILABLE; - - case STOP: - return TargetSelector.ACTIVE; - - default: - return TargetSelector.NONE; - } - } - - // ---------------------------------------------------------------------------------------------- - // Targets methods - // ---------------------------------------------------------------------------------------------- - - public boolean activate(Player player, String name, boolean showError) { - if (limitReached(player, TrackingActions.START, showError, null)) return false; - sc.targets.activateTarget(player, trackerID(), name); - return true; - } - - public List activeTargets(Player player, String startWith) { - List list = new ArrayList(); - - for (String candidate : sc.datas.activeTargetsList(player, trackerID())) - if (startWith.isEmpty() || candidate.toLowerCase().startsWith(startWith.toLowerCase())) list.add(candidate); - - return list; - } - - public List availableTargets(Player player, String startWith) { - List list = new ArrayList(); - String root = key(player); - - if (datas().contains(root)) - ((MemorySection) datas().get(root)).getKeys(false).forEach(candidate -> { - if (startWith.isEmpty() || candidate.toLowerCase().startsWith(startWith.toLowerCase())) list.add(candidate); - }); - - return list; - } - - public List autoloadTargets(Player player, String startWith) { - List list = new ArrayList(); - - if (settings.getBoolean("settings.autoload_target", false)) { - String perm = "scompass.track.auto." + trackerID() + "."; - for (String name : availableTargets(player, startWith)) - if (player.hasPermission(perm + "*") || player.hasPermission(perm + name)) list.add(name); - } - - return list; - } - - public boolean del(Player player, String name) { - String key = key(player, name); - - if (datas().contains(key)) { - disable(player, name); - return save(key, null); - } - - return false; - } - - public void disable(Player player, String name) { - sc.targets.disableTarget(player, trackerID(), name); - } - - public double[] get(Player player, String name) { - String key = key(player, name); - - if (datas().contains(key + ".x") && datas().contains(key + ".z")) - return new double[] { datas().getDouble(key + ".x"), datas().getDouble(key + ".z") }; - - return null; - } - - public double[] getCoords(Player player, String[] args) { - double[] coords = null; - - if (args.length == 5) - try { - coords = new double[] { Double.parseDouble(args[3]), Double.parseDouble(args[4]) }; - } - catch (Exception e) {} - - if (coords == null) coords = new double[] { player.getLocation().getX(), player.getLocation().getZ() }; - - return coords; - } - - public List list(Player player, TrackingActions action, String startWith) { - if (action == null) return availableTargets(player, startWith); - - List list = new ArrayList(); - - switch (action) { - case ACCEPT: - case ADD: - case DENY: - break; - - case ASK: - case DEL: - case START: - list.addAll(availableTargets(player, startWith)); - break; - - default: - list.addAll(activeTargets(player, startWith)); - break; - } - - return list; - } - - public List listFiltered(Player player, List list) { - if (player.hasPermission("scompass.track." + trackerID() + ".defined.*")) return list; - - List filtered = new ArrayList(); - for (String name : list) - if (player.hasPermission("scompass.track." + trackerID() + ".defined." + name)) filtered.add(name); - - return filtered; - } - - public boolean set(Player player, String name, double[] coords) { - String key = key(player, name); - if (datas().contains(key)) return false; - - String root = key(player); - int current = datas().contains(root) - ? datas().getConfigurationSection(root).getKeys(false).size() - : 0; - - if (limitReached(player, TrackingActions.ADD, true, current)) return false; - - boolean success = (save(key + ".x", coords[0]) && save(key + ".z", coords[1])); - if (success) return true; - - save(key, null); - return false; - } - - public boolean playerIsClose(Player player, double[] coords) { - int dist = settings.getInt("settings.auto_disabled", 0); - return (dist > 0 && player.getLocation().distance( - new Location(player.getWorld(), coords[0], player.getLocation().getY(), coords[1])) < dist); - } - - // ---------------------------------------------------------------------------------------------- - // Command methods - // ---------------------------------------------------------------------------------------------- - - public List commandSuggestions(Player player, String[] args, HashMap parsed) { - List list = new ArrayList<>(); - if (args.length < 1 || args.length > 3) return list; - - switch (args.length) { - case 2: - for (TrackingActions action : getActionsAvailable(player, false)) { - String name = getActionName(action); - if (name.toLowerCase().startsWith(args[1].toLowerCase())) list.add(name); - } - break; - - case 3: - list.addAll(list(player, (TrackingActions) parsed.get("action"), args[2])); - break; - } - - return list; - } - - public String help(Player player, String command) { - String sep = prepareMessage("commands.sctrack.help.separator") + "\n"; - String help = sep + prepareMessage("commands.sctrack.help.header", ImmutableMap.of("tracker", trackerName())) + sep; - - List list = new ArrayList(); - list.add("noargs"); - - HashMap placeholders = new HashMap(); - placeholders.put("command", command); - placeholders.put("tracker", trackerName()); - - for (TrackingActions action : getActionsAvailable(player, true)) if (!action.equals(TrackingActions.HELP)) { - list.add(action.toString()); - placeholders.put(action.toString(), sc.locale.getString("actions." + action)); - } - - for (String key : list) help += prepareMessage("help." + key, placeholders) + "\n"; - return help + sep; - } - - public void parseArguments(Player player, String[] args, HashMap parsed) { - TrackingActions action = getActionByName(args[1]); - if (action == null || !getActionsAvailable(player, false).contains(action)) return; - parsed.put("action", action); - if (args.length == 2) return; - if (get(player, args[2]) != null) parsed.put("target", args[2]); - } - - public abstract boolean perform(Player player, String command, TrackingActions action, String target, String[] args); - - // ---------------------------------------------------------------------------------------------- - // Storage methods - // ---------------------------------------------------------------------------------------------- - - public MemorySection datas() { - return sc.datas.users; - } - - public String key(Player player) { - return key(player, null); - } - - public String key(Player player, String name) { - return sc.datas.getKey(player, trackerID() + (name == null ? "" : "." + name)); - } - - public boolean save(String key, Object value) { - datas().set(key, value); - return sc.datas.saveUserDatas(); - } -} diff --git a/src/me/arboriginal/SimpleCompass/plugin/Listeners.java b/src/me/arboriginal/SimpleCompass/plugin/Listeners.java deleted file mode 100644 index d44d55a..0000000 --- a/src/me/arboriginal/SimpleCompass/plugin/Listeners.java +++ /dev/null @@ -1,157 +0,0 @@ -package me.arboriginal.SimpleCompass.plugin; - -import java.util.HashMap; -import java.util.UUID; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityPickupItemEvent; -import org.bukkit.event.entity.EntityToggleGlideEvent; -import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.inventory.InventoryCloseEvent; -import org.bukkit.event.inventory.InventoryOpenEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerCommandSendEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerSwapHandItemsEvent; -import org.bukkit.event.server.ServerCommandEvent; -import org.bukkit.event.vehicle.VehicleEnterEvent; -import org.bukkit.event.vehicle.VehicleExitEvent; -import org.bukkit.inventory.InventoryHolder; -import me.arboriginal.SimpleCompass.managers.TaskManager.TasksTypes; -import me.arboriginal.SimpleCompass.utils.CacheUtil; - -public class Listeners implements Listener { - public SimpleCompass sc; - public HashMap locks; - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public Listeners(SimpleCompass plugin) { - sc = plugin; - locks = new HashMap(); - } - - // ---------------------------------------------------------------------------------------------- - // Listener methods - // ---------------------------------------------------------------------------------------------- - - @EventHandler - public void onEntityPickupItem(EntityPickupItemEvent event) { - if (event.isCancelled() || !isPlayer(event.getEntity())) return; - sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) event.getEntity(), sc.config.getInt("delays.pickup_refresh")); - } - - @EventHandler - public void onEntityToggleGlide(EntityToggleGlideEvent event) { - if (event.isCancelled() || !isPlayer(event.getEntity())) return; - sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) event.getEntity()); - } - - @EventHandler - public void onInventoryClose(InventoryCloseEvent event) { - InventoryHolder holder = event.getInventory().getHolder(); - if (!(holder instanceof Player) || !isPlayer((Player) holder)) return; - sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) holder); - } - - @EventHandler - public void onInventoryOpen(InventoryOpenEvent event) { - if (event.isCancelled()) return; - - sc.tasks.clear(TasksTypes.REFRESH_STATUS, (Player) event.getPlayer()); - } - - @EventHandler - public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - if (event.isCancelled()) return; - - sc.compasses.commandTrigger(event.getMessage().substring(1)); - } - - @EventHandler - public void onPlayerCommandSend(PlayerCommandSendEvent event) { - if (!isPlayer(event.getPlayer())) return; - sc.tasks.set(TasksTypes.REFRESH_STATUS, event.getPlayer()); - } - - @EventHandler - public void onPlayerDeath(PlayerDeathEvent event) { - if (!isPlayer(event.getEntity())) return; - sc.compasses.removeCompass((Player) event.getEntity()); - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - - sc.cache.init(player.getUniqueId()); - sc.targets.loadTargets(player); - sc.tasks.set(TasksTypes.REFRESH_STATUS, player); - sc.tasks.set(TasksTypes.FIX_UUID, player); - } - - @EventHandler - public void onPlayerMove(PlayerMoveEvent event) { - if (event.isCancelled()) return; - - Player player = event.getPlayer(); - UUID uid = player.getUniqueId(); - Long now = CacheUtil.now(); - - if (locks.containsKey(uid) && locks.get(uid) > now) return; - - locks.put(uid, now + sc.config.getInt("delays.update_compass")); - sc.compasses.refreshCompassDatas(player); - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - UUID uid = player.getUniqueId(); - - locks.remove(uid); - sc.tasks.clear(player); - sc.targets.unloadTargets(player); - sc.cache.clear(uid); - } - - @EventHandler - public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) { - if (event.isCancelled()) return; - - sc.tasks.set(TasksTypes.REFRESH_STATUS, event.getPlayer()); - } - - @EventHandler - public void onVehicleEnter(VehicleEnterEvent event) { - if (event.isCancelled() || !isPlayer(event.getEntered())) return; - sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) event.getEntered()); - } - - @EventHandler - public void onVehicleExit(VehicleExitEvent event) { - if (event.isCancelled() || !isPlayer(event.getExited())) return; - sc.tasks.set(TasksTypes.REFRESH_STATUS, (Player) event.getExited()); - } - - @EventHandler - public void onServerCommand(ServerCommandEvent event) { - if (event.isCancelled()) return; - - sc.compasses.commandTrigger(event.getCommand()); - } - - // ----------------------------------------------------------------------------------------------- - // Private methods - // ----------------------------------------------------------------------------------------------- - - private boolean isPlayer(Entity entity) { - return (entity instanceof Player) && !entity.hasMetadata("NPC"); - } -} diff --git a/src/me/arboriginal/SimpleCompass/plugin/SimpleCompass.java b/src/me/arboriginal/SimpleCompass/plugin/SimpleCompass.java deleted file mode 100644 index c5f5439..0000000 --- a/src/me/arboriginal/SimpleCompass/plugin/SimpleCompass.java +++ /dev/null @@ -1,381 +0,0 @@ -package me.arboriginal.SimpleCompass.plugin; - -import java.io.File; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import org.apache.commons.lang.time.DurationFormatUtils; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.plugin.java.JavaPlugin; -import com.google.common.collect.ImmutableMap; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import me.arboriginal.SimpleCompass.commands.InterfaceCommand; -import me.arboriginal.SimpleCompass.commands.OptionCommand; -import me.arboriginal.SimpleCompass.commands.TrackCommand; -import me.arboriginal.SimpleCompass.managers.CompassManager; -import me.arboriginal.SimpleCompass.managers.DataManager; -import me.arboriginal.SimpleCompass.managers.TargetManager; -import me.arboriginal.SimpleCompass.managers.TaskManager; -import me.arboriginal.SimpleCompass.utils.CacheUtil; -import me.arboriginal.SimpleCompass.utils.ConfigUtil; -import me.arboriginal.SimpleCompass.utils.LangUtil; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.ClickEvent; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.TextComponent; - -public class SimpleCompass extends JavaPlugin implements TabCompleter { - public FileConfiguration config, locale; - public CacheUtil cache; - public DataManager datas; - public TaskManager tasks; - public TargetManager targets; - public Listeners listeners; - public CompassManager compasses = null; - public boolean isReady = false; - - public HashMap trackers; - - // ---------------------------------------------------------------------------------------------- - // JavaPlugin methods - // ---------------------------------------------------------------------------------------------- - - @Override - public void onDisable() { - super.onDisable(); - - isReady = false; - compasses.unload(); - tasks.clear(); - } - - @Override - public void onEnable() { - super.onEnable(); - - try { - getServer().spigot(); - } - catch (Exception e) { - getServer().getPluginManager().disablePlugin(this); - getLogger().severe("This plugin only works on Spigot servers!"); - // No need to go on, it will not work - return; - } - - loadTrackers(); - reloadConfig(); - checkUpdate(getServer().getConsoleSender()); - - if (!trackers.isEmpty()) getCommand("scompass-track").setExecutor(new TrackCommand(this)); - - getCommand("scompass-option").setExecutor(new OptionCommand(this)); - getCommand("scompass").setExecutor(new InterfaceCommand(this)); - - listeners = new Listeners(this); - getServer().getPluginManager().registerEvents(listeners, this); - } - - @Override - public void onLoad() { - super.onLoad(); - - cache = new CacheUtil(this); - } - - @Override - public void reloadConfig() { - super.reloadConfig(); - cache.reset(); - - saveDefaultConfig(); - - isReady = false; - config = getConfig(); - config.options().copyDefaults(true); - locale = new LangUtil(this).getLocale(config.getString("language")); - - for (ConfigUtil.ConfigError error : new ConfigUtil(this).validate(config)) - getLogger().warning(prepareMessage(error.errorKey, error.placeholders)); - - saveConfig(); - - if (compasses != null) compasses.unload(); - - datas = new DataManager(this); - tasks = new TaskManager(this); - targets = new TargetManager(this); - compasses = new CompassManager(this); - - targets.loadTargets(); - compasses.refreshCompassState(); - - isReady = true; - } - - // ---------------------------------------------------------------------------------------------- - // JavaPlugin methods: Basic commands - // ---------------------------------------------------------------------------------------------- - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (command.getName().toLowerCase().equals("scompass-reload")) { - reloadConfig(); - - Iterator it = trackers.keySet().iterator(); - while (it.hasNext()) { - String trackerID = it.next(); - - if (!trackers.get(trackerID).init()) { - it.remove(); - sendMessage(sender, "tracker_disabled", ImmutableMap.of("tracker", trackerID)); - } - } - - sendMessage(sender, "configuration_reloaded"); - checkUpdate(sender); - return true; - } - - return super.onCommand(sender, command, label, args); - } - - // ---------------------------------------------------------------------------------------------- - // Public methods - // ---------------------------------------------------------------------------------------------- - - public TextComponent createClickableMessage(String text, Map> commands) { - TextComponent textComponent = new TextComponent(); - - for (String command : commands.keySet()) text = text.replace(command, "§k" + command + "§r"); - - for (BaseComponent component : TextComponent.fromLegacyText(text)) { - if (component instanceof TextComponent) { - Map command = commands.get(((TextComponent) component).getText().trim()); - - if (command != null) { - if (command.containsKey("text")) ((TextComponent) component).setText("§r" + command.get("text")); - - if (command.containsKey("click")) - component.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, command.get("click"))); - - if (command.containsKey("hover")) - component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - TextComponent.fromLegacyText(command.get("hover")))); - } - } - - textComponent.addExtra(component); - } - - return textComponent; - } - - public String formatMessage(String message) { - return ChatColor.translateAlternateColorCodes('&', message); - } - - public String formatTime(long time) { - String[] parts = DurationFormatUtils.formatDuration(time, "HH:mm:ss").split(":"); - String hour = locale.getString("time_display.hour"); - String minute = locale.getString("time_display.minute"); - String second = locale.getString("time_display.second"); - String human = ""; - - if (time < 60000) { - human = Math.max(Integer.parseInt(parts[2]), 1) + second; - } - else { - if (time >= 3600000) { - human = parts[0] + hour + " "; - } - - human += (time > config.getInt("min_time_to_display_seconds") * 1000) - ? parts[1] + minute + " " + parts[2] + second - : (Integer.parseInt(parts[1]) + 1) + minute; - } - - return human.replaceFirst("^0+(?!$)", ""); - } - - public String githubVersion(String repository) { - String version = (String) cache.versionGet(repository); - if (version != null) return version; - - String url = "https://api.github.com/repos/" + repository + "/releases"; - - try { - HttpURLConnection connexion = (HttpURLConnection) new URL(url).openConnection(); - connexion.addRequestProperty("User-Agent", "SimpleCompass"); - JsonElement element = new JsonParser().parse(new InputStreamReader(connexion.getInputStream())); - - version = element.getAsJsonArray().get(0).getAsJsonObject().get("tag_name").getAsString(); - } - catch (Exception e) {} - - cache.versionSet(repository, version, config.getInt("delays.update_version_cache")); - return version; - } - - public String prepareMessage(String key) { - return prepareMessage(key, null); - } - - public String prepareMessage(String key, Map placeholders) { - String message = locale.getString(key); - - if (placeholders != null) { - for (Iterator i = placeholders.keySet().iterator(); i.hasNext();) { - String placeholder = i.next(); - - message = message.replace("{" + placeholder + "}", placeholders.get(placeholder)); - } - } - - return formatMessage(message.replace("{prefix}", locale.getString("prefix"))); - } - - public void sendMessage(CommandSender sender, String key) { - sendMessage(sender, key, null); - } - - public void sendMessage(CommandSender sender, String key, Map placeholders) { - if (key.isEmpty()) return; - - String message = prepareMessage(key, placeholders); - - if (!message.isEmpty()) sender.sendMessage(message); - } - - // ---------------------------------------------------------------------------------------------- - // Private methods - // ---------------------------------------------------------------------------------------------- - - private void checkUpdate(CommandSender sender) { - if (!config.getBoolean("check_update")) return; - String version = githubVersion("arboriginal/SimpleCompass"); - - if (version == null) - sendMessage(sender, "plugin_check_update_failed"); - else { - String current = getDescription().getVersion(); - if (!version.equals(current)) - sendMessage(sender, "plugin_check_update_available", ImmutableMap.of("version", version, "current", current)); - } - - if (trackers.isEmpty()) return; - trackers.forEach((trackerID, tracker) -> { - tracker.checkUpdate(sender); - }); - } - - private void loadTrackers() { - File dir = new File(getDataFolder(), "trackers"); - if (!dir.exists()) dir.mkdirs(); - - if (!dir.exists() || !dir.isDirectory()) { - getLogger().severe("Unable to create trackers folder..."); - return; - } - - trackers = new HashMap(); - for (final File file : dir.listFiles()) { - if (file.isDirectory() || !file.getName().endsWith(".jar")) continue; - - Exception error = loadTrackerFile(file); - - if (error == null) - getLogger().info("Tracker §6{tracker}§r successfully loaded".replace("{tracker}", file.getName())); - else - getLogger().severe("Error loading tracker " + file.getName() + ": " + error.getMessage()); - } - } - - private Exception loadTrackerException(URLClassLoader loader, JarFile jar, String message) { - if (loader != null) - try { - loader.close(); - } - catch (Exception e) {} - - if (jar != null) - try { - jar.close(); - } - catch (Exception e) {} - - return new Exception(message); - } - - private Exception loadTrackerFile(File file) { - URLClassLoader loader = null; - JarFile jar = null; - - try { - loader = new URLClassLoader(new URL[] { new URL("jar:" + file.toURI().toURL() + "!/") }, getClassLoader()); - } - catch (Exception e) { - return loadTrackerException(loader, jar, "Can't initialize a class loader from " + file.getName()); - } - - Enumeration entries = null; - - try { - jar = new JarFile(file.getAbsolutePath()); - entries = jar.entries(); - } - catch (Exception e) {} - - if (entries == null) - return loadTrackerException(loader, jar, "Can't read content of " + file.getName()); - - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - if (entry.isDirectory() || !entry.getName().endsWith(".class")) continue; - - String className = entry.getName().substring(0, entry.getName().length() - 6).replace('/', '.'); - Object tracker = null; - - try { - tracker = Class.forName(className, true, loader).getConstructor(this.getClass()).newInstance(this); - } - catch (NoClassDefFoundError e) { - return loadTrackerException(loader, jar, "Can't find class " + className + " in " + file.getName() + "..."); - } - catch (Exception e) { - return loadTrackerException(loader, jar, "Can't load class " + className + " from " + file.getName() + "..."); - } - - if (!(tracker instanceof AbstractTracker)) continue; - String trackerID = ((AbstractTracker) tracker).trackerID(); - - if (trackers.containsKey(trackerID)) - return loadTrackerException(loader, jar, - "Tracker {tracker} is using the ID {id} which is already used by {other}..." - .replace("{tracker}", file.getName()).replace("id", trackerID) - .replace("{other}", trackers.get(trackerID).getClass().getSimpleName())); - - if (!((AbstractTracker) tracker).init()) - return loadTrackerException(loader, jar, - "Tracker {tracker} failed on init...".replace("{tracker}", file.getName()).replace("id", trackerID)); - - trackers.put(trackerID, (AbstractTracker) tracker); - loadTrackerException(loader, jar, ""); - return null; - } - - return loadTrackerException(loader, jar, "No tracker found in the jar file..."); - } -} diff --git a/src/me/arboriginal/SimpleCompass/utils/CacheUtil.java b/src/me/arboriginal/SimpleCompass/utils/CacheUtil.java deleted file mode 100644 index 44c6b99..0000000 --- a/src/me/arboriginal/SimpleCompass/utils/CacheUtil.java +++ /dev/null @@ -1,114 +0,0 @@ -package me.arboriginal.SimpleCompass.utils; - -import java.io.File; -import java.util.HashMap; -import java.util.UUID; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public class CacheUtil { - private SimpleCompass sc; - private File vcf; - private FileConfiguration vcc; - private HashMap> datas; - - public static final int PERMANENT = -1; - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public CacheUtil(SimpleCompass plugin) { - sc = plugin; - vcf = new File(sc.getDataFolder(), "versionCache.yml"); - - if (!vcf.exists()) - try { - vcf.createNewFile(); - } - catch (Exception e) { - sc.getLogger().warning("Can't write to version cache file"); - } - - vcc = YamlConfiguration.loadConfiguration(vcf); - reset(); - } - - // ---------------------------------------------------------------------------------------------- - // Static methods - // ---------------------------------------------------------------------------------------------- - - public static long now() { - return System.currentTimeMillis(); - } - - // ---------------------------------------------------------------------------------------------- - // Public methods - // ---------------------------------------------------------------------------------------------- - - public void clear(UUID uid) { - datas.remove(uid); - } - - public void clear(UUID uid, String key) { - datas.get(uid).remove(key); - } - - public Object get(UUID uid, String key) { - if (!datas.containsKey(uid)) return null; - Data data = datas.get(uid).get(key); - return (data != null && (data.expire == PERMANENT || data.expire > now())) ? data.value : null; - } - - public void init(UUID uid) { - datas.put(uid, new HashMap()); - } - - public void reset() { - datas = new HashMap>(); - - for (Player player : sc.getServer().getOnlinePlayers()) init(player.getUniqueId()); - } - - public void set(UUID uid, String key, Object value, int duration) { - if (!datas.containsKey(uid)) init(uid); - datas.get(uid).put(key, new Data((duration == PERMANENT) ? PERMANENT : now() + duration, value)); - } - - // ---------------------------------------------------------------------------------------------- - // Public methods: Version update check cache - // ---------------------------------------------------------------------------------------------- - - public Object versionGet(String key) { - long expire = vcc.getLong("version." + key + ".expire", 0); - return (expire > now()) ? vcc.get("version." + key + ".value", null) : null; - } - - public void versionSet(String key, Object value, int duration) { - vcc.set("version." + key + ".expire", now() + duration * 60000); - vcc.set("version." + key + ".value", value); - - try { - vcc.save(vcf); - } - catch (Exception e) { - sc.getLogger().warning("Can't write to version cache file"); - } - } - - // ---------------------------------------------------------------------------------------------- - // Private classes - // ---------------------------------------------------------------------------------------------- - - private static class Data { - public long expire; - public Object value; - - Data(long expiration, Object datas) { - expire = expiration; - value = datas; - } - } -} diff --git a/src/me/arboriginal/SimpleCompass/utils/ConfigUtil.java b/src/me/arboriginal/SimpleCompass/utils/ConfigUtil.java deleted file mode 100644 index c74ddc1..0000000 --- a/src/me/arboriginal/SimpleCompass/utils/ConfigUtil.java +++ /dev/null @@ -1,268 +0,0 @@ -package me.arboriginal.SimpleCompass.utils; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import org.apache.commons.lang.StringUtils; -import org.bukkit.Material; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.MemoryConfiguration; -import org.bukkit.configuration.file.FileConfiguration; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import me.arboriginal.SimpleCompass.commands.AbstractCommand.CompassOptions; -import me.arboriginal.SimpleCompass.commands.AbstractCommand.SubCmds; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassModes; -import me.arboriginal.SimpleCompass.compasses.AbstractCompass.CompassTypes; -import me.arboriginal.SimpleCompass.managers.CompassManager.RequirementsSections; -import me.arboriginal.SimpleCompass.plugin.AbstractTracker; -import me.arboriginal.SimpleCompass.plugin.AbstractTracker.TrackingActions; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public class ConfigUtil { - private List errors; - private SimpleCompass sc; - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public ConfigUtil(SimpleCompass plugin) { - sc = plugin; - } - - // ---------------------------------------------------------------------------------------------- - // Public methods - // ---------------------------------------------------------------------------------------------- - - public List validate(FileConfiguration configuration) { - clearErrors(); - - List modified = new ArrayList(); - - modified.addAll(validateCustomNames(TrackingActions.values(), "actions")); - modified.addAll(validateCustomNames(SubCmds.values(), "subcommands")); - - if (!modified.isEmpty()) - addError("invalid_names", ImmutableMap.of("modified", String.join(" ,", modified))); - - validateTrackerSettings(); - validateBossbarAttributes(); - - for (CompassTypes type : CompassTypes.values()) { - validateDefaultSettings(type); - - for (CompassModes mode : CompassModes.values()) validateCardinals(type, mode); - - boolean hasRequirements = false; - - for (RequirementsSections section : RequirementsSections.values()) - if (!validateRequiredItems(type, section).isEmpty()) hasRequirements = true; - - if (!hasRequirements) { - fixValue("compass." + type + ".require.items", new MemoryConfiguration()); - fixValue("compass." + type + ".require.consume", false); - } - } - - return errors; - } - - public void clearErrors() { - errors = new ArrayList(); - } - - // ---------------------------------------------------------------------------------------------- - // Private methods - // ---------------------------------------------------------------------------------------------- - - private void addError(String errorKey) { - addError(errorKey, null); - } - - private void addError(String errorKey, Map placeholders) { - errors.add(new ConfigError(errorKey, placeholders)); - } - - private void fixValue(String key) { - fixValue(key, sc.config.getDefaults().get(key)); - } - - private void fixValue(String key, Object value) { - sc.config.set(key, value); - } - - private void validateBossbarAttributes() { - try { - BarColor.valueOf(sc.config.getString("compass.BOSSBAR.attributes.color")); - } - catch (Exception e) { - addError("invalid_bossbar_color"); - fixValue("compass.BOSSBAR.attributes.color"); - } - - try { - BarStyle.valueOf(sc.config.getString("compass.BOSSBAR.attributes.style")); - } - catch (Exception e) { - addError("invalid_bossbar_style"); - fixValue("compass.BOSSBAR.attributes.style"); - } - - ConfigurationSection levels = sc.config - .getConfigurationSection("compass.BOSSBAR.attributes.elytra_durability.levels"); - - if (levels == null) return; - - TreeMap sortedLevel = new TreeMap(); - - for (String level : levels.getKeys(false)) { - try { - BarColor.valueOf(levels.get(level).toString()); - sortedLevel.put(Integer.parseInt(level), levels.get(level).toString()); - } - catch (Exception e) {} - } - - if (levels.getKeys(false).size() != sortedLevel.size()) addError("invalid_bossbar_color_level"); - - fixValue("compass.BOSSBAR.attributes.elytra_durability.levels", sortedLevel); - } - - private void validateCardinals(CompassTypes type, CompassModes mode) { - String key = type + "." + mode; - String fillChar = sc.config.getString("compass." + key + ".cardinals.filling_char"); - - if (fillChar.isEmpty()) return; - - List cardinals = ImmutableList.of("east", "north", "south", "west"); - - int maxLength = 0; - - for (String cardinal : cardinals) - maxLength = Math.max(maxLength, sc.config.getString("compass." + key + ".cardinals." + cardinal).length()); - - for (String cardinal : cardinals) { - String word = sc.config.getString("compass." + key + ".cardinals." + cardinal); - - if (word.length() < maxLength) { - word = StringUtils.repeat(fillChar, (int) Math.floor((double) (maxLength - word.length()) / 2)) + word - + StringUtils.repeat(fillChar, (int) Math.ceil((double) (maxLength - word.length()) / 2)); - - fixValue("compass." + key + ".cardinals." + cardinal, word); - addError("cardinal_length", ImmutableMap.of("key", key, "cardinal", cardinal)); - } - } - } - - private List validateCustomNames(Object[] values, String section) { - List modified = new ArrayList(); - - for (Object obj : values) { - String key = section + "." + obj; - - if (sc.locale.getString(key).contains(" ")) { - sc.locale.getString(sc.locale.getString(key).replaceAll(" ", "")); - modified.add(key); - } - } - - return modified; - } - - private void validateDefaultSettings(CompassTypes type) { - try { - CompassOptions.valueOf(sc.config.getString("compass." + type + ".default.option")); - } - catch (Exception e) { - addError("invalid_choice", ImmutableMap.of("type", "" + type, "key", "option")); - fixValue("compass." + type + ".default.option"); - } - - try { - CompassModes.valueOf(sc.config.getString("compass." + type + ".default.mode")); - } - catch (Exception e) { - addError("invalid_choice", ImmutableMap.of("type", "" + type, "key", "mode")); - fixValue("compass." + type + ".default.mode"); - } - } - - private List validateRequiredItems(CompassTypes type, RequirementsSections section) { - List list = sc.config.getList("compass." + type + ".require.items." + section); - List items = new ArrayList(); - - if (list.size() == 0) return items; - - if (list.contains("AIR")) { - fixValue("compass." + type + ".require.items." + section, items); - - return items; - } - - for (Object item : list) { - try { - Material.valueOf((String) item); - - items.add((String) item); - } - catch (Exception e) {} - } - - if (list.size() > items.size()) { - addError("invalid_items", ImmutableMap.of("section", "" + section, "type", "" + type, - "ignored", "" + (list.size() - items.size()))); - - fixValue("compass." + type + ".require.items." + section, items); - } - - return items; - } - - private void validateTrackerSettings() { - Iterator it = sc.trackers.keySet().iterator(); - while (it.hasNext()) { - String trackerID = it.next(); - - if (!((AbstractTracker) sc.trackers.get(trackerID)).trackerName().toLowerCase().matches("^[a-z0-9]+$")) { - it.remove(); - sc.sendMessage(sc.getServer().getConsoleSender(), "tracker_disabled_invalid_name", - ImmutableMap.of("tracker", trackerID)); - } - } - - List userPriorities = sc.config.getStringList("trackers_priorities"); - List readPriorities = new ArrayList(); - - for (String priority : sc.config.getStringList("trackers_priorities")) { // @formatter:off - if (!sc.trackers.containsKey(priority)) userPriorities.remove(priority); - else if (!readPriorities.contains(priority)) readPriorities.add(priority); - } // @formatter:on - - if (readPriorities.size() != sc.trackers.size()) { - fixValue("trackers_priorities"); - addError("invalid_priorities"); - } - - for (String tracker : sc.trackers.keySet()) if (!userPriorities.contains(tracker)) userPriorities.add(tracker); - fixValue("trackers_priorities", userPriorities); - } - - // ---------------------------------------------------------------------------------------------- - // Private classes - // ---------------------------------------------------------------------------------------------- - - public static class ConfigError { - public final String errorKey; - public final Map placeholders; - - public ConfigError(String k, Map p) { - errorKey = k; - placeholders = p; - } - } -} diff --git a/src/me/arboriginal/SimpleCompass/utils/LangUtil.java b/src/me/arboriginal/SimpleCompass/utils/LangUtil.java deleted file mode 100644 index 7eb7a14..0000000 --- a/src/me/arboriginal/SimpleCompass/utils/LangUtil.java +++ /dev/null @@ -1,120 +0,0 @@ -package me.arboriginal.SimpleCompass.utils; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import com.google.common.base.Charsets; -import me.arboriginal.SimpleCompass.plugin.SimpleCompass; - -public class LangUtil { - private SimpleCompass sc; - - // ---------------------------------------------------------------------------------------------- - // Constructor methods - // ---------------------------------------------------------------------------------------------- - - public LangUtil(SimpleCompass plugin) { - sc = plugin; - } - - // ---------------------------------------------------------------------------------------------- - // Public static methods - // ---------------------------------------------------------------------------------------------- - - public static void writeResourceToFile(InputStream in, File file) throws Exception { - file.getParentFile().mkdirs(); - - OutputStream out = new FileOutputStream(file); - byte[] buf = new byte[1024]; - int len; - - while ((len = in.read(buf)) > 0) out.write(buf, 0, len); - - out.close(); - in.close(); - } - - // ---------------------------------------------------------------------------------------------- - // Public methods - // ---------------------------------------------------------------------------------------------- - - public FileConfiguration getLocale(String language) { - FileConfiguration locale; - boolean newFile; - - String langRes = "lang/" + language + ".yml"; - String langRdef = "lang/en.yml"; - File langFile = new File(sc.getDataFolder(), langRes); - - if (newFile = !langFile.exists()) { - String logMsg = null; - - sc.getLogger().warning("Lang file for « " + language + " » doesn't exist."); - - if (sc.getResource(langRes) != null) { - logMsg = "Lang file for « " + language + " » copied from plugin."; - } - else { - sc.getLogger().warning("Lang « " + language + " » doesn't exist in the plugin either."); - - try { - writeResourceToFile(langRdef, langFile); - - logMsg = "A new lang file for « " + language + " » has been generated, based on english."; - langRes = null; - } - catch (Exception e) { - sc.getLogger().severe("Lang file for « " + language + " » cannot be generated."); - - logMsg = "Fallback to default lang file."; - langRes = langRdef; - } - } - - copyResourceToFile(langRes, langFile); - sc.getLogger().info(logMsg); - } - - locale = YamlConfiguration.loadConfiguration(langFile); - - if (!newFile) saveConfigToFile(locale, langFile, langRdef); - - return locale; - } - - // ---------------------------------------------------------------------------------------------- - // Private methods - // ---------------------------------------------------------------------------------------------- - - private void copyResourceToFile(String resource, File file) { - if (resource != null) { - sc.saveResource(resource, false); - - file = new File(sc.getDataFolder(), resource); - } - } - - private void saveConfigToFile(FileConfiguration config, File file, String defaultRes) { - config.setDefaults(YamlConfiguration.loadConfiguration( - new InputStreamReader(sc.getResource(defaultRes), Charsets.UTF_8))); - // This ensure sentences added in next versions are stored in the file with their default values - config.options().copyDefaults(true); - - try { - config.save(file); - } - catch (Exception e) { - sc.getLogger().warning("The language file cannot be updated in your plugin folder. " - + "You need to check by yourself if you didn't missed some sentences you want to translate. " - + "Default language will be used for them."); - } - } - - private void writeResourceToFile(String resource, File file) throws Exception { - writeResourceToFile(sc.getResource(resource), file); - } -} diff --git a/src/me/arboriginal/SimpleCompass/utils/NMSUtil.java b/src/me/arboriginal/SimpleCompass/utils/NMSUtil.java deleted file mode 100644 index c50b642..0000000 --- a/src/me/arboriginal/SimpleCompass/utils/NMSUtil.java +++ /dev/null @@ -1,73 +0,0 @@ -package me.arboriginal.SimpleCompass.utils; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -public final class NMSUtil { - // ---------------------------------------------------------------------------------------------- - // Public methods - // ---------------------------------------------------------------------------------------------- - - public static boolean openBook(Player player, ItemStack book) { - int heldSlot = player.getInventory().getHeldItemSlot(); - ItemStack current = player.getInventory().getItem(heldSlot); - boolean success = false; - - player.getInventory().setItem(heldSlot, book); - - try { - Object key = getClass("MinecraftKey").getConstructor(String.class).newInstance("minecraft:book_open"); - - success = sendPacket(player, getClass("PacketPlayOutCustomPayload") - .getConstructor(key.getClass(), getClass("PacketDataSerializer")) - .newInstance(key, getClass("PacketDataSerializer").getConstructor(ByteBuf.class) - .newInstance(Unpooled.buffer(256).setByte(0, (byte) 0).writerIndex(1)))); - } - catch (Exception e1_13) { - try { - Object key = "MC|BOpen"; - - success = sendPacket(player, getClass("PacketPlayOutCustomPayload") - .getConstructor(key.getClass(), getClass("PacketDataSerializer")) - .newInstance(key, getClass("PacketDataSerializer").getConstructor(ByteBuf.class) - .newInstance(Unpooled.buffer(256).setByte(0, (byte) 0).writerIndex(1)))); - } - catch (Exception e1_12) {} - } - - player.getInventory().setItem(heldSlot, current); - - return success; - } - - // ---------------------------------------------------------------------------------------------- - // Private methods - // ---------------------------------------------------------------------------------------------- - - private static Class getClass(String name) { - try { - return Class.forName("net.minecraft.server." + - Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3] + "." + name); - } - catch (Exception e) {} - - return null; - } - - private static boolean sendPacket(Player player, Object packet) { - try { - Object handle = player.getClass().getMethod("getHandle").invoke(player); - Object target = handle.getClass().getField("playerConnection").get(handle); - - target.getClass().getMethod("sendPacket", getClass("Packet")).invoke(target, packet); - - return true; - } - catch (Exception e) {} - - return false; - } -}