Skip to content

Commit 74b3875

Browse files
committed
Tweak formatting, work on dimension, world, and child command elements
1 parent ef98e38 commit 74b3875

File tree

5 files changed

+264
-44
lines changed

5 files changed

+264
-44
lines changed

src/main/java/org/spongepowered/api/service/command/GameArguments.java

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
package org.spongepowered.api.service.command;
2626

2727

28+
import static org.spongepowered.api.service.command.TranslationPlaceholder.t;
29+
2830
import com.flowpowered.math.vector.Vector3d;
2931
import com.google.common.base.Function;
3032
import com.google.common.base.Optional;
@@ -34,13 +36,15 @@
3436
import org.spongepowered.api.Game;
3537
import org.spongepowered.api.entity.player.Player;
3638
import org.spongepowered.api.text.Text;
37-
import org.spongepowered.api.text.Texts;
3839
import org.spongepowered.api.util.StartsWithPredicate;
3940
import org.spongepowered.api.util.command.CommandSource;
4041
import org.spongepowered.api.util.command.args.ArgumentParseException;
4142
import org.spongepowered.api.util.command.args.CommandArgs;
4243
import org.spongepowered.api.util.command.args.CommandContext;
4344
import org.spongepowered.api.util.command.args.CommandElement;
45+
import org.spongepowered.api.world.DimensionType;
46+
import org.spongepowered.api.world.Location;
47+
import org.spongepowered.api.world.World;
4448

4549
import java.util.List;
4650
import java.util.UUID;
@@ -50,32 +54,48 @@
5054
public class GameArguments {
5155
private GameArguments() {}
5256

53-
private static Text t(String input) {
54-
return Texts.of(input);
57+
/**
58+
* Expect an argument to represent an online player,
59+
* or if nothing matches and the source is a {@link Player}, give the player.
60+
* Gives value of type {@link Player}
61+
*
62+
* @param key The key to store under
63+
* @param game The game to find players in
64+
* @return the argument
65+
*/
66+
public static CommandElement playerOrSource(Text key, Game game) {
67+
return new PlayerCommandElement(key, game, true);
5568
}
5669

5770
/**
5871
* Expect an argument to represent an online player.
72+
* Gives value of type {@link Player}
5973
*
6074
* @param key The key to store under
6175
* @param game The game to find players in
6276
* @return the argument
6377
*/
6478
public static CommandElement player(Text key, Game game) {
65-
return new PlayerCommandElement(key, game);
79+
return new PlayerCommandElement(key, game, false);
6680
}
6781

6882
private static class PlayerCommandElement extends CommandElement {
6983
private final Game game;
84+
private final boolean returnSource;
7085

71-
protected PlayerCommandElement(Text key, Game game) {
86+
protected PlayerCommandElement(Text key, Game game, boolean returnSource) {
7287
super(key);
7388
this.game = game;
89+
this.returnSource = returnSource;
7490
}
7591

7692
@Override
7793
protected Object parseValue(CommandSource source, CommandArgs args) throws ArgumentParseException {
7894
// TODO: Make player name resolution better -- support selectors, etc
95+
if (!args.hasNext() && this.returnSource) {
96+
return tryReturnSource(source, args);
97+
}
98+
7999
final String playerName = args.next();
80100
Optional<Player> ret;
81101
try {
@@ -85,12 +105,24 @@ protected Object parseValue(CommandSource source, CommandArgs args) throws Argum
85105
ret = this.game.getServer().getPlayer(playerName);
86106
}
87107
if (!ret.isPresent()) {
88-
throw args.createError(t("No matching players found!"));
108+
if (this.returnSource) {
109+
return tryReturnSource(source, args);
110+
} else {
111+
throw args.createError(t("No matching players found!"));
112+
}
89113
} else {
90114
return ret.get();
91115
}
92116
}
93117

118+
private Player tryReturnSource(CommandSource source, CommandArgs args) throws ArgumentParseException {
119+
if (source instanceof Player) {
120+
return ((Player) source);
121+
} else {
122+
throw args.createError(t("No players matched and source was not a player!"));
123+
}
124+
}
125+
94126
@Override
95127
public List<String> complete(CommandSource src, CommandArgs args, CommandContext context) {
96128
Iterable<String> players = Iterables.transform(this.game.getServer().getOnlinePlayers(), new Function<Player, String>() {
@@ -110,6 +142,7 @@ public String apply(@Nullable Player input) {
110142

111143
/**
112144
* Expect an argument to represent a world.
145+
* Gives values of type {@link World}
113146
*
114147
* @param key The key to store under
115148
* @param game The game to find worlds from
@@ -129,15 +162,43 @@ protected WorldCommandElement(Text key, Game game) {
129162

130163
@Override
131164
protected Object parseValue(CommandSource source, CommandArgs args) throws ArgumentParseException {
132-
return null;
165+
final String worldName = args.next();
166+
Optional<World> ret = this.game.getServer().getWorld(worldName);
167+
if (!ret.isPresent()) {
168+
throw args.createError(t("Unable to find world for name %s", worldName));
169+
}
170+
return ret.get();
133171
}
134172

135173
@Override
136174
public List<String> complete(CommandSource src, CommandArgs args, CommandContext context) {
137-
return null;
175+
final Optional<String> worldNameComponent = args.nextIfPresent();
176+
Iterable<String> worldsList = Iterables.transform(this.game.getServer().getWorlds(), new Function<World, String>() {
177+
@Nullable
178+
@Override
179+
public String apply(@Nullable World input) {
180+
return input == null ? null : input.getName();
181+
}
182+
});
183+
if (worldNameComponent.isPresent()) {
184+
worldsList = Iterables.filter(worldsList, new StartsWithPredicate(worldNameComponent.get()));
185+
}
186+
return ImmutableList.copyOf(worldsList);
138187
}
139188
}
140189

190+
/**
191+
* Expect an argument to represent a dimension.
192+
* Gives values of tye {@link DimensionType}
193+
*
194+
* @param key The key to store under
195+
* @param game The game to find dimensions from
196+
* @return the argument
197+
*/
198+
public static CommandElement dimension(Text key, Game game) {
199+
return catalogedElement(key, game, DimensionType.class);
200+
}
201+
141202
/**
142203
* Expect an argument to represent a {@link Vector3d}.
143204
*
@@ -166,7 +227,7 @@ public List<String> complete(CommandSource src, CommandArgs args, CommandContext
166227
}
167228

168229
/**
169-
* Expect an argument to represent a location.
230+
* Expect an argument to represent a {@link Location}.
170231
*
171232
* @param key The key to store under
172233
* @param game The game to find worlds from
@@ -196,7 +257,7 @@ public List<String> complete(CommandSource src, CommandArgs args, CommandContext
196257
}
197258

198259
/**
199-
* Expect an argument that is a member of the specified catalog type.
260+
* Expect an argument that is a member of the specified catalog type {@link T}.
200261
*
201262
* @param key The key to store the resolved value under
202263
* @param game The game to get the registry from

src/main/java/org/spongepowered/api/util/command/CommandMessageFormatting.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public class CommandMessageFormatting {
3333
public static final Text SPACE_TEXT = Texts.of(" ");
3434
public static final Text PLUS_TEXT = Texts.of("*");
3535
public static final Text NEWLINE_TEXT = Texts.of('\n');
36+
public static final Text LT_TEXT = Texts.of("<");
37+
public static final Text GT_TEXT = Texts.of(">");
38+
public static final Text ELIPSES_TEXT = Texts.of("…");
3639

3740
/**
3841
* Format text to be output as an error directly to a sender. Not necessary when creating an exception to be thrown

src/main/java/org/spongepowered/api/util/command/args/ChildCommandElementExecutor.java

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.spongepowered.api.util.command.CommandSource;
4343
import org.spongepowered.api.util.command.dispatcher.SimpleDispatcher;
4444
import org.spongepowered.api.util.command.spec.CommandExecutor;
45+
import org.spongepowered.api.util.command.spec.CommandSpec;
4546

4647
import java.util.List;
4748
import java.util.concurrent.atomic.AtomicInteger;
@@ -68,12 +69,23 @@ public ChildCommandElementExecutor(@Nullable CommandExecutor fallbackExecutor) {
6869
/**
6970
* Register a child command for a given set of aliases.
7071
*
71-
* @param value The command to register
72-
* @param key The key to register it as
72+
* @param callable The command to register
73+
* @param aliases The aliases to register it as
7374
* @return The child command's mapping, if present
7475
*/
75-
public Optional<CommandMapping> register(CommandCallable value, List<String> key) {
76-
return this.dispatcher.register(value, key);
76+
public Optional<CommandMapping> register(CommandCallable callable, List<String> aliases) {
77+
return this.dispatcher.register(callable, aliases);
78+
}
79+
80+
/**
81+
* Register a child command for a given set of aliases.
82+
*
83+
* @param callable The command to register
84+
* @param aliases The aliases to register it as
85+
* @return The child command's mapping, if present
86+
*/
87+
public Optional<CommandMapping> register(CommandCallable callable, String... aliases) {
88+
return this.dispatcher.register(callable, aliases);
7789
}
7890

7991
@Override
@@ -85,19 +97,23 @@ public List<String> complete(final CommandSource src, CommandArgs args, CommandC
8597
if (!child.isPresent()) {
8698
return ImmutableList.of();
8799
}
88-
args.nextIfPresent();
89-
final String arguments = args.getRaw().substring(args.getRawPosition());
90-
while (args.hasNext()) {
100+
if (child.get().getCallable() instanceof CommandSpec) {
101+
return ((CommandSpec) child.get().getCallable()).complete(src, args, context);
102+
} else {
91103
args.nextIfPresent();
92-
}
93-
try {
94-
return child.get().getCallable().getSuggestions(src, arguments);
95-
} catch (CommandException e) {
96-
Text eText = e.getText();
97-
if (eText != null) {
98-
src.sendMessage(error(eText));
104+
final String arguments = args.getRaw().substring(args.getRawPosition());
105+
while (args.hasNext()) {
106+
args.nextIfPresent();
107+
}
108+
try {
109+
return child.get().getCallable().getSuggestions(src, arguments);
110+
} catch (CommandException e) {
111+
Text eText = e.getText();
112+
if (eText != null) {
113+
src.sendMessage(error(eText));
114+
}
115+
return ImmutableList.of();
99116
}
100-
return ImmutableList.of();
101117
}
102118
} else {
103119
return ImmutableList.copyOf(Iterables.filter(filterCommands(src), new StartsWithPredicate(commandComponent.get())));
@@ -119,35 +135,55 @@ public boolean apply(@Nullable CommandMapping input) {
119135
@Override
120136
public void parse(CommandSource source, CommandArgs args, CommandContext context) throws ArgumentParseException {
121137
super.parse(source, args, context);
122-
context.putArg(getUntranslatedKey() + "_args", args.getRaw().substring(args.getRawPosition()));
123-
while (args.hasNext()) {
124-
args.next();
138+
final CommandMapping mapping = context.<CommandMapping>getOne(getUntranslatedKey()).get();
139+
if ((mapping.getCallable() instanceof CommandSpec)) {
140+
CommandSpec spec = ((CommandSpec) mapping.getCallable());
141+
spec.populateContext(source, args, context);
142+
} else {
143+
if (args.hasNext()) {
144+
args.next();
145+
}
146+
147+
context.putArg(getUntranslatedKey() + "_args", args.getRaw().substring(args.getRawPosition()));
148+
while (args.hasNext()) {
149+
args.next();
150+
}
125151
}
126152
}
127153

128154
@Override
129155
protected Object parseValue(CommandSource source, CommandArgs args) throws ArgumentParseException {
130156
final String key = args.next();
131-
if (!this.dispatcher.containsAlias(key)) {
157+
final Optional<CommandMapping> mapping = this.dispatcher.get(key, source);
158+
if (!mapping.isPresent()) {
132159
throw args.createError(t("Input command %s was not a valid subcommand!", key));
133160
}
134161

135-
return key;
162+
return mapping.get();
136163
}
137164

138165
@Override
139166
public CommandResult execute(CommandSource src, CommandContext args) throws CommandException {
140-
final String arguments = args.<String>getOne(getUntranslatedKey() + "_args").get();
141-
String alias = args.<String>getOne(getUntranslatedKey()).get();
142-
CommandMapping mapping = this.dispatcher.get(alias, src).orNull();
167+
CommandMapping mapping = args.<CommandMapping>getOne(getUntranslatedKey()).orNull();
143168
if (mapping == null) {
144169
if (this.fallbackExecutor != null) {
145170
return this.fallbackExecutor.execute(src, args);
146171
} else {
147172
throw new CommandException(t("Invalid subcommand state -- no more than one mapping may be provided for child arg %s", getKey()));
148173
}
149174
}
150-
return mapping.getCallable().process(src, arguments).or(CommandResult.empty());
175+
if (mapping.getCallable() instanceof CommandSpec) {
176+
CommandSpec spec = ((CommandSpec) mapping.getCallable());
177+
spec.checkPermission(src);
178+
return spec.getExecutor().execute(src, args);
179+
} else {
180+
final String arguments = args.<String>getOne(getUntranslatedKey() + "_args").or("");
181+
return mapping.getCallable().process(src, arguments).or(CommandResult.empty());
182+
}
151183
}
152184

185+
@Override
186+
public Text getUsage(CommandSource src) {
187+
return this.dispatcher.getUsage(src);
188+
}
153189
}

src/main/java/org/spongepowered/api/util/command/args/CommandElement.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,6 @@ public void parse(CommandSource source, CommandArgs args, CommandContext context
111111
* @return The formatted usage
112112
*/
113113
public Text getUsage(CommandSource src) {
114-
return getKey() == null ? Texts.of() : getKey();
114+
return getKey() == null ? Texts.of() : Texts.of("<", getKey(), ">");
115115
}
116116
}

0 commit comments

Comments
 (0)