From a009dd3730e12d32a2b1eecffe63cf9d354562b0 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 19 Feb 2018 00:46:09 +0100 Subject: [PATCH] Added some things, needs testing Supporting two block creations: using block looked at Only allowing for OPs Using a method to get all vanilla commands (with the prefix of "minecraft") Updated readme Running command from command block, not the player --- README.md | 17 ++- README_hu.md | 17 ++- pom.xml | 8 +- .../norbipeti/onecommandhelper/Commands.java | 110 +++++++++--------- .../onecommandhelper/PluginMain.java | 11 +- plugin.yml => src/main/resources/plugin.yml | 8 +- src/test/java/CommandTestTest.java | 67 +++++++++++ 7 files changed, 170 insertions(+), 68 deletions(-) rename plugin.yml => src/main/resources/plugin.yml (89%) create mode 100644 src/test/java/CommandTestTest.java diff --git a/README.md b/README.md index b01ee2a..83bde2c 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,26 @@ English / [Magyar](https://github.com/NorbiPeti/OneCommandHelper/blob/master/README_hu.md) # OneCommandHelper -A plugin that allows one command creations to work on Spigot/Bukkit. +A plugin that allows one (or multiple) command creations to work on Spigot/Bukkit. +This is needed because the plugins installed on the server may have a command which replaces a vanilla command, and the plugin's version may not work the same way. + +Let's take /kill as an example. +Essentials has a /kill command, so if you use that plugin, it takes over, so every time you run /kill, it runs that one. +However, that command doesn't know about selectors, so something like `/kill @a[r=1]` wouldn't work with it. + +But, there is a syntax in Bukkit, `/plugin:command`, which allows running a specific plugin's command - or Minecraft's. +So simply running `/minecraft:kill` deals with the issue. + +But this isn't typically done in one command creations, it'd greatly limit the command length anyways. +So, this plugin does it. ## Installation Put the downloaded ([see Releases at top or click here](https://github.com/NorbiPeti/OneCommandHelper/releases)) JAR file into the server's plugin directory. No configuration needed. ## Usage -Paste the command into a command block, but *do not power it*. Instead, stand on it, and run /occ in the chat. +Paste the command into a command block, but *do not power it*. Instead, look at it, and run /occ in the chat. + +In case of multiple commands, look at the one the command's creator said to activate. ## Video [![Video](http://img.youtube.com/vi/rfPeuj0NWVg/0.jpg)](http://www.youtube.com/watch?v=rfPeuj0NWVg) diff --git a/README_hu.md b/README_hu.md index df5c636..a248cb1 100644 --- a/README_hu.md +++ b/README_hu.md @@ -1,13 +1,26 @@ [English](https://github.com/NorbiPeti/OneCommandHelper/blob/master/README.md) / Magyar # OneCommandHelper -Egy plugin, ami működőképessé teszi az egy parancsos alkotásokat Spigot/Bukkit szervereken. +Egy plugin, ami működőképessé teszi az egy (vagy több) parancsos alkotásokat Spigot/Bukkit szervereken. +Erre azért van szükség, mert a szerverekre telepített pluginoknak lehet olyan parancsuk, ami lecserél egy beépített parancsot. + +Vegyül például a /kill parancsot. +Az Essentialsnak van /kill parancsa, ezért ha használod azt a plugint, minden alkalommal, amikor lefuttatod a /kill prancsot, azt futtatja le. +Ugyanakkor az a parancs nem ismeri a szelektorokat, ezért pl. a `/kill @a[r=1]` parancs nem működne vele. + +De van egy szintaxis a Bukkitban, `/plugin:parancs`, ami lehetővé teszi egy bizonyos plugin - vagy a Minecraft - parancsának a futtatását. +Így egyszerűen a `/minecraft:kill` futtatása megoldja a problémát. + +De ezt általában nem teszik meg az egy parancsos alkotásookban, nagy mértékben korlátozná a parancs hosszúságát egyébként is. +Úgyhogy ez a plugin megcsinálja. ## Telepítés Rakd a letöltött ([lásd Releases felül vagy kattints ide](https://github.com/NorbiPeti/OneCommandHelper/releases)) JAR fájlt a szerver plugins mappába. Konfiguráció nem szükséges. ## Használat -Illeszd be a parancsot egy parancsblokkba, de *ne aktiváld*, helyette állj a parancsblokkra és írd be a /occ parancsot. +Illeszd be a parancsot egy parancsblokkba, de *ne aktiváld*, helyette nézz rá a parancsblokkra és írd be a /occ parancsot. + +Több parancs esetében arra nézz, amelyiket aktiválni kell a parancs készítője szerint. ## Videó [![Video](http://img.youtube.com/vi/rfPeuj0NWVg/0.jpg)](http://www.youtube.com/watch?v=rfPeuj0NWVg) diff --git a/pom.xml b/pom.xml index 08dc0cd..a415810 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,7 @@ maven-compiler-plugin + 3.7.0 1.8 1.8 @@ -22,7 +23,7 @@ -spigot + spigot https://hub.spigotmc.org/nexus/content/repositories/snapshots/ @@ -33,5 +34,10 @@ spigot-api 1.12.2-R0.1-SNAPSHOT + + org.mockito + mockito-all + 2.0.2-beta + \ No newline at end of file diff --git a/src/main/java/io/github/norbipeti/onecommandhelper/Commands.java b/src/main/java/io/github/norbipeti/onecommandhelper/Commands.java index e2f0470..9108718 100644 --- a/src/main/java/io/github/norbipeti/onecommandhelper/Commands.java +++ b/src/main/java/io/github/norbipeti/onecommandhelper/Commands.java @@ -1,5 +1,6 @@ package io.github.norbipeti.onecommandhelper; +import com.google.common.collect.Sets; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; @@ -9,59 +10,62 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.help.HelpTopic; +import org.bukkit.help.IndexHelpTopic; -public class Commands implements CommandExecutor -{ - private final String[] replacecmds = { "achievement", "ban", "ban-ip", - "banlist", "blockdata", "clear", "clone", "debug", - "defaultgamemode", "deop", "difficulty", "effect", "enchant", - "entitydata", "execute", "fill", "gamemode", "gamerule", "give", - "help", "kick", "kill", "list", "me", "op", "pardon", "particle", - "playsound", "publish", "replaceitem", "save", "save-all", - "save-off", "save-on", "say", "scoreboard", "seed", "setblock", - "setidletimeout", "setworldspawn", "spawnpoint", "spreadplayers", - "stats", "stop", "stopsound", "summon", "teleport", "tell", - "tellraw", "testfor", "testforblock", "testforblocks", "time", - "title", "toggledownfall", "tp", "trigger", "weather", "whitelist", - "worldborder", "xp", "commands", "banip", "broadcast", "home", - "setspawn", "unban" }; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Collection; - @Override - public boolean onCommand(CommandSender sender, Command cmd, String alias, - String[] args) - { - StringBuilder acmdb = new StringBuilder("minecraft:execute " - + sender.getName() + " ~ ~ ~ "); - if (sender != Bukkit.getConsoleSender() - && !(sender instanceof BlockCommandSender)) - { - Block block = ((Player) sender).getLocation().subtract(0, 1, 0) - .getBlock(); - if (block.getType() != Material.COMMAND) - { - sender.sendMessage("§cError! Block underneath must be command block! Found " - + block.getType()); - return true; - } - CommandBlock cmdblock = (CommandBlock) block.getState(); - acmdb.append(cmdblock.getCommand()); - } else - { - if (args.length == 0) - { - sender.sendMessage("§cUsage: /" + alias + " "); - return true; //Why use the builtin usage shoing thing - } - } - String acmd = acmdb.toString(); - StringBuilder replace = new StringBuilder("(" + replacecmds[0]); - for (int i = 1; i < replacecmds.length; i++) - replace.append("|").append(replacecmds[i]); - replace.append(")"); - acmd = acmd.replaceAll("([^t]|^)( |:| /|:/)" + replace + " ", - "$1$2minecraft:$3 ").replaceAll("\" (/*)minecraft:", - "\"$1minecraft:"); //Tellraw - Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), acmd); - return true; - } +public class Commands implements CommandExecutor { + @Override + public boolean onCommand(CommandSender sender, Command cmd, String alias, + String[] args) { + if (!sender.isOp()) { + sender.sendMessage("§cYou need to be an OP to use this command."); + return true; + } + StringBuilder acmdb = new StringBuilder("minecraft:execute "); + acmdb.append(sender.getName()).append(" "); + if (sender instanceof Player) { + Block block = ((Player) sender).getTargetBlock(null, 10); + if (block == null) { + sender.sendMessage("§cYou need to look at the command block you want to activate. Make sure you're within 10 blocks of it."); + return true; + } + if (block.getType() != Material.COMMAND) { + sender.sendMessage("§cError! You need to look at a command block. Found " + + block.getType()); + return true; + } + CommandBlock cmdblock = (CommandBlock) block.getState(); + acmdb.append(block.getX()).append(" ").append(block.getY()).append(" ").append(block.getZ()).append(" "); + acmdb.append(cmdblock.getCommand()); + } else { + sender.sendMessage("§cYou need to be a player and look at the command block where you have the command you need to run."); + return true; + } + String acmd = acmdb.toString(); + IndexHelpTopic iht = (IndexHelpTopic) Bukkit.getHelpMap().getHelpTopic("Minecraft"); + String[] replacecmds; + try { //Get Minecraft (vanilla) commands + Field f = iht.getClass().getDeclaredField("allTopics"); + f.setAccessible(true); + replacecmds = ((Collection) f.get(iht)).stream().map(ht -> ht.getName().substring(1)).toArray(String[]::new); + System.out.println(Arrays.toString(replacecmds)); //TODO: Fallback method + } catch (Exception e) { + sender.sendMessage("§cAn error occured while getting commands!"); + e.printStackTrace(); + return true; + } + StringBuilder replace = new StringBuilder("(").append(replacecmds[0]); + for (int i = 1; i < replacecmds.length; i++) + replace.append("|").append(replacecmds[i]); + replace.append(")"); + acmd = acmd.replaceAll("([^t]|^)( |:| /|:/)" + replace + " ", + "$1$2minecraft:$3 ").replaceAll("\" (/*)minecraft:", + "\"$1minecraft:"); //Tellraw + Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), acmd); + return true; + } } diff --git a/src/main/java/io/github/norbipeti/onecommandhelper/PluginMain.java b/src/main/java/io/github/norbipeti/onecommandhelper/PluginMain.java index 260c2de..bafaaab 100644 --- a/src/main/java/io/github/norbipeti/onecommandhelper/PluginMain.java +++ b/src/main/java/io/github/norbipeti/onecommandhelper/PluginMain.java @@ -2,10 +2,9 @@ package io.github.norbipeti.onecommandhelper; import org.bukkit.plugin.java.JavaPlugin; -public class PluginMain extends JavaPlugin -{ - @Override - public void onEnable() { - getCommand("occ").setExecutor(new Commands()); - } +public class PluginMain extends JavaPlugin { + @Override + public void onEnable() { + getCommand("occ").setExecutor(new Commands()); + } } diff --git a/plugin.yml b/src/main/resources/plugin.yml similarity index 89% rename from plugin.yml rename to src/main/resources/plugin.yml index 56df368..532eadc 100644 --- a/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ -name: OneCommandHelper -main: io.github.norbipeti.onecommandhelper.PluginMain -version: 1.0 -commands: +name: OneCommandHelper +main: io.github.norbipeti.onecommandhelper.PluginMain +version: 1.0 +commands: occ: \ No newline at end of file diff --git a/src/test/java/CommandTestTest.java b/src/test/java/CommandTestTest.java new file mode 100644 index 0000000..16322bc --- /dev/null +++ b/src/test/java/CommandTestTest.java @@ -0,0 +1,67 @@ +import io.github.norbipeti.onecommandhelper.Commands; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.CommandBlock; +import org.bukkit.entity.Player; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.logging.Logger; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +public class CommandTestTest { //Nope. See below. + @Test + public void test() { + Bukkit.setServer(Mockito.mock(Server.class, new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + if (is(invocationOnMock, String.class)) + return "test"; + if (is(invocationOnMock, Logger.class)) + return Logger.getLogger("Test"); + if (invocationOnMock.getMethod().getName().equals("sendMessage")) { + System.out.println(Arrays.toString(invocationOnMock.getArguments())); + return null; + } + if (!Modifier.isAbstract(invocationOnMock.getMethod().getModifiers())) + return invocationOnMock.callRealMethod(); + return null; + } + })); + Commands cmds = new Commands(); + cmds.onCommand(Mockito.mock(Player.class, new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + if (is(invocationOnMock, boolean.class)) + return true; + if (is(invocationOnMock, Block.class)) + return Mockito.mock(Block.class, new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + if (is(invocationOnMock, Material.class)) + return Material.COMMAND; + if (is(invocationOnMock, BlockState.class)) + return Mockito.mock(CommandBlock.class); + return null; //Nope. The help topics would need to be added too. + } + }); + System.out.println(invocationOnMock.getMethod().getName()); + System.out.println(Arrays.toString(invocationOnMock.getArguments())); + return null; + } + }), null, "occ", new String[]{}); + } + + private boolean is(InvocationOnMock invocationOnMock, Class cl) { + return invocationOnMock.getMethod().getReturnType().isAssignableFrom(cl); + } +} \ No newline at end of file