Merge commit '2af8c8dbf2d5eb16d7492fd12b4b786d6205d0f9' as 'lib'

This commit is contained in:
Charlie 2014-07-31 11:37:54 -04:00
commit 778c3f4043
46 changed files with 3570 additions and 0 deletions

8
lib/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Maven
target/
# Java
*.class
*.jar
*.war
*.ear

227
lib/LICENSE.txt Normal file
View File

@ -0,0 +1,227 @@
WorldEdit License
-----------------
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
JNBT License
------------
Copyright (c) 2010 Graham Edgecombe
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the JNBT team nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
JChronic License
----------------
The MIT License
Copyright (c) 2009 Mike Schrag, Sam Tingleff
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

10
lib/NOTICE.txt Normal file
View File

@ -0,0 +1,10 @@
This product includes software from JNBT (http://jnbt.sourceforge.net/).
This product includes software from WorldEdit
(http://www.sk89q.com), under GNU Lesser General Public License, version 3.
This product includes software from JOpt Simple, under the MIT license.
This product includes software by toi.
This product includes software from JChronic, under the MIT license.

18
lib/README.md Normal file
View File

@ -0,0 +1,18 @@
sk89q-command-framework
=======================
sk89q-command-framework is the command framework from sk89q's WorldEdit. It has been factored out so it may be used in other projects without having to include WorldEdit as a dependency.
Compiling
---------
You need to have Maven installed (http://maven.apache.org). Once installed, simply run:
mvn clean install
Maven will automatically download dependencies for you. Note: For that to work, be sure to add Maven to your "PATH".
Contributing
------------
Your submissions have to be licensed under the GNU General Public License v3.

58
lib/bukkit/pom.xml Normal file
View File

@ -0,0 +1,58 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.sk89q</groupId>
<artifactId>command-framework-parent</artifactId>
<version>0.5-SNAPSHOT</version>
</parent>
<artifactId>command-framework-bukkit</artifactId>
<packaging>jar</packaging>
<version>0.5-SNAPSHOT</version>
<name>Sk89q Command Framework for Bukkit</name>
<description>Supporting classes for running the command framework on Bukkit servers.</description>
<repositories>
<repository>
<id>bukkit-repo</id>
<url>http://repo.bukkit.org/content/groups/public</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>command-framework-core</artifactId>
<version>0.5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.4.7-R1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<configuration>
<artifactSet>
<includes>
<include>com.sk89q:command-framework-core</include>
</includes>
</artifactSet>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,12 @@
package com.sk89q.bukkit.util;
import org.bukkit.command.CommandSender;
import com.sk89q.minecraft.util.commands.CommandsManager;
public class BukkitCommandsManager extends CommandsManager<CommandSender> {
@Override
public boolean hasPermission(CommandSender player, String perm) {
return player.hasPermission(perm);
}
}

View File

@ -0,0 +1,54 @@
package com.sk89q.bukkit.util;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import com.sk89q.minecraft.util.commands.WrappedCommandSender;
public class BukkitWrappedCommandSender implements WrappedCommandSender {
public BukkitWrappedCommandSender(CommandSender wrapped) {
this.wrapped = wrapped;
}
@Override
public String getName() {
return this.getName();
}
@Override
public void sendMessage(String message) {
this.wrapped.sendMessage(message);
}
@Override
public void sendMessage(String[] messages) {
this.wrapped.sendMessage(messages);
}
@Override
public boolean hasPermission(String permission) {
return this.wrapped.hasPermission(permission);
}
@Override
public Type getType() {
if (this.wrapped instanceof ConsoleCommandSender) {
return Type.CONSOLE;
} else if (this.wrapped instanceof Player) {
return Type.PLAYER;
} else if (this.wrapped instanceof BlockCommandSender) {
return Type.BLOCK;
} else {
return Type.UNKNOWN;
}
}
@Override
public Object getCommandSender() {
return this.wrapped;
}
private final CommandSender wrapped;
}

View File

@ -0,0 +1,65 @@
/*
* WorldEdit
* Copyright (C) 2012 sk89q <http://www.sk89q.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 com.sk89q.bukkit.util;
/**
* @author zml2008
*/
public class CommandInfo {
private final String[] aliases;
private final Object registeredWith;
private final String usage, desc;
private final String[] permissions;
public CommandInfo(String usage, String desc, String[] aliases, Object registeredWith) {
this(usage, desc, aliases, registeredWith, null);
}
public CommandInfo(String usage, String desc, String[] aliases, Object registeredWith, String[] permissions) {
this.usage = usage;
this.desc = desc;
this.aliases = aliases;
this.permissions = permissions;
this.registeredWith = registeredWith;
}
public String[] getAliases() {
return aliases;
}
public String getName() {
return aliases[0];
}
public String getUsage() {
return usage;
}
public String getDesc() {
return desc;
}
public String[] getPermissions() {
return permissions;
}
public Object getRegisteredWith() {
return registeredWith;
}
}

View File

@ -0,0 +1,112 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2011 sk89q <http://www.sk89q.com> and contributors
*
* 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 com.sk89q.bukkit.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sk89q.util.ReflectionUtil;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandMap;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.plugin.Plugin;
/**
* @author zml2008
*/
public class CommandRegistration {
static {
Bukkit.getServer().getHelpMap().registerHelpTopicFactory(DynamicPluginCommand.class, new DynamicPluginCommandHelpTopic.Factory());
}
protected final Plugin plugin;
protected final CommandExecutor executor;
private CommandMap fallbackCommands;
public CommandRegistration(Plugin plugin) {
this(plugin, plugin);
}
public CommandRegistration(Plugin plugin, CommandExecutor executor) {
this.plugin = plugin;
this.executor = executor;
}
public boolean register(List<CommandInfo> registered) {
CommandMap commandMap = getCommandMap();
if (registered == null || commandMap == null) {
return false;
}
for (CommandInfo command : registered) {
DynamicPluginCommand cmd = new DynamicPluginCommand(command.getAliases(),
command.getDesc(), "/" + command.getAliases()[0] + " " + command.getUsage(), executor, command.getRegisteredWith(), plugin);
cmd.setPermissions(command.getPermissions());
commandMap.register(plugin.getDescription().getName(), cmd);
}
return true;
}
public CommandMap getCommandMap() {
CommandMap commandMap = ReflectionUtil.getField(plugin.getServer().getPluginManager(), "commandMap");
if (commandMap == null) {
if (fallbackCommands != null) {
commandMap = fallbackCommands;
} else {
Bukkit.getServer().getLogger().severe(plugin.getDescription().getName() +
": Could not retrieve server CommandMap, using fallback instead! Please report to http://redmine.sk89q.com");
fallbackCommands = commandMap = new SimpleCommandMap(Bukkit.getServer());
Bukkit.getServer().getPluginManager().registerEvents(new FallbackRegistrationListener(fallbackCommands), plugin);
}
}
return commandMap;
}
public boolean unregisterCommands() {
CommandMap commandMap = getCommandMap();
List<String> toRemove = new ArrayList<String>();
Map<String, org.bukkit.command.Command> knownCommands = ReflectionUtil.getField(commandMap, "knownCommands");
Set<String> aliases = ReflectionUtil.getField(commandMap, "aliases");
if (knownCommands == null || aliases == null) {
return false;
}
for (Iterator<org.bukkit.command.Command> i = knownCommands.values().iterator(); i.hasNext();) {
org.bukkit.command.Command cmd = i.next();
if (cmd instanceof DynamicPluginCommand && ((DynamicPluginCommand) cmd).getOwner().equals(executor)) {
i.remove();
for (String alias : cmd.getAliases()) {
org.bukkit.command.Command aliasCmd = knownCommands.get(alias);
if (cmd.equals(aliasCmd)) {
aliases.remove(alias);
toRemove.add(alias);
}
}
}
}
for (String string : toRemove) {
knownCommands.remove(string);
}
return true;
}
}

View File

@ -0,0 +1,66 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2011 sk89q <http://www.sk89q.com> and contributors
*
* 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 com.sk89q.bukkit.util;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.CommandsManager;
import org.bukkit.command.CommandExecutor;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @author zml2008
*/
public class CommandsManagerRegistration extends CommandRegistration {
protected CommandsManager<?> commands;
public CommandsManagerRegistration(Plugin plugin, CommandsManager<?> commands) {
super(plugin);
this.commands = commands;
}
public CommandsManagerRegistration(Plugin plugin, CommandExecutor executor, CommandsManager<?> commands) {
super(plugin, executor);
this.commands = commands;
}
public boolean register(Class<?> clazz) {
return registerAll(commands.registerAndReturn(clazz));
}
public boolean registerAll(List<Command> registered) {
List<CommandInfo> toRegister = new ArrayList<CommandInfo>();
for (Command command : registered) {
String[] permissions = null;
Method cmdMethod = commands.getMethods().get(null).get(command.aliases()[0]);
if (cmdMethod != null && cmdMethod.isAnnotationPresent(CommandPermissions.class)) {
permissions = cmdMethod.getAnnotation(CommandPermissions.class).value();
}
toRegister.add(new CommandInfo(command.usage(), command.desc(), command.aliases(), commands, permissions));
}
return register(toRegister);
}
}

View File

@ -0,0 +1,98 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2011 sk89q <http://www.sk89q.com> and contributors
*
* 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 com.sk89q.bukkit.util;
import com.sk89q.minecraft.util.commands.CommandsManager;
import com.sk89q.util.StringUtil;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.plugin.Plugin;
import java.util.Arrays;
/**
* @author zml2008
*/
public class DynamicPluginCommand extends org.bukkit.command.Command implements PluginIdentifiableCommand {
protected final CommandExecutor owner;
protected final Object registeredWith;
protected final Plugin owningPlugin;
protected String[] permissions = new String[0];
public DynamicPluginCommand(String[] aliases, String desc, String usage, CommandExecutor owner, Object registeredWith, Plugin plugin) {
super(aliases[0], desc, usage, Arrays.asList(aliases));
this.owner = owner;
this.owningPlugin = plugin;
this.registeredWith = registeredWith;
}
@Override
public boolean execute(CommandSender sender, String label, String[] args) {
return owner.onCommand(sender, this, label, args);
}
public Object getOwner() {
return owner;
}
public Object getRegisteredWith() {
return registeredWith;
}
public void setPermissions(String[] permissions) {
this.permissions = permissions;
if (permissions != null) {
super.setPermission(StringUtil.joinString(permissions, ";"));
}
}
public String[] getPermissions() {
return permissions;
}
@Override
public Plugin getPlugin() {
return owningPlugin;
}
@SuppressWarnings("unchecked")
@Override
public boolean testPermissionSilent(CommandSender sender) {
if (permissions == null || permissions.length == 0) {
return true;
}
if (registeredWith instanceof CommandsManager<?>) {
try {
for (String permission : permissions) {
if (((CommandsManager<CommandSender>) registeredWith).hasPermission(sender, permission)) {
return true;
}
}
return false;
} catch (Throwable ignore) {
}
}
return super.testPermissionSilent(sender);
}
}

View File

@ -0,0 +1,126 @@
/*
* WorldEdit
* Copyright (C) 2012 sk89q <http://www.sk89q.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 com.sk89q.bukkit.util;
import com.sk89q.minecraft.util.commands.CommandsManager;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.help.HelpTopic;
import org.bukkit.help.HelpTopicFactory;
import java.util.Map;
/**
* @author zml2008
*/
public class DynamicPluginCommandHelpTopic extends HelpTopic {
private final DynamicPluginCommand cmd;
public DynamicPluginCommandHelpTopic(DynamicPluginCommand cmd) {
this.cmd = cmd;
this.name = "/" + cmd.getName();
String fullTextTemp = null;
StringBuilder fullText = new StringBuilder();
if (cmd.getRegisteredWith() instanceof CommandsManager) {
Map<String, String> helpText = ((CommandsManager<?>) cmd.getRegisteredWith()).getHelpMessages();
final String lookupName = cmd.getName().replaceAll("/", "");
if (helpText.containsKey(lookupName)) { // We have full help text for this command
fullTextTemp = helpText.get(lookupName);
}
// No full help text, assemble help text from info
helpText = ((CommandsManager<?>) cmd.getRegisteredWith()).getCommands();
if (helpText.containsKey(cmd.getName())) {
final String shortText = helpText.get(cmd.getName());
if (fullTextTemp == null) {
fullTextTemp = this.name + " " + shortText;
}
this.shortText = shortText;
}
} else {
this.shortText = cmd.getDescription();
}
// Put the usage in the format: Usage string (newline) Aliases (newline) Help text
String[] split = fullTextTemp == null ? new String[2] : fullTextTemp.split("\n", 2);
fullText.append(ChatColor.BOLD).append(ChatColor.GOLD).append("Usage: ").append(ChatColor.WHITE);
fullText.append(split[0]).append("\n");
if (cmd.getAliases().size() > 0) {
fullText.append(ChatColor.BOLD).append(ChatColor.GOLD).append("Aliases: ").append(ChatColor.WHITE);
boolean first = true;
for (String alias : cmd.getAliases()) {
if (!first) {
fullText.append(", ");
}
fullText.append(alias);
first = false;
}
fullText.append("\n");
}
if (split.length > 1) {
fullText.append(split[1]);
}
this.fullText = fullText.toString();
}
@Override
@SuppressWarnings("unchecked")
public boolean canSee(CommandSender player) {
if (cmd.getPermissions() != null && cmd.getPermissions().length > 0) {
if (cmd.getRegisteredWith() instanceof CommandsManager) {
try {
for (String perm : cmd.getPermissions()) {
if (((CommandsManager<Object>) cmd.getRegisteredWith()).hasPermission(player, perm)) {
return true;
}
}
} catch (Throwable t) {
// Doesn't take the CommandSender (Hooray for compile-time generics!), we have other methods at our disposal
}
}
for (String perm : cmd.getPermissions()) {
if (player.hasPermission(perm)) {
return true;
}
}
return false;
}
return true;
}
@Override
public String getFullText(CommandSender forWho) {
if (this.fullText == null || this.fullText.length() == 0) {
return getShortText();
} else {
return this.fullText;
}
}
public static class Factory implements HelpTopicFactory<DynamicPluginCommand> {
@Override
public HelpTopic createTopic(DynamicPluginCommand command) {
return new DynamicPluginCommandHelpTopic(command);
}
}
}

View File

@ -0,0 +1,44 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2011 sk89q <http://www.sk89q.com> and contributors
*
* 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 com.sk89q.bukkit.util;
import org.bukkit.command.CommandMap;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
/**
* @author zml2008
*/
public class FallbackRegistrationListener implements Listener {
private final CommandMap commandRegistration;
public FallbackRegistrationListener(CommandMap commandRegistration) {
this.commandRegistration = commandRegistration;
}
@EventHandler(ignoreCancelled = true)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
if (commandRegistration.dispatch(event.getPlayer(), event.getMessage())) {
event.setCancelled(true);
}
}
}

58
lib/bungee/pom.xml Normal file
View File

@ -0,0 +1,58 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.sk89q</groupId>
<artifactId>command-framework-parent</artifactId>
<version>0.5-SNAPSHOT</version>
</parent>
<artifactId>command-framework-bungee</artifactId>
<packaging>jar</packaging>
<version>0.5-SNAPSHOT</version>
<name>Sk89q Command Framework for BungeeCord</name>
<description>Supporting classes for using the command framework on BungeeCord.</description>
<repositories>
<repository>
<id>sonatype-public</id>
<url>https://oss.sonatype.org/content/groups/public</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>command-framework-core</artifactId>
<version>0.5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.5-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<configuration>
<artifactSet>
<includes>
<include>com.sk89q:command-framework-core</include>
</includes>
</artifactSet>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,12 @@
package com.sk89q.bungee.util;
import net.md_5.bungee.api.CommandSender;
import com.sk89q.minecraft.util.commands.CommandsManager;
public class BungeeCommandsManager extends CommandsManager<CommandSender> {
@Override
public boolean hasPermission(CommandSender player, String perm) {
return player.hasPermission(perm);
}
}

View File

@ -0,0 +1,47 @@
package com.sk89q.bungee.util;
import net.md_5.bungee.api.CommandSender;
import com.sk89q.minecraft.util.commands.WrappedCommandSender;
public class BungeeWrappedCommandSender implements WrappedCommandSender {
public BungeeWrappedCommandSender(CommandSender wrapped) {
this.wrapped = wrapped;
}
@Override
public String getName() {
return this.wrapped.getName();
}
@Override
public void sendMessage(String message) {
this.wrapped.sendMessage(message);
}
@Override
public void sendMessage(String[] messages) {
this.wrapped.sendMessages(messages);
}
@Override
public boolean hasPermission(String permission) {
return this.wrapped.hasPermission(permission);
}
@Override
public Type getType() {
if (this.wrapped.getName().equals("CONSOLE")) { // hack because Bungee does not export ConsoleCommandSender
return Type.CONSOLE;
} else {
return Type.PLAYER;
}
}
@Override
public Object getCommandSender() {
return this.wrapped;
}
private final CommandSender wrapped;
}

View File

@ -0,0 +1,6 @@
package com.sk89q.bungee.util;
public interface CommandExecutor<T> {
void onCommand(T sender, String commandName, String[] args);
}

View File

@ -0,0 +1,36 @@
package com.sk89q.bungee.util;
import java.util.List;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginManager;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandsManager;
public class CommandRegistration {
public CommandRegistration(Plugin plugin, PluginManager pluginManager, CommandsManager<?> commands, CommandExecutor<CommandSender> executor) {
this.plugin = plugin;
this.pluginManager = pluginManager;
this.commands = commands;
this.executor = executor;
}
public boolean register(Class<?> clazz) {
return this.registerAll(this.commands.registerAndReturn(clazz));
}
public boolean registerAll(List<Command> registered) {
for(Command command : registered) {
CommandWrapper wrapper = new CommandWrapper(this.executor, command.aliases()[0], command.aliases());
this.pluginManager.registerCommand(this.plugin, wrapper);
}
return true;
}
private final Plugin plugin;
private final PluginManager pluginManager;
private final CommandsManager<?> commands;
private final CommandExecutor<CommandSender> executor;
}

View File

@ -0,0 +1,18 @@
package com.sk89q.bungee.util;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
public class CommandWrapper extends Command {
public CommandWrapper(CommandExecutor<CommandSender> executor, String commandName, String... aliases) {
super(commandName, null, aliases);
this.executor = executor;
}
@Override
public void execute(CommandSender sender, String[] args) {
this.executor.onCommand(sender, this.getName(), args);
}
private final CommandExecutor<CommandSender> executor;
}

13
lib/core/pom.xml Normal file
View File

@ -0,0 +1,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.sk89q</groupId>
<artifactId>command-framework-parent</artifactId>
<version>0.5-SNAPSHOT</version>
</parent>
<artifactId>command-framework-core</artifactId>
<packaging>jar</packaging>
<version>0.5-SNAPSHOT</version>
<name>Sk89q Command Framework Core</name>
<description>Core classes for the sk89q command framework.</description>
</project>

View File

@ -0,0 +1,252 @@
package com.sk89q.minecraft.util.commands;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* All supported color values for chat
*
* Class provided as part of the Bukkit project with slight modifications to
* reduce dependencies.
*
* @see https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/ChatColor.java
*/
public enum ChatColor {
/**
* Represents black
*/
BLACK('0', 0x00),
/**
* Represents dark blue
*/
DARK_BLUE('1', 0x1),
/**
* Represents dark green
*/
DARK_GREEN('2', 0x2),
/**
* Represents dark blue (aqua)
*/
DARK_AQUA('3', 0x3),
/**
* Represents dark red
*/
DARK_RED('4', 0x4),
/**
* Represents dark purple
*/
DARK_PURPLE('5', 0x5),
/**
* Represents gold
*/
GOLD('6', 0x6),
/**
* Represents gray
*/
GRAY('7', 0x7),
/**
* Represents dark gray
*/
DARK_GRAY('8', 0x8),
/**
* Represents blue
*/
BLUE('9', 0x9),
/**
* Represents green
*/
GREEN('a', 0xA),
/**
* Represents aqua
*/
AQUA('b', 0xB),
/**
* Represents red
*/
RED('c', 0xC),
/**
* Represents light purple
*/
LIGHT_PURPLE('d', 0xD),
/**
* Represents yellow
*/
YELLOW('e', 0xE),
/**
* Represents white
*/
WHITE('f', 0xF),
/**
* Represents magical characters that change around randomly
*/
MAGIC('k', 0x10, true),
/**
* Makes the text bold.
*/
BOLD('l', 0x11, true),
/**
* Makes a line appear through the text.
*/
STRIKETHROUGH('m', 0x12, true),
/**
* Makes the text appear underlined.
*/
UNDERLINE('n', 0x13, true),
/**
* Makes the text italic.
*/
ITALIC('o', 0x14, true),
/**
* Resets all previous chat colors or formats.
*/
RESET('r', 0x15);
/**
* The special character which prefixes all chat colour codes. Use this if you need to dynamically
* convert colour codes from your custom format.
*/
public static final char COLOR_CHAR = '\u00A7';
private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]");
private final int intCode;
private final char code;
private final boolean isFormat;
private final String toString;
private final static Map<Integer, ChatColor> BY_ID = new HashMap<Integer, ChatColor>();
private final static Map<Character, ChatColor> BY_CHAR = new HashMap<Character, ChatColor>();
private ChatColor(char code, int intCode) {
this(code, intCode, false);
}
private ChatColor(char code, int intCode, boolean isFormat) {
this.code = code;
this.intCode = intCode;
this.isFormat = isFormat;
this.toString = new String(new char[] {COLOR_CHAR, code});
}
/**
* Gets the char value associated with this color
*
* @return A char value of this color code
*/
public char getChar() {
return this.code;
}
@Override
public String toString() {
return this.toString;
}
/**
* Checks if this code is a format code as opposed to a color code.
*/
public boolean isFormat() {
return this.isFormat;
}
/**
* Checks if this code is a color code as opposed to a format code.
*/
public boolean isColor() {
return !this.isFormat && this != RESET;
}
/**
* Gets the color represented by the specified color code
*
* @param code Code to check
* @return Associative {@link org.bukkit.ChatColor} with the given code, or null if it doesn't exist
*/
public static ChatColor getByChar(char code) {
return BY_CHAR.get(code);
}
/**
* Gets the color represented by the specified color code
*
* @param code Code to check
* @return Associative {@link org.bukkit.ChatColor} with the given code, or null if it doesn't exist
*/
public static ChatColor getByChar(String code) {
if (code == null) throw new NullPointerException("Code cannot be null");
if (code.isEmpty()) throw new IllegalArgumentException("Code must have at least one char");
return BY_CHAR.get(code.charAt(0));
}
/**
* Strips the given message of all color codes
*
* @param input String to strip of color
* @return A copy of the input string, without any coloring
*/
public static String stripColor(final String input) {
if (input == null) {
return null;
}
return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
}
/**
* Translates a string using an alternate color code character into a string that uses the internal
* ChatColor.COLOR_CODE color code character. The alternate color code character will only be replaced
* if it is immediately followed by 0-9, A-F, a-f, K-O, k-o, R or r.
*
* @param altColorChar The alternate color code character to replace. Ex: &
* @param textToTranslate Text containing the alternate color code character.
* @return Text containing the ChatColor.COLOR_CODE color code character.
*/
public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
char[] b = textToTranslate.toCharArray();
for (int i = 0; i < b.length - 1; i++) {
if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i+1]) > -1) {
b[i] = ChatColor.COLOR_CHAR;
b[i+1] = Character.toLowerCase(b[i+1]);
}
}
return new String(b);
}
/**
* Gets the ChatColors used at the end of the given input string.
*
* @param input Input string to retrieve the colors from.
* @return Any remaining ChatColors to pass onto the next line.
*/
public static String getLastColors(String input) {
String result = "";
int length = input.length();
// Search backwards from the end as it is faster
for (int index = length - 1; index > -1; index--) {
char section = input.charAt(index);
if (section == COLOR_CHAR && index < length - 1) {
char c = input.charAt(index + 1);
ChatColor color = getByChar(c);
if (color != null) {
result = color.toString() + result;
// Once we find a color or reset we can stop searching
if (color.isColor() || color.equals(RESET)) {
break;
}
}
}
}
return result;
}
static {
for (ChatColor color : values()) {
BY_ID.put(color.intCode, color);
BY_CHAR.put(color.code, color);
}
}
}

View File

@ -0,0 +1,93 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* This annotation indicates a command. Methods should be marked with this
* annotation to tell {@link CommandsManager} that the method is a command.
* Note that the method name can actually be anything.
*
* @author sk89q
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Command {
/**
* A list of aliases for the command. The first alias is the most
* important -- it is the main name of the command. (The method name
* is never used for anything).
*
* @return Aliases for a command
*/
String[] aliases();
/**
* Usage instruction. Example text for usage could be
* <code>[-h harps] [name] [message]</code>.
*
* @return Usage instructions for a command
*/
String usage() default "";
/**
* @return A short description for the command.
*/
String desc();
/**
* The minimum number of arguments. This should be 0 or above.
*
* @return the minimum number of arguments
*/
int min() default 0;
/**
* The maximum number of arguments. Use -1 for an unlimited number
* of arguments.
*
* @return the maximum number of arguments
*/
int max() default -1;
/**
* Flags allow special processing for flags such as -h in the command,
* allowing users to easily turn on a flag. This is a string with
* each character being a flag. Use A-Z and a-z as possible flags.
* Appending a flag with a : makes the flag character before a value flag,
* meaning that if it is given it must have a value
*
* @return Flags matching a-zA-Z
*/
String flags() default "";
/**
* @return A long description for the command.
*/
String help() default "";
/**
*
*
* @return Whether any flag can be provided to the command, even if it is not in {@link #flags()}
*/
boolean anyFlags() default false;
}

View File

@ -0,0 +1,41 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Any command with this annotation will run the raw command as shown in the
* thing, as long as it is registered in the current {@link CommandsManager}.
* Mostly to move commands around without breaking things.
*
* @author zml2008
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandAlias {
/**
*
* @return Raw {@link CommandsManager}-formatted command arg array to run
*/
String[] value();
}

View File

@ -0,0 +1,338 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class CommandContext {
protected final String command;
protected final List<String> parsedArgs;
protected final List<Integer> originalArgIndices;
protected final String[] originalArgs;
protected final Set<Character> booleanFlags = new HashSet<Character>();
protected final Map<Character, String> valueFlags = new HashMap<Character, String>();
protected final SuggestionContext suggestionContext;
protected final CommandLocals locals;
public static String[] split(String args) {
return args.split(" ", -1);
}
public CommandContext(String args) throws CommandException {
this(args.split(" ", -1), null);
}
public CommandContext(String[] args) throws CommandException {
this(args, null);
}
public CommandContext(String args, Set<Character> valueFlags) throws CommandException {
this(args.split(" ", -1), valueFlags);
}
public CommandContext(String args, Set<Character> valueFlags, boolean allowHangingFlag)
throws CommandException {
this(args.split(" ", -1), valueFlags, allowHangingFlag, new CommandLocals());
}
public CommandContext(String[] args, Set<Character> valueFlags) throws CommandException {
this(args, valueFlags, false, null);
}
/**
* Parse the given array of arguments.
*
* <p>Empty arguments are removed from the list of arguments.</p>
*
* @param args an array with arguments
* @param valueFlags a set containing all value flags (pass null to disable value flag parsing)
* @param allowHangingFlag true if hanging flags are allowed
* @param locals the locals, null to create empty one
* @throws CommandException thrown on a parsing error
*/
public CommandContext(String[] args, Set<Character> valueFlags,
boolean allowHangingFlag, CommandLocals locals) throws CommandException {
if (valueFlags == null) {
valueFlags = Collections.emptySet();
}
originalArgs = args;
command = args[0];
this.locals = locals != null ? locals : new CommandLocals();
boolean isHanging = false;
SuggestionContext suggestionContext = SuggestionContext.hangingValue();
// Eliminate empty args and combine multiword args first
List<Integer> argIndexList = new ArrayList<Integer>(args.length);
List<String> argList = new ArrayList<String>(args.length);
for (int i = 1; i < args.length; ++i) {
isHanging = false;
String arg = args[i];
if (arg.length() == 0) {
isHanging = true;
continue;
}
argIndexList.add(i);
switch (arg.charAt(0)) {
case '\'':
case '"':
final StringBuilder build = new StringBuilder();
final char quotedChar = arg.charAt(0);
int endIndex;
for (endIndex = i; endIndex < args.length; ++endIndex) {
final String arg2 = args[endIndex];
if (arg2.charAt(arg2.length() - 1) == quotedChar && arg2.length() > 1) {
if (endIndex != i) build.append(' ');
build.append(arg2.substring(endIndex == i ? 1 : 0, arg2.length() - 1));
break;
} else if (endIndex == i) {
build.append(arg2.substring(1));
} else {
build.append(' ').append(arg2);
}
}
if (endIndex < args.length) {
arg = build.toString();
i = endIndex;
}
// In case there is an empty quoted string
if (arg.length() == 0) {
continue;
}
// else raise exception about hanging quotes?
}
argList.add(arg);
}
// Then flags
this.originalArgIndices = new ArrayList<Integer>(argIndexList.size());
this.parsedArgs = new ArrayList<String>(argList.size());
for (int nextArg = 0; nextArg < argList.size(); ) {
// Fetch argument
String arg = argList.get(nextArg++);
suggestionContext = SuggestionContext.hangingValue();
// Not a flag?
if (arg.charAt(0) != '-' || arg.length() == 1 || !arg.matches("^-[a-zA-Z]+$")) {
if (!isHanging) {
suggestionContext = SuggestionContext.lastValue();
}
originalArgIndices.add(argIndexList.get(nextArg - 1));
parsedArgs.add(arg);
continue;
}
// Handle flag parsing terminator --
if (arg.equals("--")) {
while (nextArg < argList.size()) {
originalArgIndices.add(argIndexList.get(nextArg));
parsedArgs.add(argList.get(nextArg++));
}
break;
}
// Go through the flag characters
for (int i = 1; i < arg.length(); ++i) {
char flagName = arg.charAt(i);
if (valueFlags.contains(flagName)) {
if (this.valueFlags.containsKey(flagName)) {
throw new CommandException("Value flag '" + flagName + "' already given");
}
if (nextArg >= argList.size()) {
if (allowHangingFlag) {
suggestionContext = SuggestionContext.flag(flagName);
break;
} else {
throw new CommandException("No value specified for the '-" + flagName + "' flag.");
}
}
// If it is a value flag, read another argument and add it
this.valueFlags.put(flagName, argList.get(nextArg++));
if (!isHanging) {
suggestionContext = SuggestionContext.flag(flagName);
}
} else {
booleanFlags.add(flagName);
}
}
}
this.suggestionContext = suggestionContext;
}
public SuggestionContext getSuggestionContext() {
return suggestionContext;
}
public String getCommand() {
return command;
}
public boolean matches(String command) {
return this.command.equalsIgnoreCase(command);
}
public String getString(int index) {
return parsedArgs.get(index);
}
public String getString(int index, String def) {
return index < parsedArgs.size() ? parsedArgs.get(index) : def;
}
public String getJoinedStrings(int initialIndex) {
initialIndex = originalArgIndices.get(initialIndex);
StringBuilder buffer = new StringBuilder(originalArgs[initialIndex]);
for (int i = initialIndex + 1; i < originalArgs.length; ++i) {
buffer.append(" ").append(originalArgs[i]);
}
return buffer.toString();
}
public String getRemainingString(int start) {
return getString(start, parsedArgs.size() - 1);
}
public String getString(int start, int end) {
StringBuilder buffer = new StringBuilder(parsedArgs.get(start));
for (int i = start + 1; i < end + 1; ++i) {
buffer.append(" ").append(parsedArgs.get(i));
}
return buffer.toString();
}
public int getInteger(int index) throws NumberFormatException {
return Integer.parseInt(parsedArgs.get(index));
}
public int getInteger(int index, int def) throws NumberFormatException {
return index < parsedArgs.size() ? Integer.parseInt(parsedArgs.get(index)) : def;
}
public double getDouble(int index) throws NumberFormatException {
return Double.parseDouble(parsedArgs.get(index));
}
public double getDouble(int index, double def) throws NumberFormatException {
return index < parsedArgs.size() ? Double.parseDouble(parsedArgs.get(index)) : def;
}
public String[] getSlice(int index) {
String[] slice = new String[originalArgs.length - index];
System.arraycopy(originalArgs, index, slice, 0, originalArgs.length - index);
return slice;
}
public String[] getPaddedSlice(int index, int padding) {
String[] slice = new String[originalArgs.length - index + padding];
System.arraycopy(originalArgs, index, slice, padding, originalArgs.length - index);
return slice;
}
public String[] getParsedSlice(int index) {
String[] slice = new String[parsedArgs.size() - index];
System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, 0, parsedArgs.size() - index);
return slice;
}
public String[] getParsedPaddedSlice(int index, int padding) {
String[] slice = new String[parsedArgs.size() - index + padding];
System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, padding, parsedArgs.size() - index);
return slice;
}
public boolean hasFlag(char ch) {
return booleanFlags.contains(ch) || valueFlags.containsKey(ch);
}
public Set<Character> getFlags() {
return booleanFlags;
}
public Map<Character, String> getValueFlags() {
return valueFlags;
}
public String getFlag(char ch) {
return valueFlags.get(ch);
}
public String getFlag(char ch, String def) {
final String value = valueFlags.get(ch);
if (value == null) {
return def;
}
return value;
}
public int getFlagInteger(char ch) throws NumberFormatException {
return Integer.parseInt(valueFlags.get(ch));
}
public int getFlagInteger(char ch, int def) throws NumberFormatException {
final String value = valueFlags.get(ch);
if (value == null) {
return def;
}
return Integer.parseInt(value);
}
public double getFlagDouble(char ch) throws NumberFormatException {
return Double.parseDouble(valueFlags.get(ch));
}
public double getFlagDouble(char ch, double def) throws NumberFormatException {
final String value = valueFlags.get(ch);
if (value == null) {
return def;
}
return Double.parseDouble(value);
}
public int argsLength() {
return parsedArgs.size();
}
public CommandLocals getLocals() {
return locals;
}
}

View File

@ -0,0 +1,72 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class CommandException extends Exception {
private static final long serialVersionUID = 870638193072101739L;
private List<String> commandStack = new ArrayList<String>();
public CommandException() {
super();
}
public CommandException(String message) {
super(message);
}
public CommandException(String message, Throwable t) {
super(message, t);
}
public CommandException(Throwable t) {
super(t);
}
public void prependStack(String name) {
commandStack.add(name);
}
public String toStackString(String prefix, String spacedSuffix) {
StringBuilder builder = new StringBuilder();
if (prefix != null) {
builder.append(prefix);
}
ListIterator<String> li = commandStack.listIterator(commandStack.size());
while (li.hasPrevious()) {
if (li.previousIndex() != commandStack.size() - 1) {
builder.append(" ");
}
builder.append(li.previous());
}
if (spacedSuffix != null) {
if (builder.length() > 0) {
builder.append(" ");
}
builder.append(spacedSuffix);
}
return builder.toString();
}
}

View File

@ -0,0 +1,50 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.util.HashMap;
import java.util.Map;
public class CommandLocals {
private final Map<Object, Object> locals = new HashMap<Object, Object>();
public boolean containsKey(Object key) {
return locals.containsKey(key);
}
public boolean containsValue(Object value) {
return locals.containsValue(value);
}
public Object get(Object key) {
return locals.get(key);
}
@SuppressWarnings("unchecked")
public <T> T get(Class<T> key) {
return (T) locals.get(key);
}
public Object put(Object key, Object value) {
return locals.put(key, value);
}
}

View File

@ -0,0 +1,37 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Indicates a list of permissions that should be checked.
*
* @author sk89q
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandPermissions {
/**
* A list of permissions. Only one permission has to be met
* for the command to be permitted.
*/
String[] value();
}

View File

@ -0,0 +1,29 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
/**
* Thrown when not enough permissions are satisfied.
*
* @author sk89q
*/
public class CommandPermissionsException extends CommandException {
private static final long serialVersionUID = -602374621030168291L;
}

View File

@ -0,0 +1,35 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
public class CommandUsageException extends CommandException {
private static final long serialVersionUID = -6761418114414516542L;
protected String usage;
public CommandUsageException(String message, String usage) {
super(message);
this.usage = usage;
}
public String getUsage() {
return usage;
}
}

View File

@ -0,0 +1,594 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sk89q.util.StringUtil;
/**
* <p>Manager for handling commands. This allows you to easily process commands,
* including nested commands, by correctly annotating methods of a class.</p>
*
* <p>To use this, it is merely a matter of registering classes containing
* the commands (as methods with the proper annotations) with the
* manager. When you want to process a command, use one of the
* <code>execute</code> methods. If something is wrong, such as incorrect
* usage, insufficient permissions, or a missing command altogether, an
* exception will be raised for upstream handling.</p>
*
* <p>Methods of a class to be registered can be static, but if an injector
* is registered with the class, the instances of the command classes
* will be created automatically and methods will be called non-statically.</p>
*
* <p>To mark a method as a command, use {@link Command}. For nested commands,
* see {@link NestedCommand}. To handle permissions, use
* {@link CommandPermissions}.</p>
*
* <p>This uses Java reflection extensively, but to reduce the overhead of
* reflection, command lookups are completely cached on registration. This
* allows for fast command handling. Method invocation still has to be done
* with reflection, but this is quite fast in that of itself.</p>
*
* @author sk89q
* @param <T> command sender class
*/
public abstract class CommandsManager<T> {
/**
* Logger for general errors.
*/
protected static final Logger logger =
Logger.getLogger(CommandsManager.class.getCanonicalName());
/**
* Mapping of commands (including aliases) with a description. Root
* commands are stored under a key of null, whereas child commands are
* cached under their respective {@link Method}. The child map has
* the key of the command name (one for each alias) with the
* method.
*/
protected Map<Method, Map<String, Method>> commands = new HashMap<Method, Map<String, Method>>();
/**
* Used to store the instances associated with a method.
*/
protected Map<Method, Object> instances = new HashMap<Method, Object>();
/**
* Mapping of commands (not including aliases) with a description. This
* is only for top level commands.
*/
protected Map<String, String> descs = new HashMap<String, String>();
/**
* Stores the injector used to getInstance.
*/
protected Injector injector;
/**
* Mapping of commands (not including aliases) with a description. This
* is only for top level commands.
*/
protected Map<String, String> helpMessages = new HashMap<String, String>();
/**
* Register an class that contains commands (denoted by {@link Command}.
* If no dependency injector is specified, then the methods of the
* class will be registered to be called statically. Otherwise, new
* instances will be created of the command classes and methods will
* not be called statically.
*
* @param cls
*/
public void register(Class<?> cls) {
registerMethods(cls, null);
}
/**
* Register an class that contains commands (denoted by {@link Command}.
* If no dependency injector is specified, then the methods of the
* class will be registered to be called statically. Otherwise, new
* instances will be created of the command classes and methods will
* not be called statically. A List of {@link Command} annotations from
* registered commands is returned.
*
* @param cls
* @return A List of {@link Command} annotations from registered commands,
* for use in eg. a dynamic command registration system.
*/
public List<Command> registerAndReturn(Class<?> cls) {
return registerMethods(cls, null);
}
/**
* Register the methods of a class. This will automatically construct
* instances as necessary.
*
* @param cls
* @param parent
* @return Commands Registered
*/
public List<Command> registerMethods(Class<?> cls, Method parent) {
try {
if (getInjector() == null) {
return registerMethods(cls, parent, null);
} else {
Object obj = getInjector().getInstance(cls);
return registerMethods(cls, parent, obj);
}
} catch (InvocationTargetException e) {
logger.log(Level.SEVERE, "Failed to register commands", e);
} catch (IllegalAccessException e) {
logger.log(Level.SEVERE, "Failed to register commands", e);
} catch (InstantiationException e) {
logger.log(Level.SEVERE, "Failed to register commands", e);
}
return null;
}
/**
* Register the methods of a class.
*
* @param cls
* @param parent
* @param obj
* @return
*/
private List<Command> registerMethods(Class<?> cls, Method parent, Object obj) {
Map<String, Method> map;
List<Command> registered = new ArrayList<Command>();
// Make a new hash map to cache the commands for this class
// as looking up methods via reflection is fairly slow
if (commands.containsKey(parent)) {
map = commands.get(parent);
} else {
map = new HashMap<String, Method>();
commands.put(parent, map);
}
for (Method method : cls.getMethods()) {
if (!method.isAnnotationPresent(Command.class)) {
continue;
}
boolean isStatic = Modifier.isStatic(method.getModifiers());
Command cmd = method.getAnnotation(Command.class);
// Cache the aliases too
for (String alias : cmd.aliases()) {
map.put(alias, method);
}
// We want to be able invoke with an instance
if (!isStatic) {
// Can't register this command if we don't have an instance
if (obj == null) {
continue;
}
instances.put(method, obj);
}
// Build a list of commands and their usage details, at least for
// root level commands
if (parent == null) {
final String commandName = cmd.aliases()[0];
final String desc = cmd.desc();
final String usage = cmd.usage();
if (usage.length() == 0) {
descs.put(commandName, desc);
} else {
descs.put(commandName, usage + " - " + desc);
}
String help = cmd.help();
if (help.length() == 0) {
help = desc;
}
final CharSequence arguments = getArguments(cmd);
for (String alias : cmd.aliases()) {
final String helpMessage = "/" + alias + " " + arguments + "\n\n" + help;
final String key = alias.replaceAll("/", "");
String previous = helpMessages.put(key, helpMessage);
if (previous != null && !previous.replaceAll("^/[^ ]+ ", "").equals(helpMessage.replaceAll("^/[^ ]+ ", ""))) {
helpMessages.put(key, previous + "\n\n" + helpMessage);
}
}
}
// Add the command to the registered command list for return
registered.add(cmd);
// Look for nested commands -- if there are any, those have
// to be cached too so that they can be quickly looked
// up when processing commands
if (method.isAnnotationPresent(NestedCommand.class)) {
NestedCommand nestedCmd = method.getAnnotation(NestedCommand.class);
for (Class<?> nestedCls : nestedCmd.value()) {
registerMethods(nestedCls, method);
}
}
}
if (cls.getSuperclass() != null) {
registerMethods(cls.getSuperclass(), parent, obj);
}
return registered;
}
/**
* Checks to see whether there is a command named such at the root level.
* This will check aliases as well.
*
* @param command
* @return
*/
public boolean hasCommand(String command) {
return commands.get(null).containsKey(command.toLowerCase());
}
/**
* Get a list of command descriptions. This is only for root commands.
*
* @return
*/
public Map<String, String> getCommands() {
return descs;
}
public Map<Method, Map<String, Method>> getMethods() {
return commands;
}
/**
* Get a map from command name to help message. This is only for root commands.
*
* @return
*/
public Map<String, String> getHelpMessages() {
return helpMessages;
}
/**
* Get the usage string for a command.
*
* @param args
* @param level
* @param cmd
* @return
*/
protected String getUsage(String[] args, int level, Command cmd) {
final StringBuilder command = new StringBuilder();
command.append('/');
for (int i = 0; i <= level; ++i) {
command.append(args[i]);
command.append(' ');
}
command.append(getArguments(cmd));
final String help = cmd.help();
if (help.length() > 0) {
command.append("\n\n");
command.append(help);
}
return command.toString();
}
protected CharSequence getArguments(Command cmd) {
final String flags = cmd.flags();
final StringBuilder command2 = new StringBuilder();
if (flags.length() > 0) {
String flagString = flags.replaceAll(".:", "");
if (flagString.length() > 0) {
command2.append("[-");
for (int i = 0; i < flagString.length(); ++i) {
command2.append(flagString.charAt(i));
}
command2.append("] ");
}
}
command2.append(cmd.usage());
return command2;
}
/**
* Get the usage string for a nested command.
*
* @param args
* @param level
* @param method
* @param player
* @return
* @throws CommandException
*/
protected String getNestedUsage(String[] args, int level,
Method method, T player) throws CommandException {
StringBuilder command = new StringBuilder();
command.append("/");
for (int i = 0; i <= level; ++i) {
command.append(args[i] + " ");
}
Map<String, Method> map = commands.get(method);
boolean found = false;
command.append("<");
Set<String> allowedCommands = new HashSet<String>();
for (Map.Entry<String, Method> entry : map.entrySet()) {
Method childMethod = entry.getValue();
found = true;
if (hasPermission(childMethod, player)) {
Command childCmd = childMethod.getAnnotation(Command.class);
allowedCommands.add(childCmd.aliases()[0]);
}
}
if (allowedCommands.size() > 0) {
command.append(StringUtil.joinString(allowedCommands, "|", 0));
} else {
if (!found) {
command.append("?");
} else {
//command.append("action");
throw new CommandPermissionsException();
}
}
command.append(">");
return command.toString();
}
/**
* Attempt to execute a command. This version takes a separate command
* name (for the root command) and then a list of following arguments.
*
* @param cmd command to run
* @param args arguments
* @param player command source
* @param methodArgs method arguments
* @throws CommandException
*/
public void execute(String cmd, String[] args, T player,
Object... methodArgs) throws CommandException {
String[] newArgs = new String[args.length + 1];
System.arraycopy(args, 0, newArgs, 1, args.length);
newArgs[0] = cmd;
Object[] newMethodArgs = new Object[methodArgs.length + 1];
System.arraycopy(methodArgs, 0, newMethodArgs, 1, methodArgs.length);
executeMethod(null, newArgs, player, newMethodArgs, 0);
}
/**
* Attempt to execute a command.
*
* @param args
* @param player
* @param methodArgs
* @throws CommandException
*/
public void execute(String[] args, T player,
Object... methodArgs) throws CommandException {
Object[] newMethodArgs = new Object[methodArgs.length + 1];
System.arraycopy(methodArgs, 0, newMethodArgs, 1, methodArgs.length);
executeMethod(null, args, player, newMethodArgs, 0);
}
/**
* Attempt to execute a command.
*
* @param parent
* @param args
* @param player
* @param methodArgs
* @param level
* @throws CommandException
*/
public void executeMethod(Method parent, String[] args,
T player, Object[] methodArgs, int level) throws CommandException {
String cmdName = args[level];
Map<String, Method> map = commands.get(parent);
Method method = map.get(cmdName.toLowerCase());
if (method == null) {
if (parent == null) { // Root
throw new UnhandledCommandException();
} else {
throw new MissingNestedCommandException("Unknown command: " + cmdName,
getNestedUsage(args, level - 1, parent, player));
}
}
checkPermission(player, method);
int argsCount = args.length - 1 - level;
// checks if we need to execute the body of the nested command method (false)
// or display the help what commands are available (true)
// this is all for an args count of 0 if it is > 0 and a NestedCommand Annotation is present
// it will always handle the methods that NestedCommand points to
// e.g.:
// - /cmd - @NestedCommand(executeBody = true) will go into the else loop and execute code in that method
// - /cmd <arg1> <arg2> - @NestedCommand(executeBody = true) will always go to the nested command class
// - /cmd <arg1> - @NestedCommand(executeBody = false) will always go to the nested command class not matter the args
boolean executeNested = method.isAnnotationPresent(NestedCommand.class)
&& (argsCount > 0 || !method.getAnnotation(NestedCommand.class).executeBody());
if (executeNested) {
if (argsCount == 0) {
throw new MissingNestedCommandException("Sub-command required.",
getNestedUsage(args, level, method, player));
} else {
executeMethod(method, args, player, methodArgs, level + 1);
}
} else if (method.isAnnotationPresent(CommandAlias.class)) {
CommandAlias aCmd = method.getAnnotation(CommandAlias.class);
executeMethod(parent, aCmd.value(), player, methodArgs, level);
} else {
Command cmd = method.getAnnotation(Command.class);
String[] newArgs = new String[args.length - level];
System.arraycopy(args, level, newArgs, 0, args.length - level);
final Set<Character> valueFlags = new HashSet<Character>();
char[] flags = cmd.flags().toCharArray();
Set<Character> newFlags = new HashSet<Character>();
for (int i = 0; i < flags.length; ++i) {
if (flags.length > i + 1 && flags[i + 1] == ':') {
valueFlags.add(flags[i]);
++i;
}
newFlags.add(flags[i]);
}
CommandContext context = new CommandContext(newArgs, valueFlags);
if (context.argsLength() < cmd.min()) {
throw new CommandUsageException("Too few arguments.", getUsage(args, level, cmd));
}
if (cmd.max() != -1 && context.argsLength() > cmd.max()) {
throw new CommandUsageException("Too many arguments.", getUsage(args, level, cmd));
}
if (!cmd.anyFlags()) {
for (char flag : context.getFlags()) {
if (!newFlags.contains(flag)) {
throw new CommandUsageException("Unknown flag: " + flag, getUsage(args, level, cmd));
}
}
}
methodArgs[0] = context;
Object instance = instances.get(method);
invokeMethod(parent, args, player, method, instance, methodArgs, argsCount);
}
}
protected void checkPermission(T player, Method method) throws CommandException {
if (!hasPermission(method, player)) {
throw new CommandPermissionsException();
}
}
public void invokeMethod(Method parent, String[] args, T player, Method method,
Object instance, Object[] methodArgs, int level) throws CommandException {
try {
method.invoke(instance, methodArgs);
} catch (IllegalArgumentException e) {
logger.log(Level.SEVERE, "Failed to execute command", e);
} catch (IllegalAccessException e) {
logger.log(Level.SEVERE, "Failed to execute command", e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof CommandException) {
throw (CommandException) e.getCause();
}
throw new WrappedCommandException(e.getCause());
}
}
/**
* Returns whether a player has access to a command.
*
* @param method
* @param player
* @return
*/
protected boolean hasPermission(Method method, T player) {
CommandPermissions perms = method.getAnnotation(CommandPermissions.class);
if (perms == null) {
return true;
}
for (String perm : perms.value()) {
if (hasPermission(player, perm)) {
return true;
}
}
return false;
}
/**
* Returns whether a player permission..
*
* @param player
* @param perm
* @return
*/
public abstract boolean hasPermission(T player, String perm);
/**
* Get the injector used to create new instances. This can be
* null, in which case only classes will be registered statically.
*/
public Injector getInjector() {
return injector;
}
/**
* Set the injector for creating new instances.
*
* @param injector injector or null
*/
public void setInjector(Injector injector) {
this.injector = injector;
}
}

View File

@ -0,0 +1,32 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* This annotation indicates that a command can be used from the console.
*
* @author sk89q
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Console {
}

View File

@ -0,0 +1,41 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.lang.reflect.InvocationTargetException;
/**
* Constructs new instances.
*/
public interface Injector {
/**
* Constructs a new instance of the given class.
*
* @param cls class
* @return object
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
*/
public Object getInstance(Class<?> cls) throws InvocationTargetException,
IllegalAccessException, InstantiationException;
}

View File

@ -0,0 +1,66 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//$Id$
package com.sk89q.minecraft.util.commands;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Indicates how the affected blocks should be hinted at in the log.
*
* @author sk89q
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Logging {
public enum LogMode {
/**
* Player position
*/
POSITION,
/**
* Region selection
*/
REGION,
/**
* Player orientation and region selection
*/
ORIENTATION_REGION,
/**
* Either the player position or pos1, depending on the placeAtPos1 flag
*/
PLACEMENT,
/**
* Log all information available
*/
ALL
}
/**
* Log mode. Can be either POSITION, REGION, ORIENTATION_REGION, PLACEMENT or ALL.
*/
LogMode value();
}

View File

@ -0,0 +1,29 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
public class MissingNestedCommandException extends CommandUsageException {
private static final long serialVersionUID = -4382896182979285355L;
public MissingNestedCommandException(String message, String usage) {
super(message, usage);
}
}

View File

@ -0,0 +1,46 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Indicates a nested command. Mark methods with this annotation to tell
* {@link CommandsManager} that a method is merely a shell for child
* commands. Note that the body of a method marked with this annotation
* will never called. Additionally, not all fields of {@link Command} apply
* when it is used in conjunction with this annotation, although both
* are still required.
*
* @author sk89q
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface NestedCommand {
/**
* A list of classes with the child commands.
*/
Class<?>[] value();
/**
* If set to true it will execute the body of the tagged method.
*/
boolean executeBody() default false;
}

View File

@ -0,0 +1,62 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;
public class SimpleInjector implements Injector {
private static final Logger logger = Logger.getLogger(SimpleInjector.class.getCanonicalName());
private Object[] args;
private Class<?>[] argClasses;
public SimpleInjector(Object... args) {
this.args = args;
argClasses = new Class[args.length];
for (int i = 0; i < args.length; ++i) {
argClasses[i] = args[i].getClass();
}
}
public Object getInstance(Class<?> clazz) {
try {
Constructor<?> ctr = clazz.getConstructor(argClasses);
ctr.setAccessible(true);
return ctr.newInstance(args);
} catch (NoSuchMethodException e) {
logger.severe("Error initializing commands class " + clazz + ": ");
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
logger.severe("Error initializing commands class " + clazz + ": ");
e.printStackTrace();
return null;
} catch (InstantiationException e) {
logger.severe("Error initializing commands class " + clazz + ": ");
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
logger.severe("Error initializing commands class " + clazz + ": ");
e.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,68 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
public class SuggestionContext {
private static final SuggestionContext FOR_LAST = new SuggestionContext(null, true);
private static final SuggestionContext FOR_HANGING = new SuggestionContext(null, false);
private final Character flag;
private final boolean forLast;
private SuggestionContext(Character flag, boolean forLast) {
this.flag = flag;
this.forLast = forLast;
}
public boolean forHangingValue() {
return flag == null && !forLast;
}
public boolean forLastValue() {
return flag == null && forLast;
}
public boolean forFlag() {
return flag != null;
}
public Character getFlag() {
return flag;
}
@Override
public String toString() {
return forFlag() ? ("-" + getFlag()) : (forHangingValue() ? "hanging" : "last");
}
public static SuggestionContext flag(Character flag) {
return new SuggestionContext(flag, false);
}
public static SuggestionContext lastValue() {
return FOR_LAST;
}
public static SuggestionContext hangingValue() {
return FOR_HANGING;
}
}

View File

@ -0,0 +1,25 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
public class UnhandledCommandException extends CommandException {
private static final long serialVersionUID = 3370887306593968091L;
}

View File

@ -0,0 +1,28 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.minecraft.util.commands;
public class WrappedCommandException extends CommandException {
private static final long serialVersionUID = -4075721444847778918L;
public WrappedCommandException(Throwable t) {
super(t);
}
}

View File

@ -0,0 +1,22 @@
package com.sk89q.minecraft.util.commands;
public interface WrappedCommandSender {
String getName();
void sendMessage(String message);
void sendMessage(String[] messages);
boolean hasPermission(String permission);
Type getType();
Object getCommandSender();
public static enum Type {
CONSOLE,
PLAYER,
BLOCK,
UNKNOWN
}
}

View File

@ -0,0 +1,8 @@
package com.sk89q.minecraft.util.commands;
public class WrappedCommandsManager extends CommandsManager<WrappedCommandSender> {
@Override
public boolean hasPermission(WrappedCommandSender player, String perm) {
return player.hasPermission(perm);
}
}

View File

@ -0,0 +1,71 @@
/*
* CommandBook
* Copyright (C) 2011 sk89q <http://www.sk89q.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 com.sk89q.minecraft.util.pagination;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.WrappedCommandSender;
/**
* Commands that wish to display a paginated list of results can use this class to do
* the actual pagination, giving a list of items, a page number, and basic formatting information.
*/
public abstract class PaginatedResult<T> {
protected final int resultsPerPage;
public PaginatedResult() {
this(6);
}
public PaginatedResult(int resultsPerPage) {
assert resultsPerPage > 0;
this.resultsPerPage = resultsPerPage;
}
public void display(WrappedCommandSender sender, Collection<? extends T> results, int page) throws CommandException {
this.display(sender, new ArrayList<T>(results), page);
}
public void display(WrappedCommandSender sender, List<? extends T> results, int page) throws CommandException {
if (results.size() == 0) throw new CommandException("No results match!");
int maxPages = results.size() / this.resultsPerPage + 1;
// If the content divides perfectly, eg (18 entries, and 9 per page)
// we end up with a blank page this handles this case
if (results.size() % this.resultsPerPage == 0) {
maxPages--;
}
if (page <= 0 || page > maxPages) throw new CommandException("Unknown page selected! " + maxPages + " total pages.");
sender.sendMessage(this.formatHeader(page, maxPages));
for (int i = this.resultsPerPage * (page - 1); i < this.resultsPerPage * page && i < results.size(); i++) {
sender.sendMessage(this.format(results.get(i), i));
}
}
public abstract String formatHeader(int page, int maxPages);
public abstract String format(T entry, int index);
}

View File

@ -0,0 +1,23 @@
package com.sk89q.minecraft.util.pagination;
import com.sk89q.minecraft.util.commands.ChatColor;
public abstract class SimplePaginatedResult<T> extends PaginatedResult<T> {
protected final String header;
public SimplePaginatedResult(String header) {
super();
this.header = header;
}
public SimplePaginatedResult(String header, int resultsPerPage) {
super(resultsPerPage);
this.header = header;
}
@Override
public String formatHeader(int page, int maxPages) {
return ChatColor.YELLOW + this.header + " (page " + page + "/" + maxPages + ")";
}
}

View File

@ -0,0 +1,48 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.util;
import java.lang.reflect.Field;
/**
* @author zml2008
*/
public final class ReflectionUtil {
private ReflectionUtil() {
}
@SuppressWarnings("unchecked")
public static <T> T getField(Object from, String name) {
Class<?> checkClass = from.getClass();
do {
try {
Field field = checkClass.getDeclaredField(name);
field.setAccessible(true);
return (T) field.get(from);
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
}
} while (checkClass.getSuperclass() != Object.class && ((checkClass = checkClass.getSuperclass()) != null));
return null;
}
}

View File

@ -0,0 +1,311 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.util;
import java.util.Collection;
import java.util.Map;
/**
* String utilities.
*
* @author sk89q
*/
public final class StringUtil {
private StringUtil() {
}
/**
* Trim a string if it is longer than a certain length.
*
* @param str
* @param len
* @return
*/
public static String trimLength(String str, int len) {
if (str.length() > len) {
return str.substring(0, len);
}
return str;
}
/**
* Join an array of strings into a string.
*
* @param str
* @param delimiter
* @param initialIndex
* @return
*/
public static String joinString(String[] str, String delimiter,
int initialIndex) {
if (str.length == 0) {
return "";
}
StringBuilder buffer = new StringBuilder(str[initialIndex]);
for (int i = initialIndex + 1; i < str.length; ++i) {
buffer.append(delimiter).append(str[i]);
}
return buffer.toString();
}
/**
* Join an array of strings into a string.
*
* @param str
* @param delimiter
* @param initialIndex
* @param quote
* @return
*/
public static String joinQuotedString(String[] str, String delimiter,
int initialIndex, String quote) {
if (str.length == 0) {
return "";
}
StringBuilder buffer = new StringBuilder();
buffer.append(quote);
buffer.append(str[initialIndex]);
buffer.append(quote);
for (int i = initialIndex + 1; i < str.length; ++i) {
buffer.append(delimiter).append(quote).append(str[i]).append(quote);
}
return buffer.toString();
}
/**
* Join an array of strings into a string.
*
* @param str
* @param delimiter
* @return
*/
public static String joinString(String[] str, String delimiter) {
return joinString(str, delimiter, 0);
}
/**
* Join an array of strings into a string.
*
* @param str
* @param delimiter
* @param initialIndex
* @return
*/
public static String joinString(Object[] str, String delimiter,
int initialIndex) {
if (str.length == 0) {
return "";
}
StringBuilder buffer = new StringBuilder(str[initialIndex].toString());
for (int i = initialIndex + 1; i < str.length; ++i) {
buffer.append(delimiter).append(str[i].toString());
}
return buffer.toString();
}
/**
* Join an array of strings into a string.
*
* @param str
* @param delimiter
* @param initialIndex
* @return
*/
public static String joinString(int[] str, String delimiter,
int initialIndex) {
if (str.length == 0) {
return "";
}
StringBuilder buffer = new StringBuilder(Integer.toString(str[initialIndex]));
for (int i = initialIndex + 1; i < str.length; ++i) {
buffer.append(delimiter).append(Integer.toString(str[i]));
}
return buffer.toString();
}
/**
* Join an list of strings into a string.
*
* @param str
* @param delimiter
* @param initialIndex
* @return
*/
public static String joinString(Collection<?> str, String delimiter,
int initialIndex) {
if (str.size() == 0) {
return "";
}
StringBuilder buffer = new StringBuilder();
int i = 0;
for (Object o : str) {
if (i >= initialIndex) {
if (i > 0) {
buffer.append(delimiter);
}
buffer.append(o.toString());
}
++i;
}
return buffer.toString();
}
/**
* <p>Find the Levenshtein distance between two Strings.</p>
*
* <p>This is the number of changes needed to change one String into
* another, where each change is a single character modification (deletion,
* insertion or substitution).</p>
*
* <p>The previous implementation of the Levenshtein distance algorithm
* was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
*
* <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
* which can occur when my Java implementation is used with very large strings.<br>
* This implementation of the Levenshtein distance algorithm
* is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
*
* <pre>
* StringUtil.getLevenshteinDistance(null, *) = IllegalArgumentException
* StringUtil.getLevenshteinDistance(*, null) = IllegalArgumentException
* StringUtil.getLevenshteinDistance("","") = 0
* StringUtil.getLevenshteinDistance("","a") = 1
* StringUtil.getLevenshteinDistance("aaapppp", "") = 7
* StringUtil.getLevenshteinDistance("frog", "fog") = 1
* StringUtil.getLevenshteinDistance("fly", "ant") = 3
* StringUtil.getLevenshteinDistance("elephant", "hippo") = 7
* StringUtil.getLevenshteinDistance("hippo", "elephant") = 7
* StringUtil.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
* StringUtil.getLevenshteinDistance("hello", "hallo") = 1
* </pre>
*
* @param s the first String, must not be null
* @param t the second String, must not be null
* @return result distance
* @throws IllegalArgumentException if either String input <code>null</code>
*/
public static int getLevenshteinDistance(String s, String t) {
if (s == null || t == null) {
throw new IllegalArgumentException("Strings must not be null");
}
/*
* The difference between this impl. and the previous is that, rather
* than creating and retaining a matrix of size s.length()+1 by
* t.length()+1, we maintain two single-dimensional arrays of length
* s.length()+1. The first, d, is the 'current working' distance array
* that maintains the newest distance cost counts as we iterate through
* the characters of String s. Each time we increment the index of
* String t we are comparing, d is copied to p, the second int[]. Doing
* so allows us to retain the previous cost counts as required by the
* algorithm (taking the minimum of the cost count to the left, up one,
* and diagonally up and to the left of the current cost count being
* calculated). (Note that the arrays aren't really copied anymore, just
* switched...this is clearly much better than cloning an array or doing
* a System.arraycopy() each time through the outer loop.)
*
* Effectively, the difference between the two implementations is this
* one does not cause an out of memory condition when calculating the LD
* over two very large strings.
*/
int n = s.length(); // length of s
int m = t.length(); // length of t
if (n == 0) {
return m;
} else if (m == 0) {
return n;
}
int p[] = new int[n + 1]; // 'previous' cost array, horizontally
int d[] = new int[n + 1]; // cost array, horizontally
int _d[]; // placeholder to assist in swapping p and d
// indexes into strings s and t
int i; // iterates through s
int j; // iterates through t
char tj; // jth character of t
int cost; // cost
for (i = 0; i <= n; ++i) {
p[i] = i;
}
for (j = 1; j <= m; ++j) {
tj = t.charAt(j - 1);
d[0] = j;
for (i = 1; i <= n; ++i) {
cost = s.charAt(i - 1) == tj ? 0 : 1;
// minimum of cell to the left+1, to the top+1, diagonally left
// and up +cost
d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1]
+ cost);
}
// copy current distance counts to 'previous row' distance counts
_d = p;
p = d;
d = _d;
}
// our last action in the above loop was to switch d and p, so p now
// actually has the most recent cost counts
return p[n];
}
public static <T extends Enum<?>> T lookup(Map<String, T> lookup, String name, boolean fuzzy) {
String testName = name.replaceAll("[ _]", "").toLowerCase();
T type = lookup.get(testName);
if (type != null) {
return type;
}
if (!fuzzy) {
return null;
}
int minDist = -1;
for (Map.Entry<String, T> entry : lookup.entrySet()) {
final String key = entry.getKey();
if (key.charAt(0) != testName.charAt(0)) {
continue;
}
int dist = getLevenshteinDistance(key, testName);
if ((dist < minDist || minDist == -1) && dist < 2) {
minDist = dist;
type = entry.getValue();
}
}
return type;
}
}

61
lib/pom.xml Normal file
View File

@ -0,0 +1,61 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sk89q</groupId>
<artifactId>command-framework-parent</artifactId>
<packaging>pom</packaging>
<version>0.5-SNAPSHOT</version>
<name>Sk89q Command Framework</name>
<description>sk89q's command system from WorldEdit factored out</description>
<modules>
<module>core</module>
<module>bukkit</module>
<module>bungee</module>
</modules>
<scm>
<connection>scm:git:git://github.com/OvercastNetwork/sk89q-command-framework.git</connection>
<developerConnection>scm:git:git@github.com:OvercastNetwork/sk89q-command-framework.git</developerConnection>
<url>https://github.com/OvercastNetwork/sk89q-command-framework</url>
</scm>
<distributionManagement>
<repository>
<id>overcast-deployment</id>
<url>https://repo.oc.tc/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>overcast-deployment</id>
<url>https://repo.oc.tc/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<build>
<sourceDirectory>${project.basedir}/src/main/java/</sourceDirectory>
<!-- Plugins -->
<plugins>
<!-- Compile plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<!-- JAR creation plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>