Commands API implemented. Still a WIP.

Commands work and tab complete works somewhat. 
Help still needs to be done. Added in NotSetup And PluginConfig to just
make the plugin work. It's fine to remove them when there is a working
alternative.
This commit is contained in:
Tastybento 2017-12-22 17:26:05 -08:00
parent bd3427fffe
commit c5262e8faa
13 changed files with 379 additions and 62 deletions

View File

@ -1,5 +1,7 @@
package us.tastybento.bskyblock;
import java.io.File;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.PluginManager;
@ -8,6 +10,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import us.tastybento.bskyblock.api.BSModule;
import us.tastybento.bskyblock.commands.AdminCommand;
import us.tastybento.bskyblock.commands.IslandCommand;
import us.tastybento.bskyblock.config.PluginConfig;
import us.tastybento.bskyblock.config.Settings;
import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.managers.PlayersManager;
@ -20,8 +23,6 @@ import us.tastybento.bskyblock.managers.LocalesManager;
import us.tastybento.bskyblock.util.Util;
import us.tastybento.bskyblock.util.nms.NMSAbstraction;
import java.io.File;
/**
* Main BSkyBlock class - provides an island minigame in the sky
* @author Tastybento
@ -47,7 +48,7 @@ public class BSkyBlock extends JavaPlugin implements BSModule {
plugin = this;
// Load configuration and locales. If there are no errors, load the plugin.
//if(PluginConfig.loadPluginConfig(this)){
if(PluginConfig.loadPluginConfig(this)){
playersManager = new PlayersManager(this);
islandsManager = new IslandsManager(this);
@ -124,7 +125,7 @@ public class BSkyBlock extends JavaPlugin implements BSModule {
});
}
});
//}
}
}
private void registerListeners() {

View File

@ -8,29 +8,29 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.managers.PlayersManager;
import us.tastybento.bskyblock.database.managers.island.IslandsManager;
import us.tastybento.bskyblock.util.Util;
/**
* BSB composite command
* @author ben, poslovich
*
*/
public abstract class CompositeCommand extends Command implements PluginIdentifiableCommand, TabCompleter {
private String helpReference;
public abstract class CompositeCommand extends Command implements PluginIdentifiableCommand {
private static final boolean DEBUG = true;
private boolean onlyPlayer = false;
private final CompositeCommand parent;
private String permission = "";
protected BSkyBlock plugin = BSkyBlock.getPlugin();
public BSkyBlock plugin = BSkyBlock.getPlugin();
private Map<String, CompositeCommand> subCommands;
@ -46,10 +46,11 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
// Add this sub-command to the parent
parent.getSubCommands().put(label, this);
this.setAliases(new ArrayList<>(Arrays.asList(aliases)));
this.subCommands = new LinkedHashMap<>();
this.setup();
if (DEBUG)
Bukkit.getLogger().info("DEBUG: registering command " + label);
}
@ -74,31 +75,54 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
*/
@Override
public boolean execute(CommandSender sender, String label, String[] args) {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: executing command " + label);
// Get the User instance for this sender
User user = User.getInstance(sender);
// Check permissions
if (user.hasPermission(permission)) {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: sender has permission");
// Do the player part
if (onlyPlayer && user.isPlayer()) {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: sender is a player and command requires players");
// Find the subCommand
CompositeCommand subCommand = this;
// Run through any arguments
for (int i = 0; i < args.length; i++) {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: Running through args: " + args.toString());
if (args.length > 0) {
for (int i = 0; i <= args.length; i++) {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: Argument " + i);
// get the subcommand corresponding to the arg
if (subCommand.hasSubCommmands()) {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: This command has subcommands");
if (subCommand.hasSubCommand(args[i])) {
// Step down one
subCommand = subCommand.getSubCommand(args[i]);
if (DEBUG)
Bukkit.getLogger().info("DEBUG: Moved to " + subCommand.getLabel());
} else {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: Unknown command");
// Unknown command
user.sendMessage("general.errors.unknown-command");
return true;
}
} else {
// We are at the end of the walk
if (DEBUG)
Bukkit.getLogger().info("DEBUG: End of traversal, checking perms");
// Check permission
if (user.hasPermission(subCommand.getPermission())) {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: player has perm");
if (onlyPlayer && user.isPlayer()) {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: subcommand is for player's only - executing with args " + Arrays.copyOfRange(args, i, args.length));
// Execute the subcommand with trimmed args
subCommand.execute(user, Arrays.copyOfRange(args, i, args.length));
} else {
@ -110,6 +134,11 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
}
// else continue the loop
}
} else {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: no args, just execute");
execute(user, args);
}
} else {
user.sendMessage("general.errors.use-in-game");
}
@ -191,9 +220,9 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
private List<String> getSubCommandHelp(String helpRef) {
CompositeCommand subCommand = this;
List<String> result = new ArrayList<>();
result.add(helpRef + " " + helpReference);
result.add(helpRef + " " + getDescription());
while (subCommand.hasSubCommmands()) {
result.addAll(subCommand.getSubCommandList(helpReference));
result.addAll(subCommand.getSubCommandList(getDescription()));
}
return result;
}
@ -266,17 +295,13 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
return (user.getPlayer() instanceof Player);
}
@Override
public List<String> onTabComplete(final CommandSender sender, final Command command, final String label, final String[] args) {
return new ArrayList<>(subCommands.keySet());
}
/**
* Set the locale string that gives help for this command
* @param helpReference
*/
public void setHelp(String helpReference) {
this.helpReference = helpReference;
@Override
public List<String> tabComplete(final CommandSender sender, final String alias, final String[] args) {
plugin.getLogger().info("DEBUG: tab complete " + subCommands.keySet().toString());
final List<String> options = new ArrayList<>(subCommands.keySet());
String lastArg = (args.length != 0 ? args[args.length - 1] : "");
return Util.tabLimit(options, lastArg);
}
public void setOnlyPlayer(boolean onlyPlayer) {

View File

@ -180,7 +180,12 @@ public class User {
* @param message - the message to send
*/
public void sendLegacyMessage(String message) {
if (sender != null) {
sender.sendMessage(message);
} else {
// TODO: Offline message
// Save this message so the player can see it later
}
}
public void setGameMode(GameMode mode) {

View File

@ -30,6 +30,7 @@ public class IslandCommand extends CompositeCommand {
*/
@Override
public void setup() {
// Set up subcommands
new IslandAboutCommand(this);
new IslandCreateCommand(this);
new IslandGoCommand(this);
@ -37,6 +38,7 @@ public class IslandCommand extends CompositeCommand {
new IslandResetnameCommand(this);
new IslandSethomeCommand(this);
new IslandSetnameCommand(this);
// Team commands
new IslandTeamCommand(this);
new IslandTeamInviteCommand(this);
new IslandInviteAcceptCommand(this);

View File

@ -5,9 +5,6 @@ package us.tastybento.bskyblock.commands.island;
import java.io.IOException;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import us.tastybento.bskyblock.api.commands.CompositeCommand;
import us.tastybento.bskyblock.api.commands.User;
import us.tastybento.bskyblock.api.events.island.IslandEvent.Reason;
@ -38,6 +35,7 @@ public class IslandCreateCommand extends CompositeCommand {
if (getPlayers().inTeam(user.getUniqueId())) {
return false;
}
user.sendLegacyMessage("Creating island...");
createIsland(user);
return true;
}

View File

@ -20,6 +20,7 @@ public class IslandResetCommand extends CompositeCommand {
super(command, "reset", "restart");
this.setPermission(Settings.PERMPREFIX + "island.create");
this.setOnlyPlayer(true);
this.setUsage("island.reset.usage");
}
@Override

View File

@ -22,6 +22,7 @@ public class IslandResetnameCommand extends CompositeCommand {
super(command, "setname");
this.setPermission(Settings.PERMPREFIX + "island.name");
this.setOnlyPlayer(true);
this.setUsage("island.setname.usage");
}

View File

@ -8,7 +8,6 @@ import java.util.UUID;
import org.apache.commons.lang.math.NumberUtils;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.PermissionAttachmentInfo;
@ -135,7 +134,7 @@ public class IslandTeamInviteCommand extends AbstractIslandTeamCommand {
}
@Override
public List<String> onTabComplete(final CommandSender sender, final Command command, final String label, final String[] args) {
public List<String> tabComplete(final CommandSender sender, final String alias, final String[] args) {
User user = User.getInstance(sender);
if (args.length == 0 || !isPlayer(user)) {
// Don't show every player on the server. Require at least the first letter

View File

@ -5,7 +5,6 @@ import java.util.List;
import java.util.UUID;
import org.apache.commons.lang.math.NumberUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.PermissionAttachmentInfo;
@ -131,7 +130,7 @@ public class IslandTeamPromoteCommand extends AbstractIslandTeamCommand {
}
@Override
public List<String> onTabComplete(final CommandSender sender, final Command command, final String label, final String[] args) {
public List<String> tabComplete(final CommandSender sender, final String alias, final String[] args) {
User user = User.getInstance(sender);
List<String> result = new ArrayList<>();
for (UUID member : plugin.getIslands().getMembers(user.getUniqueId())) {

View File

@ -0,0 +1,76 @@
package us.tastybento.bskyblock.config;
import java.util.List;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import us.tastybento.bskyblock.BSkyBlock;
/**
* This class runs when the config file is not set up enough, or is unsafe.
* It provides useful information to the admin on what is wrong.
*
* @author Tastybento
* @author Poslovitch
*/
public class NotSetup implements CommandExecutor{
public enum ConfigError {
DIFFERENT_WORLDNAME(0, 001),
DIFFERENT_ISLAND_DISTANCE(0, 002),
PROTECTION_RANGE_HIGHER_THAN_ISLAND_DISTANCE(1, 101),
UNKNOWN_LANGUAGE(2, 201),
NOT_CHUNK_ISLAND_DISTANCE(2, 202),
NOT_EVEN_PROTECTION_RANGE(2, 203),
PURGE_ISLAND_LEVEL_TOO_LOW(3, 301),
ISLAND_DISTANCE_TOO_LOW(3, 302),
PROTECTION_RANGE_TOO_LOW(3, 303),
ISLAND_HEIGHT_TOO_LOW(3, 304),
NETHER_SPAWN_RADIUS_TOO_LOW(3, 305),
NETHER_SPAWN_RADIUS_TOO_HIGH(3, 306);
/*
* Priority:
* 0 - CRITICAL
* 1 - HIGH
* 2 - MEDIUM
* 3 - LOW
*/
private int priority;
private int id;
ConfigError(int priority, int id){
this.priority = priority;
this.id = id;
}
public static ConfigError getById(int id){
for(ConfigError e : ConfigError.values()){
if(e.id == id) return e;
}
return null;
}
}
private BSkyBlock plugin;
private List<Error> errors;
/**
* Handles plugin operation if a critical config-related issue happened
*
* @param plugin
* @param errors
*/
public NotSetup(BSkyBlock plugin, List<Error> errors){
this.plugin = plugin;
this.errors = errors;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
return true;
}
}

View File

@ -0,0 +1,140 @@
package us.tastybento.bskyblock.config;
import java.util.HashMap;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.config.NotSetup.ConfigError;
import us.tastybento.bskyblock.database.BSBDatabase.DatabaseType;
import us.tastybento.bskyblock.database.objects.Island.SettingsFlag;
/**
* Loads the plugin configuration and the locales.
* Also provides
*
* @author Tastybento
* @author Poslovitch
*/
public class PluginConfig {
/**
* Loads the plugin configuration and the locales.
* If there were errors, it setups the commands as "NotSetup" and generates a debug for admins to fix their configuration.
* @return true if there wasn't any error, otherwise false.
*/
public static boolean loadPluginConfig(BSkyBlock plugin) {
plugin.saveDefaultConfig();
// Initialize the errors list
HashMap<ConfigError, Object> errors = new HashMap<>();
//TODO config version
// The order in this file should match the order in config.yml so that it's easy to check that everything is covered
// ********************* General *********************
Settings.metrics = plugin.getConfig().getBoolean("general.metrics", true);
Settings.checkUpdates = plugin.getConfig().getBoolean("general.check-updates", true);
//loadLocales(plugin);
Settings.defaultLanguage = plugin.getConfig().getString("general.default-language", "en-US");
//if(!plugin.getLocales().containsKey(Settings.defaultLanguage)) errors.put(ConfigError.UNKNOWN_LANGUAGE, Settings.defaultLanguage);
Settings.useEconomy = plugin.getConfig().getBoolean("general.use-economy", true);
Settings.startingMoney = plugin.getConfig().getDouble("general.starting-money", 10.0);
//Settings.useControlPanel = plugin.getConfig().getBoolean("general.use-control-panel", true);
// Purge
Settings.purgeMaxIslandLevel = plugin.getConfig().getInt("general.purge.max-island-level", 50);
if(Settings.purgeMaxIslandLevel < 0) errors.put(ConfigError.PURGE_ISLAND_LEVEL_TOO_LOW, Settings.purgeMaxIslandLevel);
Settings.purgeRemoveUserData = plugin.getConfig().getBoolean("general.purge.remove-user-data", false);
// Database
String dbType = plugin.getConfig().getString("general.database.type","FLATFILE");
boolean found = false;
for (DatabaseType type: DatabaseType.values()) {
if (type.name().equals(dbType.toUpperCase())) {
Settings.databaseType = type;
found = true;
break;
}
}
if (!found) {
plugin.getLogger().severe("Database type not found! Using FLATFILE");
Settings.databaseType = DatabaseType.FLATFILE;
}
Settings.dbHost = plugin.getConfig().getString("general.database.host", "localhost");
Settings.dbPort = plugin.getConfig().getInt("general.database.port",3306);
Settings.dbName = plugin.getConfig().getString("general.database.name", "BSkyBlock");
Settings.dbUsername = plugin.getConfig().getString("general.database.username");
Settings.dbPassword = plugin.getConfig().getString("general.database.password");
Settings.recoverSuperFlat = plugin.getConfig().getBoolean("general.recover-super-flat", false);
Settings.muteDeathMessages = plugin.getConfig().getBoolean("general.mute-death-messages", false);
//Settings.ftbAutoActivator = plugin.getConfig().getBoolean("general.FTB-auto-activator", false);
Settings.allowObsidianScooping = plugin.getConfig().getBoolean("general.allow-obsidian-scooping", true);
// Allow teleport
//Settings.fallingAllowTeleport = plugin.getConfig().getBoolean("general.allow-teleport.falling", true);
//Settings.fallingBlockedCommands = plugin.getConfig().getStringList("general.allow-teleport.falling-blocked-commands");
//Settings.acidAllowTeleport = plugin.getConfig().getBoolean("general.allow-teleport.acid", true);
//Settings.acidBlockedCommands = plugin.getConfig().getStringList("general.allow-teleport.acid-blocked-commands");
// ********************* World *********************
Settings.worldName = plugin.getConfig().getString("world.world-name", "BSkyBlock_world");
//TODO check if it is the same than before
int distance = plugin.getConfig().getInt("world.distance", 208);
Settings.islandDistance = Math.round((long)distance/16) * 16;
if(distance < 48) errors.put(ConfigError.ISLAND_DISTANCE_TOO_LOW, Settings.islandDistance);
Settings.islandProtectionRange = plugin.getConfig().getInt("world.protection-range", 100);
if(Settings.islandProtectionRange < 0) errors.put(ConfigError.PROTECTION_RANGE_TOO_LOW, Settings.islandProtectionRange);
if(Settings.islandProtectionRange > Settings.islandDistance) errors.put(ConfigError.PROTECTION_RANGE_HIGHER_THAN_ISLAND_DISTANCE, Settings.islandProtectionRange);
//Settings.startX = plugin.getConfig().getInt("world.start-x", 0);
//Settings.startZ = plugin.getConfig().getInt("world.start-z", 0);
Settings.islandHeight = plugin.getConfig().getInt("world.island-height", 120);
if(Settings.islandHeight < 5) errors.put(ConfigError.ISLAND_HEIGHT_TOO_LOW, Settings.islandHeight);
Settings.seaHeight = plugin.getConfig().getInt("world.sea-height", 0);
Settings.maxIslands = plugin.getConfig().getInt("world.max-islands", 0);
// Nether
Settings.netherGenerate = plugin.getConfig().getBoolean("world.nether.generate", true);
Settings.netherIslands = plugin.getConfig().getBoolean("world.nether.islands", true);
Settings.netherTrees = plugin.getConfig().getBoolean("world.nether.trees", true);
Settings.netherRoof = plugin.getConfig().getBoolean("world.nether.roof", true);
Settings.netherSpawnRadius = plugin.getConfig().getInt("world.nether.spawn-radius", 25);
if(!Settings.netherIslands){
// If the nether is vanilla
if(Settings.netherSpawnRadius < 0) errors.put(ConfigError.NETHER_SPAWN_RADIUS_TOO_LOW, Settings.netherSpawnRadius);
if(Settings.netherSpawnRadius > 100) errors.put(ConfigError.NETHER_SPAWN_RADIUS_TOO_HIGH, Settings.netherSpawnRadius);
}
// TODO: add to config
Settings.endGenerate = true;
Settings.endIslands = false;
Settings.limitedBlocks = new HashMap<>();
Settings.defaultWorldSettings = new HashMap<>();
for (SettingsFlag flag: SettingsFlag.values()) {
Settings.defaultWorldSettings.put(flag, false);
}
Settings.defaultWorldSettings.put(SettingsFlag.ANIMAL_SPAWN, true);
Settings.defaultWorldSettings.put(SettingsFlag.MONSTER_SPAWN, true);
// Team
Settings.maxTeamSize = plugin.getConfig().getInt("island.max-team-size", 4);
//Settings.leaveConfirmation = plugin.getConfig().getBoolean("require-confirmation.leave", true);
//Settings.leaveConfirmWait = plugin.getConfig().getLong("require-confirmation.leave-wait", 10) * 20;
//TODO end loading
//TODO not setup error report
return true;
}
public static void loadLocales(BSkyBlock plugin){
//TODO Imperatively load en-US locale
}
}

View File

@ -0,0 +1,69 @@
package bskyblock;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import us.tastybento.bskyblock.api.commands.CompositeCommand;
import us.tastybento.bskyblock.api.commands.User;
import us.tastybento.bskyblock.commands.IslandCommand;
import us.tastybento.bskyblock.config.Settings;
public class TestIslandCommand {
private final UUID playerUUID = UUID.randomUUID();
@Before
public void setUp() {
//Plugin plugin = mock(Plugin.class);
//Mockito.doReturn(plugin).when(BSkyBlock.getPlugin());
//Mockito.when().thenReturn(plugin);
World world = mock(World.class);
//Mockito.when(world.getWorldFolder()).thenReturn(worldFile);
Server server = mock(Server.class);
Mockito.when(server.getLogger()).thenReturn(Logger.getAnonymousLogger());
Mockito.when(server.getWorld("world")).thenReturn(world);
Mockito.when(server.getVersion()).thenReturn("TestTestMocking");
Mockito.when(server.getVersion()).thenReturn("TestTestMocking");
Bukkit.setServer(server);
Mockito.when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
//Mockito.doReturn(Logger.getAnonymousLogger()).when(plugin.getLogger());
}
@Test
public void command() {
IslandCommand islandCommand = new IslandCommand();
User user = User.getInstance(playerUUID);
// Test basic execution
assertEquals(islandCommand.execute(user, null), true);
assertEquals(islandCommand.getLabel(), Settings.ISLANDCOMMAND);
assertEquals(islandCommand.getAliases().size(), 1);
assertEquals(islandCommand.getAliases().get(0), "is");
assertEquals(islandCommand.isOnlyPlayer(), true);
assertEquals(islandCommand.getParent(), null);
//TODO: assertEquals(islandCommand.getPermission(), "");
// Check commands and aliases match to correct class
for (Entry<String, CompositeCommand> command : islandCommand.getSubCommands().entrySet()) {
assertEquals(islandCommand.getSubCommand(command.getKey()), command.getValue());
// Check aliases
for (String alias : command.getValue().getAliases()) {
assertEquals(islandCommand.getSubCommand(alias), command.getValue());
}
}
}
}

View File

@ -22,6 +22,7 @@ public class TestTest {
@Before
public void setUp() {
/*
World world = mock(World.class);
@ -33,9 +34,10 @@ public class TestTest {
Mockito.when(server.getVersion()).thenReturn("TestTestMocking");
Mockito.when(server.getVersion()).thenReturn("TestTestMocking");
Bukkit.setServer(server);
*/
}
/*
@Test
public void createAndSave() {
@ -47,6 +49,5 @@ public class TestTest {
.build();
assertEquals(playerUUID, event.getPlayerUUID());
}
}*/
}