Implement support for commands as things.

With CommandThing and its parser, it is now possible to use commands anywhere a thing can be used. Commands are invoked as the console/server, and they support a single variable, the name of the recipient player.

Commands are give-only, meaning they will fail to be "taken" from players, and they cannot be "held" either. The idea of commands as things basically only makes sense in the context of rewards.
This commit is contained in:
Andreas Troelsen 2017-11-19 19:46:36 +01:00
parent 6e57c018b5
commit 56e83bdaf3
4 changed files with 226 additions and 0 deletions

View File

@ -0,0 +1,68 @@
package com.garbagemule.MobArena.things;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.Objects;
public class CommandThing implements Thing {
private final String command;
private final String title;
public CommandThing(String command) {
this(command, null);
}
public CommandThing(String command, String title) {
this.command = trimSlash(command);
this.title = title;
}
@Override
public boolean giveTo(Player player) {
return Bukkit.getServer().dispatchCommand(
Bukkit.getConsoleSender(),
command.replace("<player>", player.getName())
);
}
@Override
public boolean takeFrom(Player player) {
return false;
}
@Override
public boolean heldBy(Player player) {
return false;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof CommandThing)) return false;
CommandThing other = (CommandThing) o;
return Objects.equals(command, other.command)
&& Objects.equals(title, other.title);
}
@Override
public int hashCode() {
return Objects.hash(command, title);
}
@Override
public String toString() {
if (title != null) {
return title;
}
return "/" + command;
}
private String trimSlash(String command) {
if (command.startsWith("/")) {
return command.substring(1);
}
return command;
}
}

View File

@ -0,0 +1,66 @@
package com.garbagemule.MobArena.things;
class CommandThingParser implements ThingParser {
private static final String PREFIX_LONG = "command";
private static final String PREFIX_SHORT = "cmd";
@Override
public CommandThing parse(String s) {
String trimmed = trimPrefix(s);
if (trimmed == null) {
return null;
}
if (trimmed.startsWith(":")) {
return untitledCommand(trimmed);
}
if (trimmed.startsWith("(")) {
return titledCommand(s, trimmed);
}
return null;
}
private String trimPrefix(String s) {
if (s.startsWith(PREFIX_SHORT)) {
return s.substring(PREFIX_SHORT.length()).trim();
}
if (s.startsWith(PREFIX_LONG)) {
return s.substring(PREFIX_LONG.length()).trim();
}
return null;
}
private CommandThing untitledCommand(String trimmed) {
String command = trimmed.substring(1).trim();
return new CommandThing(command);
}
private CommandThing titledCommand(String s, String trimmed) {
int end = findCloseParenthesis(trimmed);
if (end == -1) {
throw new IllegalArgumentException("Missing close parenthesis in " + s);
}
if (trimmed.length() <= end || trimmed.charAt(end + 1) != ':') {
throw new IllegalArgumentException("Expected 'cmd(<name>):<command>' but got " + s);
}
String title = trimmed.substring(1, end);
String command = trimmed.substring(end + 2).trim();
return new CommandThing(command, title);
}
private int findCloseParenthesis(String trimmed) {
int stack = 1;
for (int i = 1; i < trimmed.length() - 1; i++) {
switch (trimmed.charAt(i)) {
case '(': stack++; break;
case ')': stack--; break;
}
if (stack == 0) {
return i;
}
}
return -1;
}
}

View File

@ -10,6 +10,7 @@ public class ThingManager implements ThingParser {
public ThingManager(MobArena plugin) { public ThingManager(MobArena plugin) {
parsers = new ArrayList<>(); parsers = new ArrayList<>();
parsers.add(new CommandThingParser());
parsers.add(new MoneyThingParser(plugin)); parsers.add(new MoneyThingParser(plugin));
parsers.add(new ItemStackThingParser()); parsers.add(new ItemStackThingParser());
} }

View File

@ -0,0 +1,91 @@
package com.garbagemule.MobArena.things;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class CommandThingParserTest {
private CommandThingParser subject;
@Rule
public ExpectedException exception = ExpectedException.none();
@Before
public void setup() {
subject = new CommandThingParser();
}
@Test
public void emptyStringReturnsNull() {
Thing result = subject.parse("");
assertThat(result, is(nullValue()));
}
@Test
public void commandWithoutPrefixReturnsNull() {
Thing result = subject.parse("/give <player> dirt");
assertThat(result, is(nullValue()));
}
@Test
public void barePrefixReturnsNull() {
Thing result = subject.parse("cmd");
assertThat(result, is(nullValue()));
}
@Test
public void commandWithShortPrefix() {
String command = "/give <player> dirt";
Thing result = subject.parse("cmd:" + command);
Thing expected = new CommandThing(command);
assertThat(result, equalTo(expected));
}
@Test
public void commandWithLongPrefix() {
String command = "/give <player> dirt";
Thing result = subject.parse("command:" + command);
Thing expected = new CommandThing(command);
assertThat(result, equalTo(expected));
}
@Test
public void commandWithTitle() {
String command = "/give <player> dirt";
String title = "the best command";
Thing result = subject.parse("cmd(" + title + "):" + command);
Thing expected = new CommandThing(command, title);
assertThat(result, equalTo(expected));
}
@Test
public void missingCloseParenThrows() {
exception.expect(IllegalArgumentException.class);
subject.parse("cmd(name:/give <player> dirt");
}
@Test
public void missingColonAfterTitleThrows() {
exception.expect(IllegalArgumentException.class);
subject.parse("cmd(name)");
}
}