Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-09-06 16:12:51 +02:00
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.
Dieser Commit ist enthalten in:
Ursprung
ab1e09fdaf
Commit
5e857b3547
@ -20,8 +20,8 @@
|
||||
package com.sk89q.worldedit.command.argument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.sk89q.worldedit.command.util.SuggestionHelper;
|
||||
import com.sk89q.worldedit.registry.Keyed;
|
||||
import com.sk89q.worldedit.registry.NamespacedRegistry;
|
||||
import com.sk89q.worldedit.registry.Registry;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
@ -45,8 +45,7 @@ import org.enginehub.piston.inject.Key;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class RegistryConverter<V extends Keyed> implements ArgumentConverter<V> {
|
||||
|
||||
@ -85,12 +84,10 @@ public final class RegistryConverter<V extends Keyed> implements ArgumentConvert
|
||||
|
||||
private final Registry<V> registry;
|
||||
private final TextComponent choices;
|
||||
private final boolean namespaced;
|
||||
|
||||
private RegistryConverter(Registry<V> registry) {
|
||||
this.registry = registry;
|
||||
this.choices = TextComponent.of("any " + registry.getName());
|
||||
this.namespaced = registry instanceof NamespacedRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -109,9 +106,6 @@ public final class RegistryConverter<V extends Keyed> implements ArgumentConvert
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(String input) {
|
||||
if (namespaced && input.indexOf(':') < 0) {
|
||||
input = "minecraft:" + input;
|
||||
}
|
||||
return limitByPrefix(registry.keySet().stream(), input);
|
||||
return SuggestionHelper.getRegistrySuggestions(registry, input).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.command.util;
|
||||
|
||||
import com.sk89q.worldedit.registry.Keyed;
|
||||
import com.sk89q.worldedit.registry.NamespacedRegistry;
|
||||
import com.sk89q.worldedit.registry.Registry;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockCategory;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
@ -30,39 +33,32 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.enginehub.piston.converter.SuggestionHelper.byPrefix;
|
||||
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
|
||||
|
||||
/**
|
||||
* Internal class for generating common command suggestions.
|
||||
*/
|
||||
public final class SuggestionHelper {
|
||||
private SuggestionHelper() {
|
||||
}
|
||||
|
||||
public static Stream<String> getBlockCategorySuggestions(String tag, boolean allowRandom) {
|
||||
final Stream<String> allTags = BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str);
|
||||
if (tag.isEmpty()) {
|
||||
return allTags;
|
||||
if (tag.isEmpty() || tag.equals("#")) {
|
||||
return Stream.of("##", "##*");
|
||||
}
|
||||
if (tag.startsWith("#")) {
|
||||
String key;
|
||||
if (tag.startsWith("##")) {
|
||||
key = tag.substring(2);
|
||||
if (key.isEmpty()) {
|
||||
return allTags;
|
||||
}
|
||||
boolean anyState = false;
|
||||
if (allowRandom && key.charAt(0) == '*') {
|
||||
key = key.substring(1);
|
||||
anyState = true;
|
||||
}
|
||||
if (key.indexOf(':') < 0) {
|
||||
key = "minecraft:" + key;
|
||||
}
|
||||
String finalTag = key.toLowerCase(Locale.ROOT);
|
||||
final Stream<String> stream = BlockCategory.REGISTRY.keySet().stream().filter(s ->
|
||||
s.startsWith(finalTag));
|
||||
return anyState ? stream.map(s -> "##*" + s) : stream.map(s -> "##" + s);
|
||||
} else if (tag.length() == 1) {
|
||||
return allTags;
|
||||
if (tag.equals("##")) {
|
||||
return Stream.concat(Stream.of("##*"), getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(2)).map(s -> "##" + s));
|
||||
} else if (tag.equals("##*") && allowRandom) {
|
||||
return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(3)).map(s -> "##*" + s);
|
||||
} else {
|
||||
boolean wild = tag.startsWith("##*") && allowRandom;
|
||||
return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(wild ? 3 : 2)).map(s -> (wild ? "##*" : "##") + s);
|
||||
}
|
||||
}
|
||||
return Stream.empty();
|
||||
@ -103,7 +99,7 @@ public final class SuggestionHelper {
|
||||
} else {
|
||||
Property<?> prop = propertyMap.get(matchProp);
|
||||
if (prop == null) {
|
||||
return Stream.empty();
|
||||
return propertyMap.keySet().stream().map(p -> lastValidInput + p);
|
||||
}
|
||||
final List<String> values = prop.getValues().stream().map(v -> v.toString().toLowerCase(Locale.ROOT)).collect(Collectors.toList());
|
||||
String matchVal = propVal[1].toLowerCase(Locale.ROOT);
|
||||
@ -140,4 +136,38 @@ public final class SuggestionHelper {
|
||||
}
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
public static <V extends Keyed> Stream<String> getRegistrySuggestions(Registry<V> registry, String input) {
|
||||
if (registry instanceof NamespacedRegistry) {
|
||||
return getNamespacedRegistrySuggestions(((NamespacedRegistry<V>) registry), input);
|
||||
}
|
||||
return limitByPrefix(registry.keySet().stream(), input).stream();
|
||||
}
|
||||
|
||||
public static <V extends Keyed> Stream<String> getNamespacedRegistrySuggestions(NamespacedRegistry<V> registry, String input) {
|
||||
if (input.isEmpty() || input.equals(":")) {
|
||||
final Set<String> namespaces = registry.getKnownNamespaces();
|
||||
if (namespaces.size() == 1) {
|
||||
return registry.keySet().stream();
|
||||
} else {
|
||||
return namespaces.stream().map(s -> s + ":");
|
||||
}
|
||||
}
|
||||
if (input.startsWith(":")) { // special case - search across namespaces
|
||||
final String term = input.substring(1).toLowerCase(Locale.ROOT);
|
||||
Predicate<String> search = byPrefix(term);
|
||||
return registry.keySet().stream().filter(s -> search.test(s.substring(s.indexOf(':') + 1)));
|
||||
}
|
||||
// otherwise, we actually have some text to search
|
||||
if (input.indexOf(':') < 0) {
|
||||
// don't yet have namespace - search namespaces + default
|
||||
final String lowerSearch = input.toLowerCase(Locale.ROOT);
|
||||
String defKey = registry.getDefaultNamespace() + ":" + lowerSearch;
|
||||
return Stream.concat(registry.keySet().stream().filter(s -> s.startsWith(defKey)),
|
||||
registry.getKnownNamespaces().stream().filter(n -> n.startsWith(lowerSearch)).map(n -> n + ":"));
|
||||
}
|
||||
// have a namespace - search that
|
||||
Predicate<String> search = byPrefix(input.toLowerCase(Locale.ROOT));
|
||||
return registry.keySet().stream().filter(search);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 + '\'');
|
||||
}
|
||||
|
@ -23,9 +23,13 @@ import static com.google.common.base.Preconditions.checkState;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class NamespacedRegistry<V extends Keyed> extends Registry<V> {
|
||||
private static final String MINECRAFT_NAMESPACE = "minecraft";
|
||||
private final Set<String> knownNamespaces = new HashSet<>();
|
||||
private final String defaultNamespace;
|
||||
|
||||
public NamespacedRegistry(final String name) {
|
||||
@ -46,8 +50,29 @@ public final class NamespacedRegistry<V extends Keyed> extends Registry<V> {
|
||||
@Override
|
||||
public V register(final String key, final V value) {
|
||||
requireNonNull(key, "key");
|
||||
checkState(key.indexOf(':') > -1, "key is not namespaced");
|
||||
return super.register(key, value);
|
||||
final int i = key.indexOf(':');
|
||||
checkState(i > 0, "key is not namespaced");
|
||||
final V registered = super.register(key, value);
|
||||
knownNamespaces.add(key.substring(0, i));
|
||||
return registered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of the namespaces of all registered keys.
|
||||
*
|
||||
* @return set of namespaces
|
||||
*/
|
||||
public Set<String> getKnownNamespaces() {
|
||||
return Collections.unmodifiableSet(knownNamespaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default namespace for this registry.
|
||||
*
|
||||
* @return the default namespace
|
||||
*/
|
||||
public String getDefaultNamespace() {
|
||||
return defaultNamespace;
|
||||
}
|
||||
|
||||
private String orDefaultNamespace(final String key) {
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren