Implemented the command management classes (inspired from CommandTools).

* NEW: Added command management classes.
* NEW: Added an unfinished implementation of /maptool new.
* NEW: Added the shortcut command /tomap (alias of /maptool new).
This commit is contained in:
Prokopyl 2015-03-18 01:49:30 +01:00
parent e4bd514a6e
commit 7a8ec83d6a
9 changed files with 838 additions and 0 deletions

View File

@ -18,6 +18,7 @@
package fr.moribus.imageonmap;
import fr.moribus.imageonmap.commands.Commands;
import fr.moribus.imageonmap.image.ImageIOExecutor;
import fr.moribus.imageonmap.image.MapInitEvent;
import java.io.File;
@ -63,6 +64,7 @@ public final class ImageOnMap extends JavaPlugin
MetricsLite.startMetrics();
ImageIOExecutor.start();
Commands.init(this);
getServer().getPluginManager().registerEvents(new MapInitEvent(), this);
}

View File

@ -0,0 +1,210 @@
/*
* Copyright (C) 2013 Moribus
* Copyright (C) 2015 ProkopyL <prokopylmc@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.moribus.imageonmap.commands;
import fr.moribus.imageonmap.commands.CommandException.Reason;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
abstract public class Command
{
protected final Commands commandGroup;
protected final String commandName;
protected final String usageParameters;
protected final String commandDescription;
protected CommandSender sender;
protected String[] args;
abstract protected void run() throws CommandException;
public Command(Commands commandGroup)
{
this.commandGroup = commandGroup;
CommandInfo commandInfo = this.getClass().getAnnotation(CommandInfo.class);
if(commandInfo == null)
throw new IllegalArgumentException("Command has no CommandInfo annotation");
commandName = commandInfo.name().toLowerCase();
usageParameters = commandInfo.usageParameters();
commandDescription = commandGroup.getDescription(commandName);
}
public boolean canExecute(CommandSender sender)
{
return sender.hasPermission("commandtools." + commandGroup.getUsualName());
}
protected List<String> complete() throws CommandException
{
return null;
}
public void execute(CommandSender sender, String[] args)
{
this.sender = sender; this.args = args;
try
{
if(!canExecute(sender))
throw new CommandException(this, Reason.SENDER_NOT_AUTHORIZED);
run();
}
catch(CommandException ex)
{
warning(ex.getReasonString());
}
this.sender = null; this.args = null;
}
public List<String> tabComplete(CommandSender sender, String[] args)
{
List<String> result = null;
this.sender = sender; this.args = args;
try
{
if(canExecute(sender))
result = complete();
}
catch(CommandException ex){}
this.sender = null; this.args = null;
if(result == null) result = new ArrayList<String>();
return result;
}
public String getUsageString()
{
return "/" + commandGroup.getUsualName() + " " + commandName + " " + usageParameters;
}
public String getName()
{
return commandName;
}
public Commands getCommandGroup()
{
return commandGroup;
}
public boolean matches(String name)
{
return commandName.equals(name.toLowerCase());
}
///////////// Common methods for commands /////////////
protected void throwInvalidArgument(String reason) throws CommandException
{
throw new CommandException(this, Reason.INVALID_PARAMETERS, reason);
}
protected Player playerSender() throws CommandException
{
if(!(sender instanceof Player))
throw new CommandException(this, Reason.COMMANDSENDER_EXPECTED_PLAYER);
return (Player)sender;
}
///////////// Methods for command execution /////////////
protected void info(String message)
{
sender.sendMessage("§7" + message);
}
protected void warning(String message)
{
sender.sendMessage("§c" + message);
}
protected void error(String message) throws CommandException
{
throw new CommandException(this, Reason.COMMAND_ERROR, message);
}
protected void tellRaw(String rawMessage) throws CommandException
{
Player player = playerSender();
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(),
"tellraw " + player.getName() + " " + rawMessage);
}
///////////// Methods for autocompletion /////////////
protected List<String> getMatchingSubset(String prefix, String... list)
{
return getMatchingSubset(Arrays.asList(list), prefix);
}
protected List<String> getMatchingSubset(Iterable<? extends String> list, String prefix)
{
List<String> matches = new ArrayList<String>();
for(String item : list)
{
if(item.startsWith(prefix)) matches.add(item);
}
return matches;
}
protected List<String> getMatchingPlayerNames(String prefix)
{
return getMatchingPlayerNames(Bukkit.getOnlinePlayers(), prefix);
}
protected List<String> getMatchingPlayerNames(Iterable<? extends Player> players, String prefix)
{
List<String> matches = new ArrayList<String>();
for(Player player : players)
{
if(player.getName().startsWith(prefix)) matches.add(player.getName());
}
return matches;
}
/*protected List<String> getMatchingToolNames(Player player, String prefix)
{
return getMatchingToolNames(ToolManager.getToolList(player.getUniqueId()), prefix);
}
protected List<String> getMatchingToolNames(Iterable<? extends CommandTool> tools, String prefix)
{
List<String> matches = new ArrayList<String>();
for(CommandTool tool : tools)
{
if(tool.getId().startsWith(prefix)) matches.add(tool.getId());
}
return matches;
}*/
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2013 Moribus
* Copyright (C) 2015 ProkopyL <prokopylmc@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.moribus.imageonmap.commands;
public class CommandException extends Exception
{
public enum Reason
{
COMMANDSENDER_EXPECTED_PLAYER,
INVALID_PARAMETERS,
COMMAND_ERROR,
SENDER_NOT_AUTHORIZED
}
private final Reason reason;
private final Command command;
private final String extra;
public CommandException(Command command, Reason reason, String extra)
{
this.command = command;
this.reason = reason;
this.extra = extra;
}
public CommandException(Command command, Reason reason)
{
this(command, reason, "");
}
public Reason getReason() { return reason; }
public String getReasonString()
{
switch(reason)
{
case COMMANDSENDER_EXPECTED_PLAYER:
return "You must be a player to use this command.";
case INVALID_PARAMETERS:
return "Invalid arguments : " + extra +"\n§r" +
"Usage : " + command.getUsageString() + "\n" +
"For more information, use /" +
command.getCommandGroup().getUsualName() + " help " +
command.getName();
case COMMAND_ERROR:
return extra.isEmpty() ? "An unknown error suddenly happened." : extra;
case SENDER_NOT_AUTHORIZED:
return "You do not have the permission to use this command.";
default:
return "An unknown error suddenly happened.";
}
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2013 Moribus
* Copyright (C) 2015 ProkopyL <prokopylmc@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.moribus.imageonmap.commands;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface CommandInfo
{
String name();
String usageParameters() default "";
}

View File

@ -0,0 +1,326 @@
/*
* Copyright (C) 2013 Moribus
* Copyright (C) 2015 ProkopyL <prokopylmc@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.moribus.imageonmap.commands;
import fr.moribus.imageonmap.PluginLogger;
import fr.moribus.imageonmap.commands.maptool.*;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.commons.lang.StringUtils;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.plugin.java.JavaPlugin;
/**
*
* @author Prokopyl<prokopylmc@gmail.com>
*/
public enum Commands implements TabCompleter, CommandExecutor
{
MAPTOOL(new String[]{"maptool"},
NewCommand.class),
TOMAP(MAPTOOL, NewCommand.class, "tomap");
static private final Commands[] commandGroups = Commands.class.getEnumConstants();
private final Commands shortcutCommandGroup;
private final String[] names;
private final Class<? extends Command>[] commandsClasses;
private final ArrayList<Command> commands = new ArrayList<>();
private final HashMap<String, String> commandsDescriptions = new HashMap<>();
private String description = "";
private Commands(Commands shortcutCommandGroup, Class<? extends Command> commandClass, String ... names)
{
this.names = names;
this.commandsClasses = new Class[]{commandClass};
this.shortcutCommandGroup = shortcutCommandGroup;
initCommands();
}
private Commands(String[] names, Class<? extends Command> ... commandsClasses)
{
this.names = names;
this.commandsClasses = commandsClasses;
this.shortcutCommandGroup = null;
initDescriptions();
initCommands();
}
private void initDescriptions()
{
String fileName = "help/" + getUsualName() + ".txt";
InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName);
if(stream == null)
{
PluginLogger.LogWarning("Could not load description file for the " + getUsualName() + " command");
return;
}
Scanner scanner = new Scanner(stream);
StringBuilder builder = new StringBuilder();
//Getting the group's description
//And then each command's description
int colonIndex, firstSpaceIndex;
boolean isGroupDescription = true;
while (scanner.hasNextLine())
{
String line = scanner.nextLine();
colonIndex = line.indexOf(':');
if(isGroupDescription)
{
firstSpaceIndex = line.indexOf(' ');
if(colonIndex > 0 && firstSpaceIndex > colonIndex)
isGroupDescription = false;
}
if(isGroupDescription)
{
builder.append(line).append('\n');
}
else
{
commandsDescriptions.put(line.substring(0, colonIndex).trim(),
line.substring(colonIndex + 1).trim());
}
}
scanner.close();
description = builder.toString().trim();
}
private void initCommands()
{
for (Class<? extends Command> commandClass : commandsClasses)
{
addCommand(commandClass);
}
if(!isShortcutCommand()) addCommand(HelpCommand.class);
}
private void addCommand(Class<? extends Command> commandClass)
{
Constructor<? extends Command> constructor;
try
{
constructor = commandClass.getConstructor(Commands.class);
commands.add(constructor.newInstance(isShortcutCommand() ? shortcutCommandGroup : this));
}
catch (Exception ex)
{
PluginLogger.LogWarning("Exception while initializing command", ex);
}
}
public boolean executeMatchingCommand(CommandSender sender, String[] args)
{
if(isShortcutCommand())
{
commands.get(0).execute(sender, args);
return true;
}
if(args.length <= 0)
{
sender.sendMessage(getUsage()); return false;
}
String commandName = args[0];
String[] commandArgs = getCommandArgsFromGroupArgs(args);
return executeMatchingCommand(sender, commandName, commandArgs);
}
private boolean executeMatchingCommand(CommandSender sender, String commandName, String[] args)
{
Command command = getMatchingCommand(commandName);
if(command != null)
{
command.execute(sender, args);
}
else
{
sender.sendMessage(getUsage());
}
return command != null;
}
static public void init(JavaPlugin plugin)
{
org.bukkit.command.PluginCommand bukkitCommand;
for(Commands commandGroup : commandGroups)
{
bukkitCommand = plugin.getCommand(commandGroup.getUsualName());
bukkitCommand.setAliases(commandGroup.getAliases());
bukkitCommand.setExecutor(commandGroup);
bukkitCommand.setTabCompleter(commandGroup);
}
}
@Override
public List<String> onTabComplete(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args)
{
return tabComplete(sender, args);
}
@Override
public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args)
{
return executeMatchingCommand(sender, args);
}
public List<String> tabComplete(CommandSender sender, String[] args)
{
if(isShortcutCommand()) return commands.get(0).tabComplete(sender, args);
if(args.length <= 1) return tabComplete(sender, args.length == 1 ? args[0] : null);
String commandName = args[0];
String[] commandArgs = getCommandArgsFromGroupArgs(args);
return tabCompleteMatching(sender, commandName, commandArgs);
}
public List<String> tabComplete(CommandSender sender, String commandName)
{
ArrayList<String> matchingCommands = new ArrayList<String>();
for(Command command : commands)
{
if(!command.canExecute(sender)) continue;
if(commandName == null || command.getName().startsWith(commandName.toLowerCase()))
{
matchingCommands.add(command.getName());
}
}
return matchingCommands;
}
private List<String> tabCompleteMatching(CommandSender sender, String commandName, String[] args)
{
Command command = getMatchingCommand(commandName);
if(command != null)
{
return command.tabComplete(sender, args);
}
else
{
return new ArrayList<String>();
}
}
static public String[] getCommandArgsFromGroupArgs(String[] args)
{
String[] commandArgs = new String[args.length - 1];
for(int i = 0; i < commandArgs.length; i++)
{
commandArgs[i] = args[i + 1];
}
return commandArgs;
}
public Command getMatchingCommand(String commandName)
{
for(Command command : commands)
{
if(command.matches(commandName))
{
return command;
}
}
return null;
}
static public boolean execute(CommandSender sender, String commandName, String[] args)
{
Commands commandGroup = getMatchingCommandGroup(commandName);
if(commandGroup == null) return false;
commandGroup.executeMatchingCommand(sender, args);
return true;
}
static public List<String> tabComplete(CommandSender sender, String commandName, String[] args)
{
Commands commandGroup = getMatchingCommandGroup(commandName);
if(commandGroup == null) return new ArrayList<String>();
return commandGroup.tabComplete(sender, args);
}
static private Commands getMatchingCommandGroup(String commandName)
{
Commands commandGroup = null;
for(Commands tCommandGroup : commandGroups)
{
if(tCommandGroup.matches(commandName))
{
commandGroup = tCommandGroup;
break;
}
}
return commandGroup;
}
public boolean matches(String name)
{
name = name.toLowerCase();
for(String commandName : names)
{
if(commandName.equals(name)) return true;
}
return false;
}
public String[] getCommandsNames()
{
String[] commandsNames = new String[commands.size()];
for(int i = 0; i < commands.size(); i++)
{
commandsNames[i] = commands.get(i).getName();
}
return commandsNames;
}
protected String getUsage()
{
if(isShortcutCommand()) return "§cUsage : " + commands.get(0).getUsageString();
return "§cUsage : /" + getUsualName() +
" <" + StringUtils.join(getCommandsNames(), "|") + ">";
}
public String getUsualName() { return names[0]; }
public String[] getNames() { return names.clone(); }
public List<String> getAliases() { return Arrays.asList(names).subList(1, names.length);}
public Command[] getCommands() { return commands.toArray(new Command[commands.size()]);}
public String getDescription() { return description; }
public String getDescription(String commandName) { return commandsDescriptions.get(commandName); }
public boolean isShortcutCommand() { return shortcutCommandGroup != null; }
public Commands getShortcutCommandGroup() { return shortcutCommandGroup; }
}

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2013 Moribus
* Copyright (C) 2015 ProkopyL <prokopylmc@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.moribus.imageonmap.commands;
import fr.moribus.imageonmap.PluginLogger;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
@CommandInfo(name = "help", usageParameters = "<command name>")
public class HelpCommand extends Command
{
public HelpCommand(Commands commandGroup) {
super(commandGroup);
}
@Override
protected void run() throws CommandException
{
if(args.length < 1)
groupHelp();
else
commandHelp();
}
private void groupHelp() throws CommandException
{
sender.sendMessage(commandGroup.getDescription());
String tCommandName;
String tDescription;
for(Command tCommand: commandGroup.getCommands())
{
if(!tCommand.canExecute(sender)) continue;
tCommandName = tCommand.getName();
tDescription = commandGroup.getDescription(tCommandName);
tCommandName = commandGroup.getUsualName() + " " + tCommandName;
if(tDescription == null)
sender.sendMessage("§6/" + tCommandName + "§r");
else
sender.sendMessage("§6/" + tCommandName + " : §r" + tDescription);
}
}
private void commandHelp() throws CommandException
{
Command command = commandGroup.getMatchingCommand(args[0]);
if(command == null)
{
error("The specified command does not exist.");
return;
}
if(!command.canExecute(sender))
warning("You do not have the permission to use this command.");
sender.sendMessage("§l§6 ||== ImageOnMap help ==||\n" +
"§l§6 |Usage : §r" + command.getUsageString());
try
{
String help = getHelpText(command);
if(help.isEmpty())
{
warning("There is no help message for this command.");
}
else
{
sender.sendMessage(help);
}
}
catch(IOException ex)
{
warning("Could not read help for this command.");
PluginLogger.LogWarning("Could not read help for the command : " + command.getName(), ex);
}
}
private String getHelpText(Command command) throws IOException
{
String fileName = "help/"+ commandGroup.getUsualName() +
"/" + command.getName() + ".txt";
StringBuilder result = new StringBuilder("");
InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName);
if(stream == null) return "";
Scanner scanner = new Scanner(stream);
while (scanner.hasNextLine())
{
String line = scanner.nextLine();
result.append("§l§9 |§r").append(line).append("\n");
}
scanner.close();
return result.toString().trim();
}
@Override
protected List<String> complete() throws CommandException
{
if(args.length != 1) return null;
ArrayList<String> matches = new ArrayList<String>();
for(Command command : commandGroup.getCommands())
{
if(command.getName().startsWith(args[0]))
matches.add(command.getName());
}
return matches;
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2013 Moribus
* Copyright (C) 2015 ProkopyL <prokopylmc@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.moribus.imageonmap.commands.maptool;
import fr.moribus.imageonmap.commands.Command;
import fr.moribus.imageonmap.commands.CommandException;
import fr.moribus.imageonmap.commands.CommandInfo;
import fr.moribus.imageonmap.commands.Commands;
import java.net.MalformedURLException;
import java.net.URL;
import org.bukkit.entity.Player;
@CommandInfo(name = "new", usageParameters = "<URL> [resize]")
public class NewCommand extends Command
{
public NewCommand(Commands commandGroup) {
super(commandGroup);
}
@Override
protected void run() throws CommandException
{
Player player = playerSender();
URL url;
if(args.length < 1) throwInvalidArgument("You must give an URL to take the image from.");
try
{
url = new URL(args[0]);
}
catch(MalformedURLException ex)
{
throwInvalidArgument("Invalid URL.");
}
if(args.length < 2)
{
}
info("Not implemented.");
}
}

View File

@ -0,0 +1,2 @@
This command manages and creates ImagesOnMaps.
new: Creates a new ImageOnMap.

View File

@ -0,0 +1 @@
Creates a new ImageOnMap.