mirror of https://github.com/Minestom/Minestom.git
Update args
This commit is contained in:
parent
be0c7172fa
commit
4452356af1
|
@ -21,12 +21,10 @@ public final class CommandReader {
|
|||
}
|
||||
|
||||
public String readWord() {
|
||||
final int i = nextIndexOf(SPACE, 0);
|
||||
final String s = read(i == -1 ? input.length() : i);
|
||||
cursor++;
|
||||
return s;
|
||||
return readUntil(SPACE);
|
||||
}
|
||||
|
||||
//fixme single quotes are also valid
|
||||
public String readQuotedString() {
|
||||
if (peekNextChar() != QUOTE) throw new RuntimeException("Tried to read an unquoted string as quoted.");
|
||||
int end = cursor;
|
||||
|
@ -126,6 +124,33 @@ public final class CommandReader {
|
|||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads until the supplied character or end of input is encountered, target char
|
||||
* will not be included in the result, but the cursor will skip it
|
||||
*
|
||||
* @param c end char
|
||||
* @return string from current position until end char
|
||||
*/
|
||||
public String readUntil(char c) {
|
||||
final int i = nextIndexOf(c, 0);
|
||||
final String read = read(i == -1 ? input.length() : i);
|
||||
cursor++; // skip target char
|
||||
return read;
|
||||
}
|
||||
|
||||
public String readUntilAny(char ...c) {
|
||||
int end = -1;
|
||||
for (char c1 : c) {
|
||||
final int i1 = nextIndexOf(c1, 0);
|
||||
if (i1 != -1 && i1 < end) {
|
||||
end = i1;
|
||||
}
|
||||
}
|
||||
final String read = read(end == -1 ? input.length() : end);
|
||||
cursor++; // skip target char
|
||||
return read;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int nextIndexOf(char c, int offset) {
|
||||
return IntStream.range(cursor+offset, input.length()).filter(x -> input.charAt(x) == c).findFirst().orElse(-1);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package net.minestom.server.command.builder.arguments;
|
||||
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
import net.minestom.server.utils.StringUtils;
|
||||
import net.minestom.server.command.CommandReader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -16,50 +15,36 @@ public class ArgumentLoop<T> extends Argument<List<T>> {
|
|||
|
||||
@SafeVarargs
|
||||
public ArgumentLoop(@NotNull String id, @NotNull Argument<T>... arguments) {
|
||||
super(id, true, true);
|
||||
super(id);
|
||||
this.arguments.addAll(Arrays.asList(arguments));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<T> parse(@NotNull String input) throws ArgumentSyntaxException {
|
||||
List<T> result = new ArrayList<>();
|
||||
final String[] split = input.split(StringUtils.SPACE);
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
boolean success = false;
|
||||
for (String s : split) {
|
||||
builder.append(s);
|
||||
|
||||
for (Argument<T> argument : arguments) {
|
||||
try {
|
||||
final String inputString = builder.toString();
|
||||
final T value = argument.parse(inputString);
|
||||
success = true;
|
||||
result.add(value);
|
||||
break;
|
||||
} catch (ArgumentSyntaxException ignored) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
builder.setLength(0); // Clear
|
||||
} else {
|
||||
builder.append(StringUtils.SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isEmpty() || !success) {
|
||||
throw new ArgumentSyntaxException("Invalid loop, there is no valid argument found", input, INVALID_INPUT_ERROR);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Argument<T>> arguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Result<List<T>> parse(CommandReader reader) {
|
||||
final List<T> result = new ArrayList<>();
|
||||
|
||||
while (reader.hasRemaining()) {
|
||||
for (Argument<T> argument : arguments) {
|
||||
final T value = argument.parse(reader).value();
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
} else {
|
||||
if (result.isEmpty()) {
|
||||
return Result.incompatibleType();
|
||||
} else {
|
||||
return Result.syntaxError("Invalid loop, one of the arguments didn't return a value", "", INVALID_INPUT_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parser() {
|
||||
return null;
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package net.minestom.server.command.builder.arguments.minecraft;
|
||||
|
||||
import net.minestom.server.command.CommandReader;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import net.minestom.server.entity.GameMode;
|
||||
import net.minestom.server.utils.StringUtils;
|
||||
import net.minestom.server.utils.binary.BinaryWriter;
|
||||
import net.minestom.server.utils.entity.EntityFinder;
|
||||
import net.minestom.server.utils.math.IntRange;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -33,43 +34,81 @@ public class ArgumentEntity extends Argument<EntityFinder> {
|
|||
private static final List<String> SELECTOR_VARIABLES = Arrays.asList("@p", "@r", "@a", "@e", "@s");
|
||||
private static final List<String> PLAYERS_ONLY_SELECTOR = Arrays.asList("@p", "@r", "@a", "@s");
|
||||
private static final List<String> SINGLE_ONLY_SELECTOR = Arrays.asList("@p", "@r", "@s");
|
||||
// List with all the valid arguments
|
||||
private static final List<String> VALID_ARGUMENTS = Arrays.asList(
|
||||
"x", "y", "z",
|
||||
"distance", "dx", "dy", "dz",
|
||||
"scores", "tag", "team", "limit", "sort", "level", "gamemode", "name",
|
||||
"x_rotation", "y_rotation", "type", "nbt", "advancements", "predicate");
|
||||
|
||||
// List with all the easily parsable arguments which only require reading until a specific character (comma)
|
||||
private static final List<String> SIMPLE_ARGUMENTS = Arrays.asList(
|
||||
"x", "y", "z",
|
||||
"distance", "dx", "dy", "dz",
|
||||
"scores", "tag", "team", "limit", "sort", "level", "gamemode",
|
||||
"x_rotation", "y_rotation", "type", "advancements", "predicate");
|
||||
|
||||
private boolean onlySingleEntity;
|
||||
private boolean onlyPlayers;
|
||||
|
||||
public ArgumentEntity(String id) {
|
||||
super(id, true);
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Result<EntityFinder> parse(CommandReader reader) {
|
||||
final String input = reader.readWord();
|
||||
// Check for raw player name or UUID
|
||||
if (!input.startsWith(SELECTOR_PREFIX)) {
|
||||
|
||||
// Check if the input is a valid UUID
|
||||
try {
|
||||
final UUID uuid = UUID.fromString(input);
|
||||
return Result.success(new EntityFinder()
|
||||
.setTargetSelector(EntityFinder.TargetSelector.MINESTOM_UUID)
|
||||
.setConstantUuid(uuid));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
// Check if the input is a valid player name
|
||||
if (USERNAME_PATTERN.matcher(input).matches()) {
|
||||
return Result.success(new EntityFinder()
|
||||
.setTargetSelector(EntityFinder.TargetSelector.MINESTOM_USERNAME)
|
||||
.setConstantName(input));
|
||||
}
|
||||
|
||||
return Result.syntaxError("Input isn't a valid uuid/player name", input, INVALID_ARGUMENT_NAME);
|
||||
}
|
||||
|
||||
// The minimum size is always 2 for the selector variable, ex: @p
|
||||
if (input.length() < 2)
|
||||
return Result.incompatibleType();
|
||||
|
||||
final String selectorVariable = input.substring(0, 2);
|
||||
|
||||
// Check if the selector variable used exists
|
||||
if (!SELECTOR_VARIABLES.contains(selectorVariable))
|
||||
return Result.syntaxError("Invalid selector variable", input, INVALID_SYNTAX);
|
||||
|
||||
// Check if it should only select single entity and if the selector variable valid the condition
|
||||
if (onlySingleEntity && !SINGLE_ONLY_SELECTOR.contains(selectorVariable))
|
||||
return Result.syntaxError("Argument requires only a single entity", input, ONLY_SINGLE_ENTITY_ERROR);
|
||||
|
||||
// Check if it should only select players and if the selector variable valid the condition
|
||||
if (onlyPlayers && !PLAYERS_ONLY_SELECTOR.contains(selectorVariable))
|
||||
return Result.syntaxError("Argument requires only players", input, ONLY_PLAYERS_ERROR);
|
||||
|
||||
// Create the EntityFinder which will be used for the rest of the parsing
|
||||
final EntityFinder entityFinder = new EntityFinder()
|
||||
.setTargetSelector(toTargetSelector(selectorVariable));
|
||||
|
||||
// The selector is a single selector variable which verify all the conditions
|
||||
if (input.length() == 2)
|
||||
return Result.success(entityFinder);
|
||||
|
||||
// START PARSING THE STRUCTURE
|
||||
return parseStructure(reader, entityFinder, input.substring(2));
|
||||
}
|
||||
|
||||
@Contract("_ -> this")
|
||||
public ArgumentEntity singleEntity(boolean singleEntity) {
|
||||
this.onlySingleEntity = singleEntity;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Contract("_ -> this")
|
||||
public ArgumentEntity onlyPlayers(boolean onlyPlayers) {
|
||||
this.onlyPlayers = onlyPlayers;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EntityFinder parse(@NotNull String input) throws ArgumentSyntaxException {
|
||||
return staticParse(input, onlySingleEntity, onlyPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parser() {
|
||||
return "minecraft:entity";
|
||||
|
@ -89,183 +128,84 @@ public class ArgumentEntity extends Argument<EntityFinder> {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link Argument#parse(Argument)}
|
||||
*/
|
||||
@Deprecated
|
||||
@NotNull
|
||||
public static EntityFinder staticParse(@NotNull String input,
|
||||
boolean onlySingleEntity, boolean onlyPlayers) throws ArgumentSyntaxException {
|
||||
// Check for raw player name or UUID
|
||||
if (!input.contains(SELECTOR_PREFIX) && !input.contains(StringUtils.SPACE)) {
|
||||
|
||||
// Check if the input is a valid UUID
|
||||
try {
|
||||
final UUID uuid = UUID.fromString(input);
|
||||
return new EntityFinder()
|
||||
.setTargetSelector(EntityFinder.TargetSelector.MINESTOM_UUID)
|
||||
.setConstantUuid(uuid);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
// Check if the input is a valid player name
|
||||
if (USERNAME_PATTERN.matcher(input).matches()) {
|
||||
return new EntityFinder()
|
||||
.setTargetSelector(EntityFinder.TargetSelector.MINESTOM_USERNAME)
|
||||
.setConstantName(input);
|
||||
}
|
||||
}
|
||||
|
||||
// The minimum size is always 2 (for the selector variable, ex: @p)
|
||||
if (input.length() < 2)
|
||||
throw new ArgumentSyntaxException("Length needs to be > 1", input, INVALID_SYNTAX);
|
||||
|
||||
// The target selector variable always start by '@'
|
||||
if (!input.startsWith(SELECTOR_PREFIX))
|
||||
throw new ArgumentSyntaxException("Target selector needs to start with @", input, INVALID_SYNTAX);
|
||||
|
||||
final String selectorVariable = input.substring(0, 2);
|
||||
|
||||
// Check if the selector variable used exists
|
||||
if (!SELECTOR_VARIABLES.contains(selectorVariable))
|
||||
throw new ArgumentSyntaxException("Invalid selector variable", input, INVALID_SYNTAX);
|
||||
|
||||
// Check if it should only select single entity and if the selector variable valid the condition
|
||||
if (onlySingleEntity && !SINGLE_ONLY_SELECTOR.contains(selectorVariable))
|
||||
throw new ArgumentSyntaxException("Argument requires only a single entity", input, ONLY_SINGLE_ENTITY_ERROR);
|
||||
|
||||
// Check if it should only select players and if the selector variable valid the condition
|
||||
if (onlyPlayers && !PLAYERS_ONLY_SELECTOR.contains(selectorVariable))
|
||||
throw new ArgumentSyntaxException("Argument requires only players", input, ONLY_PLAYERS_ERROR);
|
||||
|
||||
// Create the EntityFinder which will be used for the rest of the parsing
|
||||
final EntityFinder entityFinder = new EntityFinder()
|
||||
.setTargetSelector(toTargetSelector(selectorVariable));
|
||||
|
||||
// The selector is a single selector variable which verify all the conditions
|
||||
if (input.length() == 2)
|
||||
return entityFinder;
|
||||
|
||||
// START PARSING THE STRUCTURE
|
||||
final String structure = input.substring(2);
|
||||
return parseStructure(input, entityFinder, structure);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static EntityFinder parseStructure(@NotNull String input,
|
||||
private static @NotNull Result<EntityFinder> parseStructure(@NotNull CommandReader reader,
|
||||
@NotNull EntityFinder entityFinder,
|
||||
@NotNull String structure) throws ArgumentSyntaxException {
|
||||
// The structure isn't opened or closed properly
|
||||
if (!structure.startsWith("[") || !structure.endsWith("]"))
|
||||
throw new ArgumentSyntaxException("Target selector needs to start and end with brackets", input, INVALID_SYNTAX);
|
||||
// The structure isn't opened
|
||||
if (!structure.startsWith("["))
|
||||
return Result.syntaxError("Target selector needs to start with brackets", structure, INVALID_SYNTAX);
|
||||
|
||||
// Remove brackets
|
||||
final String structureData = structure.substring(1, structure.length() - 1);
|
||||
//System.out.println("structure data: " + structureData);
|
||||
// Position cursor to start of structure data
|
||||
reader.setCursor(reader.cursor()-(structure.length()-structure.indexOf('[')));
|
||||
|
||||
String currentArgument = "";
|
||||
for (int i = 0; i < structureData.length(); i++) {
|
||||
final char c = structureData.charAt(i);
|
||||
if (c == '=') {
|
||||
|
||||
// Replace all unnecessary spaces
|
||||
currentArgument = currentArgument.trim();
|
||||
|
||||
if (!VALID_ARGUMENTS.contains(currentArgument))
|
||||
throw new ArgumentSyntaxException("Argument name '" + currentArgument + "' does not exist", input, INVALID_ARGUMENT_NAME);
|
||||
|
||||
i = parseArgument(entityFinder, currentArgument, input, structureData, i);
|
||||
currentArgument = ""; // Reset current argument
|
||||
} else {
|
||||
currentArgument += c;
|
||||
do {
|
||||
final String variable = reader.readUntil('=');
|
||||
switch (variable) {
|
||||
case "nbt", "name" -> throw new RuntimeException("Unsupported"); //todo parse these
|
||||
default -> {
|
||||
final String value = reader.readUntilAny(',', ']');
|
||||
switch (variable) {
|
||||
case "type": {
|
||||
final boolean include = !value.startsWith("!");
|
||||
final String entityName = include ? value : value.substring(1);
|
||||
final EntityType entityType = EntityType.fromNamespaceId(entityName);
|
||||
if (entityType == null)
|
||||
return Result.syntaxError("Invalid entity name", value, INVALID_ARGUMENT_VALUE);
|
||||
entityFinder.setEntity(entityType, include ? EntityFinder.ToggleableType.INCLUDE : EntityFinder.ToggleableType.EXCLUDE);
|
||||
break;
|
||||
}
|
||||
case "gamemode": {
|
||||
final boolean include = !value.startsWith("!");
|
||||
final String gameModeName = include ? value : value.substring(1);
|
||||
try {
|
||||
final GameMode gameMode = GameMode.valueOf(gameModeName.toUpperCase());
|
||||
entityFinder.setGameMode(gameMode, include ? EntityFinder.ToggleableType.INCLUDE : EntityFinder.ToggleableType.EXCLUDE);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.syntaxError("Invalid entity game mode", value, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "limit":
|
||||
try {
|
||||
int limit = Integer.parseInt(value);
|
||||
if (limit <= 0) {
|
||||
return Result.syntaxError("Limit must be positive", value, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
entityFinder.setLimit(limit);
|
||||
} catch (NumberFormatException e) {
|
||||
return Result.syntaxError("Invalid limit number", value, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
break;
|
||||
case "sort":
|
||||
try {
|
||||
EntityFinder.EntitySort entitySort = EntityFinder.EntitySort.valueOf(value.toUpperCase());
|
||||
entityFinder.setEntitySort(entitySort);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.syntaxError("Invalid entity sort", value, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
break;
|
||||
case "level":
|
||||
final IntRange level = Argument.parse(new ArgumentIntRange(value)).value();
|
||||
if (level == null)
|
||||
return Result.syntaxError("Invalid level number", value, INVALID_ARGUMENT_VALUE);
|
||||
entityFinder.setLevel(level);
|
||||
break;
|
||||
case "distance":
|
||||
final IntRange distance = Argument.parse(new ArgumentIntRange(value)).value();
|
||||
if (distance == null)
|
||||
return Result.syntaxError("Invalid level number", value, INVALID_ARGUMENT_VALUE);
|
||||
entityFinder.setDistance(distance);
|
||||
break;
|
||||
case "x", "y", "z", "dx", "dy", "dz", "scores", "tag", "team", "x_rotation", "y_rotation", "advancements", "predicate":
|
||||
throw new RuntimeException("Unsupported variable"); //fixme support others too
|
||||
default:
|
||||
return Result.syntaxError("Invalid variable", variable, INVALID_ARGUMENT_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (reader.hasRemaining() && reader.getCharAt(reader.cursor()) != ']');
|
||||
|
||||
return entityFinder;
|
||||
}
|
||||
|
||||
private static int parseArgument(@NotNull EntityFinder entityFinder,
|
||||
@NotNull String argumentName,
|
||||
@NotNull String input,
|
||||
@NotNull String structureData, int beginIndex) throws ArgumentSyntaxException {
|
||||
final char comma = ',';
|
||||
final boolean isSimple = SIMPLE_ARGUMENTS.contains(argumentName);
|
||||
|
||||
int finalIndex = beginIndex + 1;
|
||||
StringBuilder valueBuilder = new StringBuilder();
|
||||
for (; finalIndex < structureData.length(); finalIndex++) {
|
||||
final char c = structureData.charAt(finalIndex);
|
||||
|
||||
// Command is parsed
|
||||
if (isSimple && c == comma)
|
||||
break;
|
||||
|
||||
valueBuilder.append(c);
|
||||
}
|
||||
|
||||
final String value = valueBuilder.toString().trim();
|
||||
|
||||
//System.out.println("value: " + value);
|
||||
switch (argumentName) {
|
||||
case "type": {
|
||||
final boolean include = !value.startsWith("!");
|
||||
final String entityName = include ? value : value.substring(1);
|
||||
final EntityType entityType = EntityType.fromNamespaceId(entityName);
|
||||
if (entityType == null)
|
||||
throw new ArgumentSyntaxException("Invalid entity name", input, INVALID_ARGUMENT_VALUE);
|
||||
entityFinder.setEntity(entityType, include ? EntityFinder.ToggleableType.INCLUDE : EntityFinder.ToggleableType.EXCLUDE);
|
||||
break;
|
||||
}
|
||||
case "gamemode": {
|
||||
final boolean include = !value.startsWith("!");
|
||||
final String gameModeName = include ? value : value.substring(1);
|
||||
try {
|
||||
final GameMode gameMode = GameMode.valueOf(gameModeName.toUpperCase());
|
||||
entityFinder.setGameMode(gameMode, include ? EntityFinder.ToggleableType.INCLUDE : EntityFinder.ToggleableType.EXCLUDE);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ArgumentSyntaxException("Invalid entity game mode", input, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "limit":
|
||||
int limit;
|
||||
try {
|
||||
limit = Integer.parseInt(value);
|
||||
entityFinder.setLimit(limit);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ArgumentSyntaxException("Invalid limit number", input, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
if (limit <= 0) {
|
||||
throw new ArgumentSyntaxException("Limit must be positive", input, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
break;
|
||||
case "sort":
|
||||
try {
|
||||
EntityFinder.EntitySort entitySort = EntityFinder.EntitySort.valueOf(value.toUpperCase());
|
||||
entityFinder.setEntitySort(entitySort);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ArgumentSyntaxException("Invalid entity sort", input, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
break;
|
||||
case "level":
|
||||
try {
|
||||
final IntRange level = Argument.parse(new ArgumentIntRange(value));
|
||||
entityFinder.setLevel(level);
|
||||
} catch (ArgumentSyntaxException e) {
|
||||
throw new ArgumentSyntaxException("Invalid level number", input, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
break;
|
||||
case "distance":
|
||||
try {
|
||||
final IntRange distance = Argument.parse(new ArgumentIntRange(value));
|
||||
entityFinder.setDistance(distance);
|
||||
} catch (ArgumentSyntaxException e) {
|
||||
throw new ArgumentSyntaxException("Invalid level number", input, INVALID_ARGUMENT_VALUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return finalIndex;
|
||||
return Result.success(entityFinder);
|
||||
}
|
||||
|
||||
public boolean isOnlySingleEntity() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package net.minestom.server.command.builder.arguments.minecraft;
|
||||
|
||||
import net.minestom.server.command.CommandReader;
|
||||
import net.minestom.server.command.builder.arguments.Argument;
|
||||
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -25,13 +25,45 @@ public class ArgumentItemStack extends Argument<ItemStack> {
|
|||
public static final int INVALID_MATERIAL = 3;
|
||||
|
||||
public ArgumentItemStack(String id) {
|
||||
super(id, true);
|
||||
super(id);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ItemStack parse(@NotNull String input) throws ArgumentSyntaxException {
|
||||
return staticParse(input);
|
||||
public @NotNull Result<ItemStack> parse(CommandReader reader) {
|
||||
final int cursor = reader.cursor();
|
||||
final String input = reader.readWord();
|
||||
int nbtIndex = input.indexOf("{");
|
||||
|
||||
if (nbtIndex == 0)
|
||||
return Result.syntaxError("The item needs a material", input, NO_MATERIAL);
|
||||
|
||||
if (nbtIndex == -1) {
|
||||
// Only material name
|
||||
final Material material = Material.fromNamespaceId(input);
|
||||
if (material == null)
|
||||
return Result.incompatibleType();
|
||||
return Result.success(ItemStack.of(material));
|
||||
} else {
|
||||
// Material plus additional NBT
|
||||
final String materialName = input.substring(0, nbtIndex);
|
||||
final Material material = Material.fromNamespaceId(materialName);
|
||||
if (material == null)
|
||||
return Result.syntaxError("Material is invalid", input, INVALID_MATERIAL);
|
||||
|
||||
// Move cursor to start of nbt data
|
||||
reader.setCursor(cursor+nbtIndex);
|
||||
nbtIndex = reader.getClosingIndexOfJsonObject(0);
|
||||
|
||||
if (nbtIndex == -1) return Result.syntaxError("Item NBT is invalid", input, INVALID_NBT);
|
||||
|
||||
final String sNBT = reader.read(nbtIndex).replace("\\\"", "\"");
|
||||
|
||||
try {
|
||||
return Result.success(ItemStack.fromNBT(material, (NBTCompound) new SNBTParser(new StringReader(sNBT)).parse()));
|
||||
} catch (NBTException e) {
|
||||
return Result.syntaxError("Item NBT is invalid", input, INVALID_NBT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,42 +71,6 @@ public class ArgumentItemStack extends Argument<ItemStack> {
|
|||
return "minecraft:item_stack";
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link Argument#parse(Argument)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static ItemStack staticParse(@NotNull String input) throws ArgumentSyntaxException {
|
||||
final int nbtIndex = input.indexOf("{");
|
||||
|
||||
if (nbtIndex == 0)
|
||||
throw new ArgumentSyntaxException("The item needs a material", input, NO_MATERIAL);
|
||||
|
||||
if (nbtIndex == -1) {
|
||||
// Only material name
|
||||
final Material material = Material.fromNamespaceId(input);
|
||||
if (material == null)
|
||||
throw new ArgumentSyntaxException("Material is invalid", input, INVALID_MATERIAL);
|
||||
return ItemStack.of(material);
|
||||
} else {
|
||||
// Material plus additional NBT
|
||||
final String materialName = input.substring(0, nbtIndex);
|
||||
final Material material = Material.fromNamespaceId(materialName);
|
||||
if (material == null)
|
||||
throw new ArgumentSyntaxException("Material is invalid", input, INVALID_MATERIAL);
|
||||
|
||||
final String sNBT = input.substring(nbtIndex).replace("\\\"", "\"");
|
||||
|
||||
NBTCompound compound;
|
||||
try {
|
||||
compound = (NBTCompound) new SNBTParser(new StringReader(sNBT)).parse();
|
||||
} catch (NBTException e) {
|
||||
throw new ArgumentSyntaxException("Item NBT is invalid", input, INVALID_NBT);
|
||||
}
|
||||
|
||||
return ItemStack.fromNBT(material, compound);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("ItemStack<%s>", getId());
|
||||
|
|
Loading…
Reference in New Issue