0.0.2 - Add javadoc and source plugins
This commit is contained in:
parent
9248899c40
commit
18e199bc2a
10
.gitignore
vendored
10
.gitignore
vendored
|
|
@ -1,9 +1,3 @@
|
|||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
.idea/
|
||||
*.iml
|
||||
|
|
|
|||
47
pom.xml
Normal file
47
pom.xml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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.alttd</groupId>
|
||||
<artifactId>AltitudeAPI</artifactId>
|
||||
<version>0.0.2</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.destroystokyo.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.14.1-R0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
50
src/main/java/com/alttd/altitudeapi/AltitudeAPI.java
Normal file
50
src/main/java/com/alttd/altitudeapi/AltitudeAPI.java
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package com.alttd.altitudeapi;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.alttd.altitudeapi.utils.items.ItemDb;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class AltitudeAPI extends JavaPlugin
|
||||
{
|
||||
private static AltitudeAPI instance;
|
||||
|
||||
private static ItemDb itemDb;
|
||||
|
||||
public void onEnable()
|
||||
{
|
||||
instance = this;
|
||||
|
||||
saveDefaultConfig();
|
||||
|
||||
if (getConfig().getBoolean("use-items"))
|
||||
{
|
||||
saveResource("items.csv", true);
|
||||
itemDb = new ItemDb(new File(getDataFolder(), "items.csv"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ItemDb} loaded by this plugin.
|
||||
*
|
||||
* @return the {@link ItemDb} loaded by this plugin.
|
||||
*/
|
||||
public static ItemDb getItemDb()
|
||||
{
|
||||
if (itemDb == null)
|
||||
{
|
||||
throw new IllegalStateException("Enable the item api in the config file.");
|
||||
}
|
||||
return itemDb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of this API.
|
||||
*
|
||||
* @return the singleton instance of this API.
|
||||
*/
|
||||
public static AltitudeAPI getInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,352 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
/**
|
||||
* @param <T> the type the argument will be after being parsed.
|
||||
*
|
||||
* @author Michael Ziluck
|
||||
*/
|
||||
public class CommandArgument<T>
|
||||
{
|
||||
protected ValidCommand command;
|
||||
|
||||
protected T value;
|
||||
|
||||
protected String name;
|
||||
|
||||
protected boolean optional;
|
||||
|
||||
protected boolean variableLength;
|
||||
|
||||
protected boolean allowsConsole;
|
||||
|
||||
protected int ordinal;
|
||||
|
||||
protected List<SenderValidator> senderValidators;
|
||||
|
||||
protected List<Validator<T>> validators;
|
||||
|
||||
protected Parser<T> parser;
|
||||
|
||||
protected String permission;
|
||||
|
||||
protected String[] tabOptions;
|
||||
|
||||
/**
|
||||
* Constructs a new argument. This will also initialize the validators list.
|
||||
*/
|
||||
protected CommandArgument()
|
||||
{
|
||||
this.senderValidators = new LinkedList<>();
|
||||
this.validators = new LinkedList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given argument. This will parse it into it's appropriate form, as well as validate that it is in the
|
||||
* proper state. The value returned represents whether or not the process was successful. No error message is
|
||||
* required beyond what was already sent within the parsers and validators.
|
||||
*
|
||||
* @param sender the sender of the command.
|
||||
* @param label the label of the command.
|
||||
* @param argument the raw string argument to be processed.
|
||||
*
|
||||
* @return {@code true} if the process was successful. Otherwise, returns {@code false}.
|
||||
*/
|
||||
protected boolean process(CommandSender sender, String[] label, String argument)
|
||||
{
|
||||
if (hasPermission() && !sender.hasPermission(permission))
|
||||
{
|
||||
CommandLang.NO_PERMISSION.send(sender);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (SenderValidator senderValidator : senderValidators)
|
||||
{
|
||||
if (!senderValidator.validate(sender))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
value = parser.parseArgument(sender, label, argument);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Validator<T> validator : validators)
|
||||
{
|
||||
if (!validator.validateArgument(sender, label, value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all potential options a player can have when trying to tab-complete this argument. This should always
|
||||
* be implemented. However, because that most likely will not happen, it defaults to the same behavior that Bukkit
|
||||
* uses which is to list off the names of all visible connected players.
|
||||
*
|
||||
* @param sender the sender who is tab-completing.
|
||||
* @param lastWord the content of the item so far.
|
||||
*
|
||||
* @return all argument options.
|
||||
*/
|
||||
protected List<String> getRecommendations(CommandSender sender, String lastWord)
|
||||
{
|
||||
List<String> recommendations = parser.getRecommendations(sender, lastWord);
|
||||
if (recommendations == null)
|
||||
{
|
||||
recommendations = CommandHandler.defaultTabComplete(sender, lastWord);
|
||||
}
|
||||
return recommendations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the most recent value processed by this argument.
|
||||
*/
|
||||
public void clearValue()
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the argument has a required rank. Otherwise returns {@code false}.
|
||||
*/
|
||||
public boolean hasPermission()
|
||||
{
|
||||
return permission != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ability to use an argument might differ from the ability to use a command in general. This is the rank
|
||||
* required to use this argument within a command.
|
||||
*
|
||||
* @return the rank required to use this argument.
|
||||
*/
|
||||
public String getPermission()
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the required permission for this argument. This should only be set once, and should only be changed from the
|
||||
* CommandArgumentBuilder. Will throw an {@link IllegalStateException} if set a second time.
|
||||
*
|
||||
* @param permission the required permission.
|
||||
*/
|
||||
public void setPermission(String permission)
|
||||
{
|
||||
if (this.permission != null)
|
||||
{
|
||||
throw new IllegalArgumentException("Permission can only be set once.");
|
||||
}
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parser for this argument.
|
||||
*/
|
||||
public Parser<T> getParser()
|
||||
{
|
||||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parser for this argument. This should only be set once, and should only be changed from the
|
||||
* CommandArgumentBuilder. Will throw an {@link IllegalStateException} if set a second time.
|
||||
*
|
||||
* @param parser the argument's parser.
|
||||
*/
|
||||
protected void setParser(Parser<T> parser)
|
||||
{
|
||||
if (this.parser != null)
|
||||
{
|
||||
throw new IllegalArgumentException("Parser can only be set once.");
|
||||
}
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of the validators. This view can't be changed, and will throw exceptions if it is attempted.
|
||||
*
|
||||
* @return the validators for this argument.
|
||||
*/
|
||||
public List<Validator<T>> getValidators()
|
||||
{
|
||||
return Collections.unmodifiableList(validators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new validator to the argument.
|
||||
*
|
||||
* @param validator the new validator.
|
||||
*/
|
||||
public void addValidator(Validator<T> validator)
|
||||
{
|
||||
this.validators.add(validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of the sender validators. This view can't be changed, and will throw exception if it is attempted.
|
||||
*
|
||||
* @return the sender validators for this argument
|
||||
*/
|
||||
public List<SenderValidator> getSenderValidators()
|
||||
{
|
||||
return Collections.unmodifiableList(senderValidators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new sender validator to the argument.
|
||||
*
|
||||
* @param senderValidator the new sender validator.
|
||||
*/
|
||||
public void addSenderValidator(SenderValidator senderValidator)
|
||||
{
|
||||
this.senderValidators.add(senderValidator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets where in the order of arguments this argument falls for a particular command. The default is -1, so if -1 is
|
||||
* returned it means that this argument has not yet been assigned to a command.
|
||||
*
|
||||
* @return the argument ordinal.
|
||||
*/
|
||||
public int getOrdinal()
|
||||
{
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the order that this argument falls for a particular command. This method is protected to make sure that the
|
||||
* CommandHandler does not break when managing the argument system.
|
||||
*
|
||||
* @param ordinal the new argument ordinal.
|
||||
*/
|
||||
protected void setOrdinal(int ordinal)
|
||||
{
|
||||
this.ordinal = ordinal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if this argument can't be used by console. Otherwise returns {@code false}.
|
||||
*/
|
||||
public boolean allowsConsole()
|
||||
{
|
||||
return allowsConsole;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param status {@code true} if this argument can't be used by console.
|
||||
*/
|
||||
public void setAllowsConsole(boolean status)
|
||||
{
|
||||
this.allowsConsole = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if this argument has variable length. Otherwise returns {@code false}.
|
||||
*/
|
||||
public boolean hasVariableLength()
|
||||
{
|
||||
return variableLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param status {@code true} if this argument has variable length.
|
||||
*/
|
||||
public void setVariableLength(boolean status)
|
||||
{
|
||||
this.variableLength = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this argument is optional or not.
|
||||
*/
|
||||
public boolean isOptional()
|
||||
{
|
||||
return optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param state whether or not the argument is optional.
|
||||
*/
|
||||
public void setOptional(boolean state)
|
||||
{
|
||||
this.optional = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the argument
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name for the argument. This should only be set once, and should only be changed from the
|
||||
* CommandArgumentBuilder. Will throw an {@link IllegalStateException} if set a second time.
|
||||
*
|
||||
* @param name the name of the argument.
|
||||
*/
|
||||
public void setName(String name)
|
||||
{
|
||||
if (this.name != null)
|
||||
{
|
||||
throw new IllegalStateException("Name can only be set once.");
|
||||
}
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This should only be used to check if an optional argument has a value.
|
||||
*
|
||||
* @return {@code true} if this argument has a value.
|
||||
*/
|
||||
public boolean hasValue()
|
||||
{
|
||||
return value != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value that was just parsed and validated.
|
||||
*
|
||||
* @return the value.
|
||||
*/
|
||||
public T getValue()
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new IllegalStateException("Argument has not been processed.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the command this argument belongs to.
|
||||
*/
|
||||
protected ValidCommand getCommand()
|
||||
{
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param command the command this argument belongs to.
|
||||
*/
|
||||
protected void setCommand(ValidCommand command)
|
||||
{
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
public class CommandArgumentBuilder<T>
|
||||
{
|
||||
|
||||
private CommandArgument<T> argument;
|
||||
|
||||
private CommandArgumentBuilder()
|
||||
{
|
||||
argument = new CommandArgument<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name for the argument.
|
||||
*
|
||||
* @param name the name for the argument.
|
||||
*
|
||||
* @return the same builder.
|
||||
*/
|
||||
public CommandArgumentBuilder<T> setName(String name)
|
||||
{
|
||||
argument.setName(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parser for the argument.
|
||||
*
|
||||
* @param parser the parser for the argument.
|
||||
*
|
||||
* @return the same builder.
|
||||
*/
|
||||
public CommandArgumentBuilder<T> setParser(Parser<T> parser)
|
||||
{
|
||||
argument.setParser(parser);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the required rank for the argument.
|
||||
*
|
||||
* @param permission the required permission for the argument.
|
||||
*
|
||||
* @return the same builder.
|
||||
*/
|
||||
public CommandArgumentBuilder<T> setRequiredPermission(String permission)
|
||||
{
|
||||
argument.setPermission(permission);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a validator to be used by the argument.
|
||||
*
|
||||
* @param validator the new validator.
|
||||
*
|
||||
* @return the same builder.
|
||||
*/
|
||||
public CommandArgumentBuilder<T> addValidator(Validator<T> validator)
|
||||
{
|
||||
argument.addValidator(validator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sender validator to be used by the argument.
|
||||
*
|
||||
* @param senderValidator the new sender validator.
|
||||
*
|
||||
* @return the same builder.
|
||||
*/
|
||||
public CommandArgumentBuilder<T> addSenderValidator(SenderValidator senderValidator)
|
||||
{
|
||||
argument.addSenderValidator(senderValidator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this argument as optional. It defaults to false which is why there is no option to disable it as each
|
||||
* option should only be set once.
|
||||
*
|
||||
* @return the same builder.
|
||||
*/
|
||||
public CommandArgumentBuilder<T> setOptional()
|
||||
{
|
||||
argument.setOptional(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this argument as having variable length. It defaults to false which is why there is no option to disable it
|
||||
* as each option should only be set to once.
|
||||
*
|
||||
* @return the same builder.
|
||||
*/
|
||||
public CommandArgumentBuilder<T> setVariableLength()
|
||||
{
|
||||
argument.setVariableLength(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this argument as usable by the console. It defaults to false which is why there is no option to disable it
|
||||
* as each option should only be set once.
|
||||
*
|
||||
* @return the same builder
|
||||
*/
|
||||
public CommandArgumentBuilder<T> setAllowsConsole()
|
||||
{
|
||||
argument.setAllowsConsole(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link CommandArgument} that has been built. Will throw an {@link IllegalStateException} if the
|
||||
* parser has not been set as it is required.
|
||||
*
|
||||
* @return build the completed argument.
|
||||
*/
|
||||
public CommandArgument<T> build()
|
||||
{
|
||||
if (argument.getName() == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Argument name not set");
|
||||
}
|
||||
if (argument.getParser() == null)
|
||||
{
|
||||
throw new IllegalStateException("Argument parser not set.");
|
||||
}
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
public static <T> CommandArgumentBuilder<T> createBuilder(Class<T> type)
|
||||
{
|
||||
return new CommandArgumentBuilder<T>();
|
||||
}
|
||||
|
||||
}
|
||||
258
src/main/java/com/alttd/altitudeapi/commands/CommandHandler.java
Normal file
258
src/main/java/com/alttd/altitudeapi/commands/CommandHandler.java
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
/**
|
||||
* The processor that handles all {@link ValidCommand ValidCommands}.
|
||||
*
|
||||
* @author Michael Ziluck
|
||||
*/
|
||||
public class CommandHandler implements CommandExecutor, TabCompleter
|
||||
{
|
||||
|
||||
private static CommandHandler instance;
|
||||
|
||||
private static SimpleCommandMap commandMapInstance = getCommandMap();
|
||||
|
||||
private static Map<String, Command> knownCommands = getKnownCommands();
|
||||
|
||||
private List<ValidCommand> commands;
|
||||
|
||||
/**
|
||||
* Constructs a new CommandHandler. Will initialize the commands list.
|
||||
*/
|
||||
public CommandHandler()
|
||||
{
|
||||
this.commands = new LinkedList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args)
|
||||
{
|
||||
ValidCommand command = getCommand(label);
|
||||
if (command != null)
|
||||
{
|
||||
if (sender.hasPermission(command.getPermission()))
|
||||
{
|
||||
command.process(sender, new String[]{ label }, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandLang.NO_PERMISSION.send(sender);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command cmd, String alias, String[] args)
|
||||
{
|
||||
ValidCommand command = getCommand(alias);
|
||||
if (command != null)
|
||||
{
|
||||
return command.processTabComplete(sender, args);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the command to be used with this command handler.
|
||||
*
|
||||
* @param command the command to register.
|
||||
* @param plugin the plugin this command is owned by.
|
||||
*/
|
||||
public void registerCommand(ValidCommand command, JavaPlugin plugin)
|
||||
{
|
||||
// remove any preexisting and conflicting commands.
|
||||
for (String str : checkString(knownCommands.keySet(), command))
|
||||
{
|
||||
knownCommands.remove(str);
|
||||
}
|
||||
|
||||
// create an instance of the bukkit command and set the proper values.
|
||||
PluginCommand bukkitCommand = createBukkitCommand(command.getName(), plugin);
|
||||
bukkitCommand.setAliases(Arrays.asList(command.getAliases()));
|
||||
bukkitCommand.setDescription(command.getDescription());
|
||||
bukkitCommand.setExecutor(this);
|
||||
bukkitCommand.setTabCompleter(this);
|
||||
|
||||
// register the command with bukkit
|
||||
commandMapInstance.register(plugin.getDescription().getName(), bukkitCommand);
|
||||
|
||||
commands.add(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the custom command of the given name. This can be either the command's name or one of it's aliases. Will
|
||||
* return null if no match was found, which should never happen assuming the command registration went properly.
|
||||
*
|
||||
* @param label the label of the command.
|
||||
*
|
||||
* @return the command, if one exists.
|
||||
*/
|
||||
public ValidCommand getCommand(String label)
|
||||
{
|
||||
for (ValidCommand command : commands)
|
||||
{
|
||||
if (command.matches(label))
|
||||
{
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all list of all commands that have a name that conflicts with the given valid command. This ensures that the
|
||||
* commands registered in our system will always supersede any other plugin's commands.
|
||||
*
|
||||
* @param strings the names of all existing commands.
|
||||
* @param command the command to check.
|
||||
*
|
||||
* @return all conflicting preexisting commands.
|
||||
*/
|
||||
private List<String> checkString(Collection<String> strings, ValidCommand command)
|
||||
{
|
||||
List<String> aliases = new ArrayList<>(Arrays.asList(command.getAliases()));
|
||||
aliases.add(command.getName());
|
||||
aliases.retainAll(strings);
|
||||
return aliases;
|
||||
}
|
||||
|
||||
private PluginCommand createBukkitCommand(String name, JavaPlugin plugin)
|
||||
{
|
||||
PluginCommand command = null;
|
||||
try
|
||||
{
|
||||
Constructor<PluginCommand> c = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
|
||||
c.setAccessible(true);
|
||||
|
||||
command = c.newInstance(name, plugin);
|
||||
}
|
||||
catch (SecurityException | IllegalArgumentException | IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the singleton instance of this handler.
|
||||
*/
|
||||
public static void initialize()
|
||||
{
|
||||
instance = new CommandHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the singleton instance of this handler.
|
||||
*/
|
||||
public static CommandHandler getInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, Command> getKnownCommands()
|
||||
{
|
||||
Map<String, Command> existingCommands = null;
|
||||
try
|
||||
{
|
||||
Field f = SimpleCommandMap.class.getDeclaredField("knownCommands");
|
||||
f.setAccessible(true);
|
||||
|
||||
existingCommands = (Map<String, Command>) f.get(commandMapInstance);
|
||||
}
|
||||
catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
return existingCommands;
|
||||
}
|
||||
|
||||
private static SimpleCommandMap getCommandMap()
|
||||
{
|
||||
SimpleCommandMap commandMap = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (Bukkit.getPluginManager() instanceof SimplePluginManager)
|
||||
{
|
||||
Field f = SimplePluginManager.class.getDeclaredField("commandMap");
|
||||
f.setAccessible(true);
|
||||
|
||||
commandMap = (SimpleCommandMap) f.get(Bukkit.getPluginManager());
|
||||
}
|
||||
}
|
||||
catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
return commandMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sender the sender of the tab complete.
|
||||
* @param lastWord the beginning of the typed argument.
|
||||
*
|
||||
* @return the name of all players visible to the sender.
|
||||
*/
|
||||
public static List<String> defaultTabComplete(CommandSender sender, String lastWord)
|
||||
{
|
||||
// if the lastWord is null, something went wrong we should exit
|
||||
if (lastWord == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// set the argument to lower case for easier comparison
|
||||
lastWord = lastWord.toLowerCase();
|
||||
|
||||
// create the list to return
|
||||
List<String> values = new LinkedList<>();
|
||||
|
||||
// create a player instance of the sender
|
||||
Player playerSender = sender instanceof Player ? (Player) sender : null;
|
||||
|
||||
// go through the players
|
||||
for (Player player : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
// if the sender is not a player or if the player can see the target, add them
|
||||
if ((playerSender == null || playerSender.canSee(player)) && (lastWord.equals("") || player.getName().toLowerCase().startsWith(lastWord)))
|
||||
{
|
||||
values.add(player.getName());
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
}
|
||||
131
src/main/java/com/alttd/altitudeapi/commands/CommandLang.java
Normal file
131
src/main/java/com/alttd/altitudeapi/commands/CommandLang.java
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.alttd.altitudeapi.utils.CollectionUtils;
|
||||
import com.alttd.altitudeapi.utils.MutableValue;
|
||||
import com.alttd.altitudeapi.utils.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class CommandLang
|
||||
{
|
||||
/**
|
||||
* When a non-player tries to run a player-only command.
|
||||
*/
|
||||
public static CommandLang ONLY_PLAYERS = new CommandLang("Only players can run that command.");
|
||||
|
||||
/**
|
||||
* The format for a command usage message.
|
||||
*/
|
||||
public static CommandLang USAGE_FORMAT = new CommandLang("&6&lUSAGE &e» &7{message}");
|
||||
|
||||
/**
|
||||
* When a {@link CommandSender} does not have permission to use a command.
|
||||
*/
|
||||
public static CommandLang NO_PERMISSION = new CommandLang("&4&lERROR &e» You don't have permission to do that.");
|
||||
|
||||
/**
|
||||
* When a player tries to list the available sub-commands.
|
||||
*/
|
||||
public static CommandLang NO_SUBS = new CommandLang("&4&lERROR &e» You don't have access to any sub-commands.");
|
||||
|
||||
public static CommandLang HEADER_FOOTER = new CommandLang("&7&m-----------------------------------");
|
||||
|
||||
private final MutableValue<String> value;
|
||||
|
||||
/**
|
||||
* Constructs a new CommandLang to be used in this class.
|
||||
*
|
||||
* @param value the default message.
|
||||
*/
|
||||
private CommandLang(String value)
|
||||
{
|
||||
// set the default value
|
||||
this.value = new MutableValue<>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this lang option.
|
||||
*
|
||||
* @return the value of this lang option.
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return value.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lang message.
|
||||
*
|
||||
* @param value the new lang value.
|
||||
*/
|
||||
public void setValue(String value)
|
||||
{
|
||||
this.value.setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a string with the proper parameters.
|
||||
*
|
||||
* @param args the placeholders and proper content.
|
||||
*
|
||||
* @return the rendered string.
|
||||
*/
|
||||
private String renderString(Object... args)
|
||||
{
|
||||
if (args.length % 2 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Message rendering requires an even number of arguments. " + Arrays.toString(args) + " given.");
|
||||
}
|
||||
String string = getValue();
|
||||
for (int i = 0; i < args.length; i += 2)
|
||||
{
|
||||
string = string.replace(args[i].toString(), CollectionUtils.firstNonNull(args[i + 1], "").toString());
|
||||
}
|
||||
|
||||
return ChatColor.translateAlternateColorCodes('&', string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this message and returns it.
|
||||
*
|
||||
* @param parameters all additional arguments to fill placeholders.
|
||||
*
|
||||
* @return the compiled message.
|
||||
*/
|
||||
private String getMessage(Object... parameters)
|
||||
{
|
||||
return renderString(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this {@link CommandLang} object to the {@link CommandSender} target. The parameters replace all
|
||||
* placeholders that exist in the String as well.
|
||||
*
|
||||
* @param sender the {@link CommandSender} receiving the message.
|
||||
* @param parameters all additional arguments to fill placeholders.
|
||||
*/
|
||||
public void send(CommandSender sender, Object... parameters)
|
||||
{
|
||||
sender.sendMessage(getMessage(parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a usage message to the {@link CommandSender} for a command with the given label and parameters.
|
||||
*
|
||||
* @param sender the sender of the message
|
||||
* @param label the labels the command has.
|
||||
* @param parameters the parameters a command has.
|
||||
*/
|
||||
protected static void sendUsageMessage(CommandSender sender, String[] label, String[] parameters)
|
||||
{
|
||||
StringBuilder args = new StringBuilder("/" + StringUtils.compile(label));
|
||||
for (String str : parameters)
|
||||
{
|
||||
args.append(" [").append(str).append("]");
|
||||
}
|
||||
|
||||
sender.sendMessage(USAGE_FORMAT.getMessage("{usage}", args.toString()));
|
||||
}
|
||||
}
|
||||
50
src/main/java/com/alttd/altitudeapi/commands/Parser.java
Normal file
50
src/main/java/com/alttd/altitudeapi/commands/Parser.java
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public interface Parser<T>
|
||||
{
|
||||
|
||||
/**
|
||||
* Parses the argument from the raw string into the appropriate type. If the argument can't be parsed
|
||||
*
|
||||
* @param sender the sender of the command.
|
||||
* @param label the label of the command
|
||||
* @param rawArgument the argument to be parsed.
|
||||
*
|
||||
* @return the successfully parsed argument.
|
||||
*/
|
||||
public T parseArgument(CommandSender sender, String[] label, String rawArgument);
|
||||
|
||||
/**
|
||||
* Get tab complete recommendations for an argument with this given parser. If the default is wanted, it exists in
|
||||
* {@link CommandHandler#defaultTabComplete(CommandSender, String)}.
|
||||
*
|
||||
* @param sender the sender of the tab complete.
|
||||
* @param lastWord the content of the item so far.
|
||||
*
|
||||
* @return the recommendations.
|
||||
*/
|
||||
public List<String> getRecommendations(CommandSender sender, String lastWord);
|
||||
|
||||
public static void pruneSuggestions(List<String> values, String lastWord)
|
||||
{
|
||||
if (values == null || values.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lastWord = lastWord.toLowerCase();
|
||||
Iterator<String> it = values.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
if (!it.next().toLowerCase().startsWith(lastWord))
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public interface SenderValidator
|
||||
{
|
||||
|
||||
/**
|
||||
* Validates that the sender is in the proper state.
|
||||
*
|
||||
* @param sender the person sending the command.
|
||||
* @return {@code true} if the sender is valid.
|
||||
*/
|
||||
public boolean validate(CommandSender sender);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alttd.altitudeapi.utils.StringUtils;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public abstract class ValidBaseCommand extends ValidCommand
|
||||
{
|
||||
|
||||
protected List<ValidCommand> subCommands;
|
||||
|
||||
/**
|
||||
* Constructs a new base command.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param permission the required rank to use this command.
|
||||
* @param aliases any aliases for this command.
|
||||
*/
|
||||
protected ValidBaseCommand(String name, String description, String permission, String[] aliases)
|
||||
{
|
||||
super(name, description, permission, aliases);
|
||||
|
||||
subCommands = new LinkedList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new base command with no aliases.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param permission the required rank to use this command.
|
||||
*/
|
||||
protected ValidBaseCommand(String name, String description, String permission)
|
||||
{
|
||||
this(name, description, permission, new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new base command with no required permission.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param aliases any aliases for this command.
|
||||
*/
|
||||
protected ValidBaseCommand(String name, String description, String[] aliases)
|
||||
{
|
||||
this(name, description, null, aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new base command with no aliases and no required permission.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
*/
|
||||
protected ValidBaseCommand(String name, String description)
|
||||
{
|
||||
this(name, description, null, new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process(CommandSender sender, String[] label, String[] rawArguments)
|
||||
{
|
||||
ValidCommand sub;
|
||||
if (rawArguments.length == 0 || (sub = getSubCommand(rawArguments[0])) == null)
|
||||
{
|
||||
help(sender, label);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((!hasPermission() || sender.hasPermission(getPermission())) && (!sub.hasPermission() || sender.hasPermission(sub.getPermission())))
|
||||
{
|
||||
sub.process(sender, StringUtils.add(label, rawArguments[0]), Arrays.copyOfRange(rawArguments, 1, rawArguments.length));
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandLang.NO_PERMISSION.send(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> processTabComplete(CommandSender sender, String[] rawArguments)
|
||||
{
|
||||
if (rawArguments.length == 1)
|
||||
{
|
||||
return getSubCommandNames(sender, rawArguments[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return getSubCommand(rawArguments[0]).processTabComplete(sender, Arrays.copyOfRange(rawArguments, 1, rawArguments.length));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new sub command to this base command.
|
||||
*
|
||||
* @param subCommand the sub command to add.
|
||||
*/
|
||||
public void addSubCommand(ValidCommand subCommand)
|
||||
{
|
||||
subCommands.add(subCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a sub command by the given name. This can be either the command's name or one of it's aliases.
|
||||
*
|
||||
* @param label the label sent by the player.
|
||||
*
|
||||
* @return the sub command if one is found.
|
||||
*/
|
||||
public ValidCommand getSubCommand(String label)
|
||||
{
|
||||
for (ValidCommand command : subCommands)
|
||||
{
|
||||
if (command.matches(label))
|
||||
{
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name all sub commands whose name or one if it's aliases starts with the given string. The name for each
|
||||
* command will be whichever piece was provided, whether that be the alias or the name.
|
||||
*
|
||||
* @param sender the sender of the command.
|
||||
* @param start the beginning of the label.
|
||||
*
|
||||
* @return the command labels if any are found.
|
||||
*/
|
||||
public List<String> getSubCommandNames(CommandSender sender, String start)
|
||||
{
|
||||
List<String> commandNames = new LinkedList<>();
|
||||
if (!hasPermission() || sender.hasPermission(getPermission()))
|
||||
{
|
||||
return commandNames;
|
||||
}
|
||||
String match;
|
||||
for (ValidCommand sub : subCommands)
|
||||
{
|
||||
if ((match = sub.getMatchingAlias(start)) != null && (!sub.hasPermission() || sender.hasPermission(sub.getPermission())))
|
||||
{
|
||||
commandNames.add(match);
|
||||
}
|
||||
}
|
||||
return commandNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a view of all the sub commands. This is not able to be modified and doing so will throw an exception.
|
||||
*
|
||||
* @return all the sub commands.
|
||||
*/
|
||||
public List<ValidCommand> getSubCommands()
|
||||
{
|
||||
return Collections.unmodifiableList(subCommands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the help content to the player.
|
||||
*
|
||||
* @param sender the sender of the command.
|
||||
* @param label the labels that this command has.
|
||||
*/
|
||||
public void help(CommandSender sender, String label[])
|
||||
{
|
||||
List<ValidCommand> allowedSubs = new LinkedList<>();
|
||||
for (ValidCommand sub : subCommands)
|
||||
{
|
||||
if (!sub.hasPermission() || sender.hasPermission(sub.getPermission()))
|
||||
{
|
||||
allowedSubs.add(sub);
|
||||
}
|
||||
}
|
||||
|
||||
if (allowedSubs.size() == 0)
|
||||
{
|
||||
CommandLang.NO_SUBS.send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
CommandLang.HEADER_FOOTER.send(sender);
|
||||
for (ValidCommand sub : allowedSubs)
|
||||
{
|
||||
sender.sendMessage(" §b/" + StringUtils.compile(label) + " " + sub.getName() + ": §7" + sub.getDescription());
|
||||
}
|
||||
CommandLang.HEADER_FOOTER.send(sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validRun(CommandSender sender, String[] label, List<CommandArgument<?>> arguments)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
570
src/main/java/com/alttd/altitudeapi/commands/ValidCommand.java
Normal file
570
src/main/java/com/alttd/altitudeapi/commands/ValidCommand.java
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alttd.altitudeapi.utils.CollectionUtils;
|
||||
import com.alttd.altitudeapi.utils.StringUtils;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Table;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public abstract class ValidCommand
|
||||
{
|
||||
protected String name;
|
||||
|
||||
protected String description;
|
||||
|
||||
protected String permission;
|
||||
|
||||
protected boolean blocksConsole;
|
||||
|
||||
protected String[] aliases;
|
||||
|
||||
protected LinkedList<SenderValidator> senderValidators;
|
||||
|
||||
protected ArrayList<CommandArgument<?>> arguments;
|
||||
|
||||
protected Table<Integer, Class<?>, Object> values;
|
||||
|
||||
/**
|
||||
* Constructs a new command with the given arguments. This will initialize the arguments list as well as the values
|
||||
* table. Additionally, it will automatically convert all aliases to lowercase.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param permission the required permission for the command.
|
||||
* @param blocksConsole if this command is unusable by the console.
|
||||
* @param aliases the aliases of the command.
|
||||
*/
|
||||
public ValidCommand(String name, String description, String permission, boolean blocksConsole, String[] aliases)
|
||||
{
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.permission = permission;
|
||||
this.blocksConsole = blocksConsole;
|
||||
this.aliases = aliases;
|
||||
this.senderValidators = new LinkedList<>();
|
||||
this.arguments = new ArrayList<>();
|
||||
this.values = HashBasedTable.create();
|
||||
for (int i = 0; i < aliases.length; i++)
|
||||
{
|
||||
aliases[i] = aliases[i] == null ? "" : aliases[i].toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new command without any aliases.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param permission the required permission for the command.
|
||||
* @param blocksConsole if this command is unusable by the console.
|
||||
*
|
||||
* @see #ValidCommand(String, String, String, boolean, String[])
|
||||
*/
|
||||
public ValidCommand(String name, String description, String permission, boolean blocksConsole)
|
||||
{
|
||||
this(name, description, permission, blocksConsole, new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new command that is usable by the console.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param permission the required permission for the command.
|
||||
* @param aliases the aliases of the command.
|
||||
*
|
||||
* @see #ValidCommand(String, String, String, boolean, String[])
|
||||
*/
|
||||
public ValidCommand(String name, String description, String permission, String[] aliases)
|
||||
{
|
||||
this(name, description, permission, false, aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new command without a required permission.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param blocksConsole if this command is unusable by the console.
|
||||
* @param aliases the aliases of the command.
|
||||
*
|
||||
* @see #ValidCommand(String, String, String, boolean, String[])
|
||||
*/
|
||||
public ValidCommand(String name, String description, boolean blocksConsole, String[] aliases)
|
||||
{
|
||||
this(name, description, null, blocksConsole, aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new command without any aliases and is usable by the console.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param permission the required permission for the command.
|
||||
*
|
||||
* @see #ValidCommand(String, String, String, boolean, String[])
|
||||
*/
|
||||
public ValidCommand(String name, String description, String permission)
|
||||
{
|
||||
this(name, description, permission, false, new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new command without any aliases and no required permission.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param blocksConsole if this command is unusable by the console.
|
||||
*
|
||||
* @see #ValidCommand(String, String, String, boolean, String[])
|
||||
*/
|
||||
public ValidCommand(String name, String description, boolean blocksConsole)
|
||||
{
|
||||
this(name, description, null, blocksConsole, new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new command with no required permission and is usable by the console.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
* @param aliases the aliases of the command.
|
||||
*
|
||||
* @see #ValidCommand(String, String, String, boolean, String[])
|
||||
*/
|
||||
public ValidCommand(String name, String description, String[] aliases)
|
||||
{
|
||||
this(name, description, null, false, aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new command without any aliases, no required permission, and is usable by the console.
|
||||
*
|
||||
* @param name the name of the command.
|
||||
* @param description the description of the command.
|
||||
*
|
||||
* @see #ValidCommand(String, String, String, boolean, String[])
|
||||
*/
|
||||
public ValidCommand(String name, String description)
|
||||
{
|
||||
this(name, description, null, false, new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method runs the command. It goes through each argument and will process and validate it. Then, so long as
|
||||
* that passes, it will run the command's system. Last it will clear out any saved table data and stored argument
|
||||
* values.
|
||||
*
|
||||
* @param sender the sender of the command.
|
||||
* @param label the label from which the command was sent
|
||||
* @param rawArguments the unparsed and non-validated arguments.
|
||||
*/
|
||||
protected void process(CommandSender sender, String[] label, String[] rawArguments)
|
||||
{
|
||||
if (rawArguments.length < getMinimumLength() || rawArguments.length > getMaximumLength())
|
||||
{
|
||||
CommandLang.sendUsageMessage(sender, label, getArgumentNames());
|
||||
return;
|
||||
}
|
||||
for (SenderValidator senderValidator : senderValidators)
|
||||
{
|
||||
if (!senderValidator.validate(sender))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rawArguments.length == 0 && blocksConsole() && sender instanceof ConsoleCommandSender)
|
||||
{
|
||||
CommandLang.ONLY_PLAYERS.send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
CommandArgument<?> argument;
|
||||
for (int i = 0; i < rawArguments.length; i++)
|
||||
{
|
||||
argument = getArgument(i);
|
||||
|
||||
// this should never happen, it is here exclusively to prevent potential errors that were not caught with exceptions earlier
|
||||
if (argument == null)
|
||||
{
|
||||
CommandLang.sendUsageMessage(sender, label, getArgumentNames());
|
||||
return;
|
||||
}
|
||||
|
||||
if (blocksConsole() && !argument.allowsConsole() && sender instanceof ConsoleCommandSender)
|
||||
{
|
||||
CommandLang.ONLY_PLAYERS.send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!argument.process(sender, label, !argument.hasVariableLength() ? rawArguments[i] : StringUtils.compile(Arrays.copyOfRange(rawArguments, i, rawArguments.length))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
validRun(sender, label, arguments);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
sender.sendMessage("§4An error occurred. Contact a staff member immediately.");
|
||||
for (Player player : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
if (player.hasPermission("altitude.admin"))
|
||||
{
|
||||
player.sendMessage("§4§lERROR: §cA player tried to run a FortuneBlocks command and it caused an error. Tell an administrator to check the console.");
|
||||
}
|
||||
}
|
||||
}
|
||||
arguments.forEach(CommandArgument::clearValue);
|
||||
clearTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the tab complete for the given command. This also takes into account the fact the last argument provided
|
||||
* is what is supposed to be changed. The arguments passed include only the arguments for the command, and not the
|
||||
* actual label used. The raw arguments passed should always have at least a length of 1.
|
||||
*
|
||||
* @param sender the person who sent the tab request.
|
||||
* @param rawArguments the arguments already typed by the player.
|
||||
*
|
||||
* @return the suggestions for tab complete.
|
||||
*/
|
||||
public List<String> processTabComplete(CommandSender sender, String[] rawArguments)
|
||||
{
|
||||
Iterator<CommandArgument<?>> it = arguments.iterator();
|
||||
int i = 0;
|
||||
CommandArgument<?> argument = null;
|
||||
while (it.hasNext() && i < rawArguments.length)
|
||||
{
|
||||
argument = it.next();
|
||||
i++;
|
||||
}
|
||||
if (argument != null)
|
||||
{
|
||||
if (!argument.hasPermission() || sender.hasPermission(argument.getPermission()))
|
||||
{
|
||||
return argument.getRecommendations(sender, rawArguments[rawArguments.length - 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Arrays.asList();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return CommandHandler.defaultTabComplete(sender, rawArguments[rawArguments.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command after all processing has already been completed. The label is an array of the label used by this
|
||||
* command as well as any parent command. The arguments will always be there, whether they are used or not. To check
|
||||
* if optional arguments were used, call the method {@link CommandArgument#hasValue()}.
|
||||
*
|
||||
* @param sender the sender of the command.
|
||||
* @param label the label of the command.
|
||||
* @param arguments the arguments of the command.
|
||||
*/
|
||||
public abstract void validRun(CommandSender sender, String[] label, List<CommandArgument<?>> arguments);
|
||||
|
||||
/**
|
||||
* The table of the already processed values. -1 corresponds to the sender. Every other number corresponds to the
|
||||
* ordinal of the argument. In the process of running the command, it will always grab the sender's session.
|
||||
*
|
||||
* @return the already processed values.
|
||||
*/
|
||||
public Table<Integer, Class<?>, Object> getValues()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all the stored values in the table that were added from the command's usage.
|
||||
*/
|
||||
private void clearTable()
|
||||
{
|
||||
values.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an array of all the names of the arguments.
|
||||
*/
|
||||
public String[] getArgumentNames()
|
||||
{
|
||||
String[] argumentNames = new String[arguments.size()];
|
||||
int i = 0;
|
||||
for (CommandArgument<?> argument : arguments)
|
||||
{
|
||||
argumentNames[i] = argument.getName();
|
||||
i++;
|
||||
}
|
||||
return argumentNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* The lowest possible length that the number of raw arguments is capable of being. This is the count of the number
|
||||
* of arguments that are not optional.
|
||||
*
|
||||
* @return the minimum length of the raw command arguments.
|
||||
*/
|
||||
protected int getMinimumLength()
|
||||
{
|
||||
int minimumLength = 0;
|
||||
for (CommandArgument<?> argument : arguments)
|
||||
{
|
||||
if (!argument.isOptional())
|
||||
{
|
||||
minimumLength++;
|
||||
}
|
||||
}
|
||||
return minimumLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* The highest possible length that the number of raw arguments is capable of being. For non-variable-length
|
||||
* commands, this is the size of all the arguments. For variable-length commands, it is {@link Integer#MAX_VALUE}.
|
||||
*
|
||||
* @return the maximum length of the raw command arguments.
|
||||
*/
|
||||
protected int getMaximumLength()
|
||||
{
|
||||
if (arguments.size() == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (CollectionUtils.getLast(arguments).hasVariableLength())
|
||||
{
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return arguments.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new argument to be used by the command. Will throw an {@link IllegalArgumentException} in one of two
|
||||
* cases. First, if the given argument is required and the previous argument is not optional. Second, if the
|
||||
* argument before it is of variable length. Both of these cases are not supported as there is no perfect way to
|
||||
* ensure that the arguments will always capture the desired input.
|
||||
*
|
||||
* @param argument the new argument
|
||||
*/
|
||||
protected void addArgument(CommandArgument<?> argument)
|
||||
{
|
||||
if (arguments.size() != 0)
|
||||
{
|
||||
|
||||
if (!argument.isOptional() && CollectionUtils.getLast(arguments).isOptional())
|
||||
{
|
||||
throw new IllegalArgumentException("Required arguments can only follow other required arguments.");
|
||||
}
|
||||
if (CollectionUtils.getLast(arguments).hasVariableLength())
|
||||
{
|
||||
throw new IllegalArgumentException("Arguments of variable length must be the last argument.");
|
||||
}
|
||||
}
|
||||
argument.setOrdinal(arguments.size());
|
||||
argument.setCommand(this);
|
||||
arguments.add(argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an existing argument from the command.
|
||||
*
|
||||
* @param argument the existing argument.
|
||||
*
|
||||
* @return whether or not the argument still existed.
|
||||
*/
|
||||
protected boolean removeArgument(CommandArgument<?> argument)
|
||||
{
|
||||
return arguments.remove(argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an existing argument from the command, referenced by name.
|
||||
*
|
||||
* @param argumentName the name of the argument.
|
||||
*
|
||||
* @return whether or not the argument existed.
|
||||
*/
|
||||
protected boolean removeArgument(String argumentName)
|
||||
{
|
||||
return removeArgument(getArgument(argumentName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an unmodifiable view of the arguments for this command. To add a new argument use
|
||||
* {@link #addArgument(CommandArgument)}. To remove an existing argument use
|
||||
* {@link #removeArgument(CommandArgument)}.
|
||||
*
|
||||
* @return the current existing arguments.
|
||||
*/
|
||||
public List<CommandArgument<?>> getArguments()
|
||||
{
|
||||
return Collections.unmodifiableList(arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ordinal the ordinal.
|
||||
*
|
||||
* @return the argument at the given ordinal.
|
||||
*/
|
||||
protected CommandArgument<?> getArgument(int ordinal)
|
||||
{
|
||||
for (CommandArgument<?> argument : arguments)
|
||||
{
|
||||
if (argument.getOrdinal() == ordinal)
|
||||
{
|
||||
return argument;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a particular argument that has the given name. This will return null if the argument is not found. Not case
|
||||
* sensitive.
|
||||
*
|
||||
* @param argumentName the name of the argument.
|
||||
*
|
||||
* @return the argument with the given name.
|
||||
*/
|
||||
protected CommandArgument<?> getArgument(String argumentName)
|
||||
{
|
||||
argumentName = argumentName.toLowerCase();
|
||||
for (CommandArgument<?> arg : arguments)
|
||||
{
|
||||
if (arg.getName().equals(argumentName))
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a validator to be run on the player before the command itself starts processing the information.
|
||||
*
|
||||
* @param senderValidator the new validator
|
||||
*/
|
||||
protected void addSenderValidator(SenderValidator senderValidator)
|
||||
{
|
||||
senderValidators.add(senderValidator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the passed in command string matches this particular valid command,
|
||||
*
|
||||
* @param label the label of the command.
|
||||
*
|
||||
* @return {@code true} if the parameter matches the command. Otherwise, returns {@code false}.
|
||||
*/
|
||||
protected boolean matches(String label)
|
||||
{
|
||||
label = label.toLowerCase();
|
||||
if (label == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (label.equals(getName()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for (String alias : aliases)
|
||||
{
|
||||
if (label.equals(alias))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param start the start of the alias to search for.
|
||||
*
|
||||
* @return the name or alias that starts with the given string.
|
||||
*/
|
||||
protected String getMatchingAlias(String start)
|
||||
{
|
||||
start = start.toLowerCase();
|
||||
if (name.startsWith(start))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
for (String alias : aliases)
|
||||
{
|
||||
if (alias.startsWith(start))
|
||||
{
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all other names this command could be referenced by besides it's name.
|
||||
*/
|
||||
public String[] getAliases()
|
||||
{
|
||||
return aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if this command is unusable by the console unless overridden by an argument.
|
||||
*/
|
||||
public boolean blocksConsole()
|
||||
{
|
||||
return blocksConsole;
|
||||
}
|
||||
|
||||
public boolean hasPermission()
|
||||
{
|
||||
return permission != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the permission required to run this command.
|
||||
*/
|
||||
public String getPermission()
|
||||
{
|
||||
return permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description of the command. This is given to Bukkit when the command is properly registered within
|
||||
* their system. There is no method to change this, and if it is changed via reflection, that change will not be
|
||||
* reflected within Bukkit's command system.
|
||||
*
|
||||
* @return the description of the command.
|
||||
*/
|
||||
public String getDescription()
|
||||
{
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the command. This is what is used to register the command within Bukkit, as well as the
|
||||
* primary way to reference the command elsewhere. There is no method to change this, and if it is changed via
|
||||
* reflection, that change will not be reflected within Bukkit's command system.
|
||||
*
|
||||
* @return the name of the command.
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return name.toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
19
src/main/java/com/alttd/altitudeapi/commands/Validator.java
Normal file
19
src/main/java/com/alttd/altitudeapi/commands/Validator.java
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public interface Validator<T>
|
||||
{
|
||||
|
||||
/**
|
||||
* Validates that the argument is in the correct state. This should also send any and all error messages associated
|
||||
* with the problem with the argument.
|
||||
*
|
||||
* @param sender the sender of the command.
|
||||
* @param label the label of the command
|
||||
* @param arg the argument to be validated.
|
||||
* @return {@code true} if the argument is valid. {@code false} of the argument is not valid.
|
||||
*/
|
||||
public boolean validateArgument(CommandSender sender, String[] label, T arg);
|
||||
|
||||
}
|
||||
68
src/main/java/com/alttd/altitudeapi/utils/ChatUtils.java
Normal file
68
src/main/java/com/alttd/altitudeapi/utils/ChatUtils.java
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class ChatUtils
|
||||
{
|
||||
|
||||
private final static int CENTER_PX = 154;
|
||||
|
||||
public static void sendCenteredMessage(CommandSender sender, String message)
|
||||
{
|
||||
if (message == null || message.equals(""))
|
||||
{
|
||||
sender.sendMessage("");
|
||||
}
|
||||
message = ChatColor.translateAlternateColorCodes('&', message);
|
||||
|
||||
int messagePxSize = 0;
|
||||
boolean previousCode = false;
|
||||
boolean isBold = false;
|
||||
|
||||
for (char c : message.toCharArray())
|
||||
{
|
||||
if (c == ChatColor.COLOR_CHAR)
|
||||
{
|
||||
previousCode = true;
|
||||
}
|
||||
else if (previousCode)
|
||||
{
|
||||
previousCode = false;
|
||||
isBold = (c == 'l' || c == 'L');
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultFontInfo dFI = DefaultFontInfo.getDefaultFontInfo(c);
|
||||
messagePxSize += isBold ? dFI.getBoldLength() : dFI.getLength();
|
||||
messagePxSize++;
|
||||
}
|
||||
}
|
||||
|
||||
int halvedMessageSize = messagePxSize / 2;
|
||||
int toCompensate = CENTER_PX - halvedMessageSize;
|
||||
int spaceLength = DefaultFontInfo.SPACE.getLength() + 1;
|
||||
int compensated = 0;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (compensated < toCompensate)
|
||||
{
|
||||
sb.append(" ");
|
||||
compensated += spaceLength;
|
||||
}
|
||||
sender.sendMessage(sb.toString() + message);
|
||||
}
|
||||
|
||||
public static String renderString(String string, String... arguments)
|
||||
{
|
||||
if (arguments.length % 2 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Must have an even number of arguments.");
|
||||
}
|
||||
for (int i = 0; i < arguments.length; i += 2)
|
||||
{
|
||||
string = string.replace(arguments[i], arguments[i + 1]);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
||||
249
src/main/java/com/alttd/altitudeapi/utils/CollectionUtils.java
Normal file
249
src/main/java/com/alttd/altitudeapi/utils/CollectionUtils.java
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class CollectionUtils
|
||||
{
|
||||
|
||||
private final static Map<Class<?>, Method> nameMethods = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Retrieves the last value of the given list. If the list is null or it has no elements, this will always return
|
||||
* null. If the List is also a Deque, this will return the last element using {@link Deque#peekLast()}.
|
||||
*
|
||||
* @param list the list to get the last value of.
|
||||
* @param <T> the type of the list.
|
||||
*
|
||||
* @return the last value.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getLast(List<T> list)
|
||||
{
|
||||
if (list == null || list.size() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (list instanceof Deque)
|
||||
{
|
||||
return ((Deque<T>) list).peekLast();
|
||||
}
|
||||
return list.get(list.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely checks if the given collection is immutable. If the collection is mutable, the data will not be affected
|
||||
* unless the collection in question keeps track of total number of operations. The test is done by calling
|
||||
* {@link Collection#removeIf(java.util.function.Predicate)} with the predicate of {@code false}.
|
||||
*
|
||||
* @param values the collection to check.
|
||||
*
|
||||
* @return {@code true} if the collection is immutable.
|
||||
*/
|
||||
public static boolean isImmutable(Collection<?> values)
|
||||
{
|
||||
try
|
||||
{
|
||||
values.removeIf(x -> false);
|
||||
return true;
|
||||
}
|
||||
catch (UnsupportedOperationException ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given values into their string counterpart. This is done by calling {@link Object#toString()} on
|
||||
* every object. More specific use cases like {@link org.bukkit.entity.Player#getName()} etc are not compatible.
|
||||
*
|
||||
* @param values the values to convert.
|
||||
* @param <T> the type of the collection.
|
||||
*
|
||||
* @return the generated list of Strings.
|
||||
*/
|
||||
public static <T> List<String> getStringList(Collection<T> values)
|
||||
{
|
||||
if (values == null || values.size() == 0)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> list = new LinkedList<>();
|
||||
for (Object o : values)
|
||||
{
|
||||
if (o != null)
|
||||
{
|
||||
list.add(o.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
list.add(null);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of every single object passed in the values parameter. This method requires the method "getName()"
|
||||
* to exist within whatever type is passed. If it does not exist, an empty list is returned. However, in the future
|
||||
* there is a potential that it will be changed to throwing an {@link IllegalArgumentException}.
|
||||
*
|
||||
* @param values the values to get the name of.
|
||||
* @param type the type of the object.
|
||||
* @param <T> the type of the list.
|
||||
*
|
||||
* @return the list of names.
|
||||
*/
|
||||
public static <T> List<String> getNames(Collection<T> values, Class<T> type)
|
||||
{
|
||||
if (values == null || values.size() == 0)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> list = new LinkedList<>();
|
||||
|
||||
Method method = getNameMethod(type);
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
for (Object obj : values)
|
||||
{
|
||||
try
|
||||
{
|
||||
list.add((String) method.invoke(obj));
|
||||
}
|
||||
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex)
|
||||
{
|
||||
// this exception is actually going to be printed as it should never happen.
|
||||
// the method was set to accessible previously, and it should also never have any arguments.
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static Method getNameMethod(Class<?> clazz)
|
||||
{
|
||||
Method method = nameMethods.get(clazz);
|
||||
if (method == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
method = clazz.getDeclaredMethod("getName");
|
||||
method.setAccessible(true);
|
||||
nameMethods.put(clazz, method);
|
||||
}
|
||||
catch (NoSuchMethodException | SecurityException ex)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches through the given values for the first non-null value.
|
||||
*
|
||||
* @param values the values to find.
|
||||
* @param <T> the type of the array.
|
||||
*
|
||||
* @return the first non-null value.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> T firstNonNull(T... values)
|
||||
{
|
||||
for (T value : values)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given String collection into a String array.
|
||||
*
|
||||
* @param collection the collection to convert.
|
||||
*
|
||||
* @return the newly created array.
|
||||
*/
|
||||
public static String[] toArray(Collection<String> collection)
|
||||
{
|
||||
return collection.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random value from the collection. If the collection is null or empty, this will return null.
|
||||
*
|
||||
* @param collection the collection to poll.
|
||||
* @param <T> the type of the collection.
|
||||
*
|
||||
* @return a random value from the collection.
|
||||
*/
|
||||
public static <T> T randomValue(Collection<T> collection)
|
||||
{
|
||||
return randomValue(collection, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random value from the collection. If the collection is null or empty, this will return null.
|
||||
*
|
||||
* @param collection the collection to poll.
|
||||
* @param ignored any values not suitable to be included
|
||||
* @param <T> the type of the collection.
|
||||
*
|
||||
* @return a random value from the collection.
|
||||
*/
|
||||
public static <T> T randomValue(Collection<T> collection, T... ignored)
|
||||
{
|
||||
// if it's null or empty, we don't care
|
||||
if (collection == null || collection.size() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// if the ignored values aren't null, we need to make them not an option
|
||||
if (ignored != null)
|
||||
{
|
||||
collection = new ArrayList<>(collection);
|
||||
collection.removeAll(Arrays.asList(ignored));
|
||||
}
|
||||
Random random = new Random();
|
||||
|
||||
// the index to get a value from
|
||||
int index = random.nextInt(collection.size());
|
||||
|
||||
// if it's a list, we can just get it at that index, no need to iterate
|
||||
if (collection instanceof List)
|
||||
{
|
||||
return ((List<T>) collection).get(index);
|
||||
}
|
||||
|
||||
// it's not a list, time to iterate
|
||||
Iterator<? extends T> iterator = collection.iterator();
|
||||
for (int i = 0; iterator.hasNext(); i++)
|
||||
{
|
||||
if (i == index)
|
||||
{
|
||||
return iterator.next();
|
||||
}
|
||||
iterator.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
139
src/main/java/com/alttd/altitudeapi/utils/DefaultFontInfo.java
Normal file
139
src/main/java/com/alttd/altitudeapi/utils/DefaultFontInfo.java
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
public enum DefaultFontInfo
|
||||
{
|
||||
|
||||
A('A', 5),
|
||||
a('a', 5),
|
||||
B('B', 5),
|
||||
b('b', 5),
|
||||
C('C', 5),
|
||||
c('c', 5),
|
||||
D('D', 5),
|
||||
d('d', 5),
|
||||
E('E', 5),
|
||||
e('e', 5),
|
||||
F('F', 5),
|
||||
f('f', 4),
|
||||
G('G', 5),
|
||||
g('g', 5),
|
||||
H('H', 5),
|
||||
h('h', 5),
|
||||
I('I', 3),
|
||||
i('i', 1),
|
||||
J('J', 5),
|
||||
j('j', 5),
|
||||
K('K', 5),
|
||||
k('k', 4),
|
||||
L('L', 5),
|
||||
l('l', 1),
|
||||
M('M', 5),
|
||||
m('m', 5),
|
||||
N('N', 5),
|
||||
n('n', 5),
|
||||
O('O', 5),
|
||||
o('o', 5),
|
||||
P('P', 5),
|
||||
p('p', 5),
|
||||
Q('Q', 5),
|
||||
q('q', 5),
|
||||
R('R', 5),
|
||||
r('r', 5),
|
||||
S('S', 5),
|
||||
s('s', 5),
|
||||
T('T', 5),
|
||||
t('t', 4),
|
||||
U('U', 5),
|
||||
u('u', 5),
|
||||
V('V', 5),
|
||||
v('v', 5),
|
||||
W('W', 5),
|
||||
w('w', 5),
|
||||
X('X', 5),
|
||||
x('x', 5),
|
||||
Y('Y', 5),
|
||||
y('y', 5),
|
||||
Z('Z', 5),
|
||||
z('z', 5),
|
||||
NUM_1('1', 5),
|
||||
NUM_2('2', 5),
|
||||
NUM_3('3', 5),
|
||||
NUM_4('4', 5),
|
||||
NUM_5('5', 5),
|
||||
NUM_6('6', 5),
|
||||
NUM_7('7', 5),
|
||||
NUM_8('8', 5),
|
||||
NUM_9('9', 5),
|
||||
NUM_0('0', 5),
|
||||
EXCLAMATION_POINT('!', 1),
|
||||
AT_SYMBOL('@', 6),
|
||||
NUM_SIGN('#', 5),
|
||||
DOLLAR_SIGN('$', 5),
|
||||
PERCENT('%', 5),
|
||||
UP_ARROW('^', 5),
|
||||
AMPERSAND('&', 5),
|
||||
ASTERISK('*', 5),
|
||||
LEFT_PARENTHESIS('(', 4),
|
||||
RIGHT_PERENTHESIS(')', 4),
|
||||
MINUS('-', 5),
|
||||
UNDERSCORE('_', 5),
|
||||
PLUS_SIGN('+', 5),
|
||||
EQUALS_SIGN('=', 5),
|
||||
LEFT_CURL_BRACE('{', 4),
|
||||
RIGHT_CURL_BRACE('}', 4),
|
||||
LEFT_BRACKET('[', 3),
|
||||
RIGHT_BRACKET(']', 3),
|
||||
COLON(':', 1),
|
||||
SEMI_COLON(';', 1),
|
||||
DOUBLE_QUOTE('"', 3),
|
||||
SINGLE_QUOTE('\'', 1),
|
||||
LEFT_ARROW('<', 4),
|
||||
RIGHT_ARROW('>', 4),
|
||||
QUESTION_MARK('?', 5),
|
||||
SLASH('/', 5),
|
||||
BACK_SLASH('\\', 5),
|
||||
LINE('|', 1),
|
||||
TILDE('~', 5),
|
||||
TICK('`', 2),
|
||||
PERIOD('.', 1),
|
||||
COMMA(',', 1),
|
||||
SPACE(' ', 3),
|
||||
DEFAULT('a', 4);
|
||||
|
||||
private char character;
|
||||
private int length;
|
||||
|
||||
DefaultFontInfo(char character, int length)
|
||||
{
|
||||
this.character = character;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public char getCharacter()
|
||||
{
|
||||
return this.character;
|
||||
}
|
||||
|
||||
public int getLength()
|
||||
{
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public int getBoldLength()
|
||||
{
|
||||
if (this == DefaultFontInfo.SPACE)
|
||||
return this.getLength();
|
||||
return this.length + 1;
|
||||
}
|
||||
|
||||
public static DefaultFontInfo getDefaultFontInfo(char c)
|
||||
{
|
||||
for (DefaultFontInfo dFI : DefaultFontInfo.values())
|
||||
{
|
||||
if (dFI.getCharacter() == c)
|
||||
return dFI;
|
||||
}
|
||||
return DefaultFontInfo.DEFAULT;
|
||||
}
|
||||
|
||||
}
|
||||
46
src/main/java/com/alttd/altitudeapi/utils/EnumUtil.java
Normal file
46
src/main/java/com/alttd/altitudeapi/utils/EnumUtil.java
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utils for working with enums. Most of the code was taken EssentialsX.
|
||||
*
|
||||
* @author Michael Ziluck
|
||||
*/
|
||||
public class EnumUtil
|
||||
{
|
||||
/**
|
||||
* Return a set containing <b>all</b> fields of the given enum that maths one of the provided
|
||||
* names.
|
||||
*
|
||||
* @param enumClass The class to search through
|
||||
* @param names The names of the fields to search for
|
||||
* @param <T> The enum to search through
|
||||
*
|
||||
* @return All matching enum fields
|
||||
*/
|
||||
public static <T extends Enum> Set<T> getAllMatching(Class<T> enumClass, String... names)
|
||||
{
|
||||
Set<T> set = new HashSet<>();
|
||||
|
||||
for (String name : names)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field enumField = enumClass.getDeclaredField(name);
|
||||
|
||||
if (enumField.isEnumConstant())
|
||||
{
|
||||
set.add((T) enumField.get(null));
|
||||
}
|
||||
}
|
||||
catch (NoSuchFieldException | IllegalAccessException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
}
|
||||
27
src/main/java/com/alttd/altitudeapi/utils/ItemUtils.java
Normal file
27
src/main/java/com/alttd/altitudeapi/utils/ItemUtils.java
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
public class ItemUtils
|
||||
{
|
||||
private static final Set<Material> POTIONS;
|
||||
|
||||
static
|
||||
{
|
||||
POTIONS = EnumUtil.getAllMatching(Material.class, "POTION", "SPLASH_POTION", "LINGERING_POTION", "TIPPED_ARROW");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given material is a potion.
|
||||
*
|
||||
* @param material the material to check.
|
||||
*
|
||||
* @return {@code true} if the material is a potion. Otherwise returns {@code false}.
|
||||
*/
|
||||
public static boolean isPotion(Material material)
|
||||
{
|
||||
return POTIONS.contains(material);
|
||||
}
|
||||
}
|
||||
55
src/main/java/com/alttd/altitudeapi/utils/MutableEnum.java
Normal file
55
src/main/java/com/alttd/altitudeapi/utils/MutableEnum.java
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
/**
|
||||
* Designed to wrap enums to force them to behave mutably.
|
||||
*
|
||||
* @param <T> the type this MutableEnum wraps.
|
||||
*
|
||||
* @author Michael Ziluck
|
||||
*/
|
||||
public class MutableEnum<T extends Enum<T>>
|
||||
{
|
||||
|
||||
private Enum<T> value;
|
||||
|
||||
/**
|
||||
* Creates a new MutableEnum wrapper for the given value.
|
||||
*
|
||||
* @param value the value to wrap.
|
||||
*/
|
||||
public MutableEnum(T value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently wrapped value.
|
||||
*/
|
||||
public Enum<T> getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value can't be null.
|
||||
*
|
||||
* @param value the new wrapped value.
|
||||
*/
|
||||
public void setValue(T value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new NullPointerException("Value can't be null.");
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the class type of the contained Enum.
|
||||
*/
|
||||
public Class<T> getType()
|
||||
{
|
||||
return value.getDeclaringClass();
|
||||
}
|
||||
|
||||
}
|
||||
45
src/main/java/com/alttd/altitudeapi/utils/MutableString.java
Normal file
45
src/main/java/com/alttd/altitudeapi/utils/MutableString.java
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
/**
|
||||
* Designed to wrap Strings to force them to behave mutably.
|
||||
*
|
||||
* @author Michael Ziluck
|
||||
*/
|
||||
public class MutableString
|
||||
{
|
||||
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Creates a new MutableString wrapper for the given value.
|
||||
*
|
||||
* @param value the value to wrap.
|
||||
*/
|
||||
public MutableString(String value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently wrapped value.
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value can't be null.
|
||||
*
|
||||
* @param value the new wrapped value.
|
||||
*/
|
||||
public void setValue(String value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new NullPointerException("Value can't be null.");
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
60
src/main/java/com/alttd/altitudeapi/utils/MutableValue.java
Normal file
60
src/main/java/com/alttd/altitudeapi/utils/MutableValue.java
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
/**
|
||||
* Represents a mutable data type for a type that may not normally be mutable, either because it is final, primitive, or sealed.
|
||||
*
|
||||
* @param <T> the type of this mutable value.
|
||||
*/
|
||||
public class MutableValue<T>
|
||||
{
|
||||
private T value;
|
||||
|
||||
/**
|
||||
* Constructs a new MutableValue with the given object.
|
||||
*
|
||||
* @param t the value to be stored.
|
||||
*/
|
||||
public MutableValue(T t)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Value can't be null.");
|
||||
}
|
||||
|
||||
this.value = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that is currently stored. If there is no value, returns null.
|
||||
*
|
||||
* @return the value that is currently stored.
|
||||
*/
|
||||
public T getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value that is currently stored.
|
||||
*
|
||||
* @param t the new value to be stored.
|
||||
*/
|
||||
public void setValue(T t)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Value can't be null.");
|
||||
}
|
||||
this.value = t;
|
||||
}
|
||||
|
||||
public Class<T> getType()
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new IllegalStateException("Value can't be null.");
|
||||
}
|
||||
|
||||
return (Class<T>) value.getClass();
|
||||
}
|
||||
}
|
||||
157
src/main/java/com/alttd/altitudeapi/utils/StringUtils.java
Normal file
157
src/main/java/com/alttd/altitudeapi/utils/StringUtils.java
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class StringUtils
|
||||
{
|
||||
|
||||
public static String implode(String[] strings, int start, int end)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
sb.append(strings[i] + " ");
|
||||
}
|
||||
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
public static String[] add(String[] array, String add)
|
||||
{
|
||||
String[] values = new String[array.length + 1];
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
values[i] = array[i];
|
||||
}
|
||||
values[array.length] = add;
|
||||
return values;
|
||||
}
|
||||
|
||||
public static String compile(String[] strings)
|
||||
{
|
||||
return implode(strings, 0, strings.length);
|
||||
}
|
||||
|
||||
public static String capitalize(final String str)
|
||||
{
|
||||
int strLen;
|
||||
if (str == null || (strLen = str.length()) == 0)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
final int firstCodepoint = str.codePointAt(0);
|
||||
final int newCodePoint = Character.toTitleCase(firstCodepoint);
|
||||
if (firstCodepoint == newCodePoint)
|
||||
{
|
||||
// already capitalized
|
||||
return str;
|
||||
}
|
||||
|
||||
final int newCodePoints[] = new int[strLen]; // cannot be longer than
|
||||
// the char array
|
||||
int outOffset = 0;
|
||||
newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
|
||||
for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen;)
|
||||
{
|
||||
final int codepoint = str.codePointAt(inOffset);
|
||||
newCodePoints[outOffset++] = codepoint; // copy the remaining ones
|
||||
inOffset += Character.charCount(codepoint);
|
||||
}
|
||||
return new String(newCodePoints, 0, outOffset);
|
||||
}
|
||||
|
||||
public static boolean contains(String[] values, String search)
|
||||
{
|
||||
for (String val : values)
|
||||
{
|
||||
if (val.equalsIgnoreCase(search))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isNullOrEmpty(String str)
|
||||
{
|
||||
return str == null || str.length() == 0;
|
||||
}
|
||||
|
||||
public static boolean isWhitespace(String str)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final int sz = str.length();
|
||||
for (int i = 0; i < sz; i++)
|
||||
{
|
||||
if (!Character.isWhitespace(str.charAt(i)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean containsAny(String search, String... strings)
|
||||
{
|
||||
if (isNullOrEmpty(search))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (String searchCharSequence : strings)
|
||||
{
|
||||
if (indexOf(search, searchCharSequence, 0) >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int indexOf(CharSequence cs, CharSequence searchChar, int start)
|
||||
{
|
||||
return cs.toString().indexOf(searchChar.toString(), start);
|
||||
}
|
||||
|
||||
public static String formatNumber(Number number, int decimalPlaces, boolean useCommas)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (useCommas)
|
||||
{
|
||||
sb.append("#,##0");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("0");
|
||||
}
|
||||
if (decimalPlaces > 0)
|
||||
{
|
||||
sb.append('.');
|
||||
for (int i = 0; i < decimalPlaces; i++)
|
||||
{
|
||||
sb.append('0');
|
||||
}
|
||||
}
|
||||
return new DecimalFormat(sb.toString()).format(number);
|
||||
}
|
||||
|
||||
public static String doubleFormat(double number)
|
||||
{
|
||||
String formatted;
|
||||
|
||||
if (number % 1 == 0)
|
||||
{
|
||||
formatted = Integer.toString((int) number);
|
||||
}
|
||||
else
|
||||
{
|
||||
formatted = Double.toString(number);
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
|
||||
}
|
||||
22
src/main/java/com/alttd/altitudeapi/utils/VersionUtils.java
Normal file
22
src/main/java/com/alttd/altitudeapi/utils/VersionUtils.java
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package com.alttd.altitudeapi.utils;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
|
||||
public class VersionUtils
|
||||
{
|
||||
|
||||
public static void stopDrops(BlockBreakEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
event.setDropItems(false);
|
||||
}
|
||||
catch (NoSuchMethodError ex)
|
||||
{
|
||||
event.setCancelled(true);
|
||||
event.getBlock().setType(Material.AIR);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package com.alttd.altitudeapi.utils.items;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.potion.PotionData;
|
||||
|
||||
public class ItemData
|
||||
{
|
||||
private final Material material;
|
||||
|
||||
private PotionData potionData = null;
|
||||
|
||||
private EntityType entity = null;
|
||||
|
||||
public ItemData(Material material)
|
||||
{
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
public ItemData(Material material, PotionData potionData)
|
||||
{
|
||||
this.material = material;
|
||||
this.potionData = potionData;
|
||||
}
|
||||
|
||||
public ItemData(Material material, EntityType entity)
|
||||
{
|
||||
this.material = material;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public Material getMaterial()
|
||||
{
|
||||
return material;
|
||||
}
|
||||
|
||||
public PotionData getPotionData()
|
||||
{
|
||||
return this.potionData;
|
||||
}
|
||||
|
||||
public EntityType getEntity()
|
||||
{
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return (31 * material.hashCode()) ^ potionData.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!(o instanceof ItemData))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ItemData that = (ItemData) o;
|
||||
return this.material == that.getMaterial() && potionDataEquals(that) && entityEquals(that);
|
||||
}
|
||||
|
||||
private boolean potionDataEquals(ItemData o)
|
||||
{
|
||||
if (this.potionData == null && o.getPotionData() == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (this.potionData != null && o.getPotionData() != null)
|
||||
{
|
||||
return this.potionData.equals(o.getPotionData());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean entityEquals(ItemData o)
|
||||
{
|
||||
if (this.entity == null && o.getEntity() == null)
|
||||
{ // neither have an entity
|
||||
return true;
|
||||
}
|
||||
else if (this.entity != null && o.getEntity() != null)
|
||||
{ // both have an entity; check if it's the same one
|
||||
return this.entity.equals(o.getEntity());
|
||||
}
|
||||
else
|
||||
{ // one has an entity but the other doesn't, so they can't be equal
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
279
src/main/java/com/alttd/altitudeapi/utils/items/ItemDb.java
Normal file
279
src/main/java/com/alttd/altitudeapi/utils/items/ItemDb.java
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
package com.alttd.altitudeapi.utils.items;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.alttd.altitudeapi.AltitudeAPI;
|
||||
import com.alttd.altitudeapi.utils.ItemUtils;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||
import org.bukkit.inventory.meta.Damageable;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
import org.bukkit.potion.PotionData;
|
||||
|
||||
public class ItemDb
|
||||
{
|
||||
private static Gson gson = new Gson();
|
||||
|
||||
// Maps primary name to ItemData
|
||||
private final transient Map<String, ItemData> items = new HashMap<>();
|
||||
|
||||
// Maps alias to primary name
|
||||
private final transient Map<String, String> itemAliases = new HashMap<>();
|
||||
|
||||
// Every known alias
|
||||
private final transient Set<String> allAliases = new HashSet<>();
|
||||
|
||||
private transient File file;
|
||||
|
||||
private boolean ready = false;
|
||||
|
||||
public ItemDb(File file)
|
||||
{
|
||||
this.file = file;
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
public void reloadConfig()
|
||||
{
|
||||
if (file == null)
|
||||
{
|
||||
file = new File(AltitudeAPI.getInstance().getDataFolder(), "items.json");
|
||||
}
|
||||
|
||||
this.rebuild();
|
||||
AltitudeAPI.getInstance().getLogger().info(String.format("Loaded %s items from items.json.", listNames().size()));
|
||||
}
|
||||
|
||||
private void rebuild()
|
||||
{
|
||||
this.reset();
|
||||
|
||||
String json = getLines(file).stream()
|
||||
.filter(line -> !line.startsWith("#"))
|
||||
.collect(Collectors.joining());
|
||||
|
||||
this.loadJSON(String.join("\n", json));
|
||||
|
||||
ready = true;
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
ready = false;
|
||||
items.clear();
|
||||
itemAliases.clear();
|
||||
allAliases.clear();
|
||||
}
|
||||
|
||||
public void loadJSON(String source)
|
||||
{
|
||||
JsonObject map = (new JsonParser()).parse(source).getAsJsonObject();
|
||||
|
||||
for (Map.Entry<String, JsonElement> entry : map.entrySet())
|
||||
{
|
||||
String key = entry.getKey();
|
||||
JsonElement element = entry.getValue();
|
||||
boolean valid = false;
|
||||
|
||||
if (element.isJsonObject())
|
||||
{
|
||||
ItemData data = gson.fromJson(element, ItemData.class);
|
||||
items.put(key, data);
|
||||
valid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
String target = element.getAsString();
|
||||
itemAliases.put(key, target);
|
||||
valid = true;
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (valid)
|
||||
{
|
||||
allAliases.add(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
AltitudeAPI.getInstance().getLogger().warning(String.format("Failed to add item: \"%s\": %s", key, element.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ItemStack get(String id) throws Exception
|
||||
{
|
||||
id = id.toLowerCase();
|
||||
final String[] split = id.split(":");
|
||||
|
||||
ItemData data = getByName(split[0]);
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
throw new Exception("Unknown item name: " + id);
|
||||
}
|
||||
|
||||
Material material = data.getMaterial();
|
||||
|
||||
if (!material.isItem())
|
||||
{
|
||||
throw new Exception("Cannot spawn " + id + "; this is not a spawnable item.");
|
||||
}
|
||||
|
||||
ItemStack stack = new ItemStack(material);
|
||||
stack.setAmount(material.getMaxStackSize());
|
||||
|
||||
PotionData potionData = data.getPotionData();
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
|
||||
if (potionData != null && meta instanceof PotionMeta)
|
||||
{
|
||||
PotionMeta potionMeta = (PotionMeta) meta;
|
||||
potionMeta.setBasePotionData(potionData);
|
||||
}
|
||||
|
||||
// For some reason, Damageable doesn't extend ItemMeta but CB implements them in the same
|
||||
// class. As to why, your guess is as good as mine.
|
||||
if (split.length > 1 && meta instanceof Damageable)
|
||||
{
|
||||
Damageable damageMeta = (Damageable) meta;
|
||||
damageMeta.setDamage(Integer.parseInt(split[1]));
|
||||
}
|
||||
|
||||
EntityType entity = data.getEntity();
|
||||
if (entity != null && material.toString().contains("SPAWNER"))
|
||||
{
|
||||
BlockStateMeta bsm = (BlockStateMeta) meta;
|
||||
|
||||
BlockState bs = bsm.getBlockState();
|
||||
|
||||
((CreatureSpawner) bs).setSpawnedType(entity);
|
||||
|
||||
bsm.setBlockState(bs);
|
||||
}
|
||||
|
||||
stack.setItemMeta(meta);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private ItemData getByName(String name)
|
||||
{
|
||||
name = name.toLowerCase();
|
||||
if (items.containsKey(name))
|
||||
{
|
||||
return items.get(name);
|
||||
}
|
||||
else if (itemAliases.containsKey(name))
|
||||
{
|
||||
return items.get(itemAliases.get(name));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> nameList(ItemStack item)
|
||||
{
|
||||
List<String> names = new ArrayList<>();
|
||||
String primaryName = name(item);
|
||||
names.add(primaryName);
|
||||
|
||||
for (Map.Entry<String, String> entry : itemAliases.entrySet())
|
||||
{
|
||||
if (entry.getValue().equalsIgnoreCase(primaryName))
|
||||
{
|
||||
names.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
public String name(ItemStack item)
|
||||
{
|
||||
ItemData data = lookup(item);
|
||||
|
||||
for (Map.Entry<String, ItemData> entry : items.entrySet())
|
||||
{
|
||||
if (entry.getValue().equals(data))
|
||||
{
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ItemData lookup(ItemStack item)
|
||||
{
|
||||
Material type = item.getType();
|
||||
|
||||
if (ItemUtils.isPotion(type) && item.getItemMeta() instanceof PotionMeta)
|
||||
{
|
||||
PotionData potion = ((PotionMeta) item.getItemMeta()).getBasePotionData();
|
||||
return new ItemData(type, potion);
|
||||
}
|
||||
else if (type.toString().contains("SPAWNER"))
|
||||
{
|
||||
EntityType entity = ((CreatureSpawner) ((BlockStateMeta) item.getItemMeta()).getBlockState()).getSpawnedType();
|
||||
return new ItemData(type, entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ItemData(type);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<String> listNames()
|
||||
{
|
||||
return Collections.unmodifiableSet(allAliases);
|
||||
}
|
||||
|
||||
private List<String> getLines(File file)
|
||||
{
|
||||
try (final BufferedReader reader = new BufferedReader(new FileReader(file)))
|
||||
{
|
||||
final List<String> lines = new ArrayList<>(9000);
|
||||
String line = null;
|
||||
do
|
||||
{
|
||||
if ((line = reader.readLine()) == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lines.add(line);
|
||||
} while (true);
|
||||
return lines;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
1
src/main/resources/config.yml
Normal file
1
src/main/resources/config.yml
Normal file
|
|
@ -0,0 +1 @@
|
|||
use-items: false
|
||||
8976
src/main/resources/items.csv
Normal file
8976
src/main/resources/items.csv
Normal file
File diff suppressed because it is too large
Load Diff
5
src/main/resources/lang.yml
Normal file
5
src/main/resources/lang.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
only-players: "Only players can run that command."
|
||||
usage-format: "&6&lUSAGE &e» &7{message}"
|
||||
no-permission: "&4&lERROR &e» You don't have permission to do that."
|
||||
no-subs: "&4&lERROR &e» You don't have access to any sub-commands."
|
||||
header-footer: "&7&m-----------------------------------"
|
||||
4
src/main/resources/plugin.yml
Normal file
4
src/main/resources/plugin.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
main: com.alttd.altitudeapi.AltitudeAPI
|
||||
name: AltitudeAPI
|
||||
version: ${project.version}
|
||||
author: Michael Ziluck
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.alttd.altitudeapi.commands;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class CommandLangTest
|
||||
{
|
||||
private FileConfiguration config;
|
||||
|
||||
@Before
|
||||
public void setup()
|
||||
{
|
||||
File file = new File("src/main/resources/lang.yml");
|
||||
|
||||
config = YamlConfiguration.loadConfiguration(file);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_file_contains_options()
|
||||
{
|
||||
Field[] fields = CommandLang.class.getDeclaredFields();
|
||||
|
||||
for (Field field : fields)
|
||||
{
|
||||
if (Modifier.isStatic(field.getModifiers()))
|
||||
{
|
||||
assertTrue("Missing value in file: " + field.getName(), config.contains(field.getName().toLowerCase().replace("_", "-")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user