Improve parsing from registries.

If multiple namespaces are present, suggestions will first suggest a
namespace, then once a namespace is selected, keys within that namespace.

Starting an argument with ":" will instead search across all namespaces
for matching keys.
This commit is contained in:
wizjany
2019-05-27 11:12:46 -04:00
parent ab1e09fdaf
commit 5e857b3547
5 changed files with 123 additions and 79 deletions

View File

@ -54,8 +54,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.stream.Stream;
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
/**
* Parses block input strings.
*/
@ -111,6 +109,7 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
* @param string Input string
* @return Mapped string
*/
@SuppressWarnings("ConstantConditions")
private String woolMapper(String string) {
switch (string.toLowerCase(Locale.ROOT)) {
case "white":
@ -191,7 +190,7 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
} catch (NoMatchException e) {
throw e; // Pass-through
} catch (Exception e) {
e.printStackTrace();
WorldEdit.logger.warn("Unknown state '" + parseableData + "'", e);
throw new NoMatchException("Unknown state '" + parseableData + "'");
}
}
@ -204,14 +203,7 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
public Stream<String> getSuggestions(String input) {
final int idx = input.lastIndexOf('[');
if (idx < 0) {
if (input.indexOf(':') == -1) {
String key = ("minecraft:" + input).toLowerCase(Locale.ROOT);
return BlockType.REGISTRY.keySet().stream().filter(s -> s.startsWith(key));
}
if (input.contains(",")) {
return Stream.empty();
}
return limitByPrefix(BlockType.REGISTRY.keySet().stream(), input).stream();
return SuggestionHelper.getNamespacedRegistrySuggestions(BlockType.REGISTRY, input);
}
String blockType = input.substring(0, idx);
BlockType type = BlockTypes.get(blockType.toLowerCase(Locale.ROOT));
@ -238,8 +230,10 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
// Legacy matcher
if (context.isTryingLegacy()) {
try {
String[] split = blockAndExtraData[0].split(":");
if (split.length == 1) {
String[] split = blockAndExtraData[0].split(":", 2);
if (split.length == 0) {
throw new InputParseException("Invalid colon.");
} else if (split.length == 1) {
state = LegacyMapper.getInstance().getBlockFromLegacy(Integer.parseInt(split[0]));
} else {
state = LegacyMapper.getInstance().getBlockFromLegacy(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
@ -247,7 +241,7 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
if (state != null) {
blockType = state.getBlockType();
}
} catch (NumberFormatException e) {
} catch (NumberFormatException ignored) {
}
}
@ -310,23 +304,15 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
} else {
// Attempt to lookup a block from ID or name.
blockType = BlockTypes.get(typeString.toLowerCase(Locale.ROOT));
}
if (blockType == null) {
throw new NoMatchException("Does not match a valid block type: '" + input + "'");
}
if (blockType == null) {
throw new NoMatchException("Does not match a valid block type: '" + input + "'");
}
blockStates.putAll(parseProperties(blockType, stateProperties, context));
if (!context.isPreferringWildcard()) {
// No wildcards allowed => eliminate them. (Start with default state)
state = blockType.getDefaultState();
for (Map.Entry<Property<?>, Object> blockState : blockStates.entrySet()) {
@SuppressWarnings("unchecked")
Property<Object> objProp = (Property<Object>) blockState.getKey();
state = state.with(objProp, blockState.getValue());
}
} else {
if (context.isPreferringWildcard()) {
FuzzyBlockState.Builder fuzzyBuilder = FuzzyBlockState.builder();
fuzzyBuilder.type(blockType);
for (Map.Entry<Property<?>, Object> blockState : blockStates.entrySet()) {
@ -335,8 +321,20 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
fuzzyBuilder.withProperty(objProp, blockState.getValue());
}
state = fuzzyBuilder.build();
} else {
// No wildcards allowed => eliminate them. (Start with default state)
state = blockType.getDefaultState();
for (Map.Entry<Property<?>, Object> blockState : blockStates.entrySet()) {
@SuppressWarnings("unchecked")
Property<Object> objProp = (Property<Object>) blockState.getKey();
state = state.with(objProp, blockState.getValue());
}
}
}
// this should be impossible but IntelliJ isn't that smart
if (blockType == null) {
throw new NoMatchException("Does not match a valid block type: '" + input + "'");
}
// Check if the item is allowed
if (context.isRestricted()) {
@ -369,6 +367,7 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
}
return new MobSpawnerBlock(state, mobName);
} else {
//noinspection ConstantConditions
return new MobSpawnerBlock(state, EntityTypes.PIG.getId());
}
} else if (blockType == BlockTypes.PLAYER_HEAD || blockType == BlockTypes.PLAYER_WALL_HEAD) {

View File

@ -21,22 +21,20 @@ package com.sk89q.worldedit.extension.factory.parser.mask;
import com.google.common.base.Splitter;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.SuggestionHelper;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.function.mask.BiomeMask2D;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.session.request.RequestExtent;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.Biomes;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.util.Collection;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class BiomeMaskParser extends InputParser<Mask> {
@ -47,20 +45,20 @@ public class BiomeMaskParser extends InputParser<Mask> {
@Override
public Stream<String> getSuggestions(String input) {
final Stream<String> allBiomes = BiomeType.REGISTRY.keySet().stream().map(biomeType -> "$" + biomeType);
if (input.isEmpty()) {
return allBiomes;
return Stream.of("$");
}
if (input.charAt(0) == '$') {
String key = input.substring(1);
if (key.isEmpty()) {
return allBiomes;
input = input.substring(1);
final int lastTermIdx = input.lastIndexOf(',');
if (lastTermIdx <= 0) {
return SuggestionHelper.getNamespacedRegistrySuggestions(BiomeType.REGISTRY, input).map(s -> "$" + s);
}
if (key.indexOf(':') < 0) {
key = "minecraft:" + key;
}
String biomeId = key.toLowerCase(Locale.ROOT);
return BiomeType.REGISTRY.keySet().stream().filter(s -> s.startsWith(biomeId)).map(s -> "$" + s);
String prev = input.substring(0, lastTermIdx) + ",";
Set<String> prevBiomes = Arrays.stream(prev.split(",", 0)).collect(Collectors.toSet());
String search = input.substring(lastTermIdx + 1);
return SuggestionHelper.getNamespacedRegistrySuggestions(BiomeType.REGISTRY, search)
.filter(s -> !prevBiomes.contains(s)).map(s -> "$" + prev + s);
}
return Stream.empty();
}
@ -72,10 +70,8 @@ public class BiomeMaskParser extends InputParser<Mask> {
}
Set<BiomeType> biomes = new HashSet<>();
BiomeRegistry biomeRegistry = worldEdit.getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
Collection<BiomeType> knownBiomes = BiomeType.REGISTRY.values();
for (String biomeName : Splitter.on(",").split(input.substring(1))) {
BiomeType biome = Biomes.findBiomeByName(knownBiomes, biomeName, biomeRegistry);
BiomeType biome = BiomeType.REGISTRY.get(biomeName);
if (biome == null) {
throw new InputParseException("Unknown biome '" + biomeName + '\'');
}