Began rewriting lookups to reusable system
This commit is contained in:
@@ -87,8 +87,8 @@ public final class Entities {
|
||||
*/
|
||||
@NotNull
|
||||
public static TestableEntity lookup(@NotNull final String key) {
|
||||
if (key.contains("?")) {
|
||||
String[] options = key.split("\\?");
|
||||
if (key.contains(" ? ")) {
|
||||
String[] options = StringUtils.splitAround(key, "?");
|
||||
for (String option : options) {
|
||||
TestableEntity lookup = lookup(option);
|
||||
if (!(lookup instanceof EmptyTestableEntity)) {
|
||||
|
||||
@@ -8,9 +8,9 @@ import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
|
||||
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
|
||||
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
|
||||
import com.willfp.eco.core.recipe.parts.TestableStack;
|
||||
import com.willfp.eco.lookup.LookupHelper;
|
||||
import com.willfp.eco.util.NamespacedKeyUtils;
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -68,6 +68,11 @@ public final class Items {
|
||||
*/
|
||||
private static final List<LookupArgParser> ARG_PARSERS = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The handler.
|
||||
*/
|
||||
private static final ItemsLookupHandler ITEMS_LOOKUP_HANDLER = new ItemsLookupHandler(Items::doParse);
|
||||
|
||||
/**
|
||||
* Register a new custom item.
|
||||
*
|
||||
@@ -131,20 +136,11 @@ public final class Items {
|
||||
*/
|
||||
@NotNull
|
||||
public static TestableItem lookup(@NotNull final String key) {
|
||||
if (key.contains("?")) {
|
||||
String[] options = key.split("\\?");
|
||||
for (String option : options) {
|
||||
TestableItem lookup = lookup(option);
|
||||
if (!(lookup instanceof EmptyTestableItem)) {
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
||||
return new EmptyTestableItem();
|
||||
}
|
||||
|
||||
String[] args = StringUtils.parseTokens(key);
|
||||
return LookupHelper.parseWith(key, ITEMS_LOOKUP_HANDLER);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static TestableItem doParse(@NotNull final String[] args) {
|
||||
if (args.length == 0) {
|
||||
return new EmptyTestableItem();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.willfp.eco.core.items;
|
||||
|
||||
import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
|
||||
import com.willfp.eco.lookup.LookupHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Handle item lookup strings.
|
||||
*/
|
||||
public class ItemsLookupHandler implements LookupHandler<TestableItem> {
|
||||
/**
|
||||
* The parser.
|
||||
*/
|
||||
private final Function<String[], @NotNull TestableItem> parser;
|
||||
|
||||
/**
|
||||
* Create new lookup handler.
|
||||
*
|
||||
* @param parser The parser.
|
||||
*/
|
||||
public ItemsLookupHandler(@NotNull final Function<String[], @NotNull TestableItem> parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull TestableItem parse(@NotNull final String[] args) {
|
||||
return parser.apply(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(@NotNull final TestableItem object) {
|
||||
return !(object instanceof EmptyTestableItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull TestableItem getFailsafe() {
|
||||
return new EmptyTestableItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull TestableItem join(@NotNull final Collection<TestableItem> options) {
|
||||
throw new UnsupportedOperationException("Joining not supported!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.willfp.eco.lookup;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Handle lookups, used in {@link com.willfp.eco.core.entities.Entities} and {@link com.willfp.eco.core.items.Items}.
|
||||
*
|
||||
* @param <T> The type of testable object, eg {@link com.willfp.eco.core.items.TestableItem}.
|
||||
*/
|
||||
public interface LookupHandler<T> {
|
||||
/**
|
||||
* Parse arguments to an object.
|
||||
*
|
||||
* @param args The arguments.
|
||||
* @return The object.
|
||||
*/
|
||||
@NotNull
|
||||
T parse(@NotNull String[] args);
|
||||
|
||||
/**
|
||||
* Validate an object.
|
||||
*
|
||||
* @param object The object.
|
||||
* @return If validated.
|
||||
*/
|
||||
boolean validate(@NotNull T object);
|
||||
|
||||
/**
|
||||
* Get the failsafe object.
|
||||
* <p>
|
||||
* A failsafe object should never pass {@link this#validate(Object)}.
|
||||
*
|
||||
* @return The failsafe.
|
||||
*/
|
||||
@NotNull
|
||||
T getFailsafe();
|
||||
|
||||
/**
|
||||
* Join several options together.
|
||||
*
|
||||
* @param options The options.
|
||||
* @return The joined object.
|
||||
*/
|
||||
@NotNull
|
||||
T join(@NotNull Collection<T> options);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.willfp.eco.lookup;
|
||||
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper for lookups.
|
||||
*/
|
||||
public final class LookupHelper {
|
||||
/**
|
||||
* All segment parsers.
|
||||
*/
|
||||
private static final List<SegmentParser> SEGMENT_PARSERS = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Parse key to object.
|
||||
*
|
||||
* @param key The key.
|
||||
* @param handler The handler.
|
||||
* @param <T> The object type.
|
||||
* @return The object.
|
||||
*/
|
||||
@NotNull
|
||||
public static <T> T parseWith(@NotNull final String key,
|
||||
@NotNull final LookupHandler<T> handler) {
|
||||
for (SegmentParser parser : SEGMENT_PARSERS) {
|
||||
T generated = parser.parse(key, handler);
|
||||
|
||||
if (generated != null) {
|
||||
return generated;
|
||||
}
|
||||
}
|
||||
|
||||
String[] args = StringUtils.parseTokens(key);
|
||||
|
||||
return handler.parse(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register segment parser.
|
||||
*
|
||||
* @param parser The parser.
|
||||
*/
|
||||
public static void registerSegmentParser(@NotNull final SegmentParser parser) {
|
||||
SEGMENT_PARSERS.add(parser);
|
||||
}
|
||||
|
||||
private LookupHelper() {
|
||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.willfp.eco.lookup;
|
||||
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Parse a key into segments.
|
||||
*/
|
||||
public abstract class SegmentParser {
|
||||
/**
|
||||
* The pattern to split keys on.
|
||||
*/
|
||||
private final String pattern;
|
||||
|
||||
/**
|
||||
* Create new lookup segment parser.
|
||||
*
|
||||
* @param pattern The pattern.
|
||||
*/
|
||||
protected SegmentParser(@NotNull final String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle segments from key.
|
||||
*
|
||||
* @param segments The key segments.
|
||||
* @param handler The handler.
|
||||
* @param <T> The object type.
|
||||
* @return The returned object.
|
||||
*/
|
||||
protected abstract <T> T handleSegments(@NotNull String[] segments,
|
||||
@NotNull LookupHandler<T> handler);
|
||||
|
||||
/**
|
||||
* Try parse segments from key.
|
||||
*
|
||||
* @param key The key.
|
||||
* @param handler The handler.
|
||||
* @param <T> The object type.
|
||||
* @return Null if no segments were found, or the object generated from the segments.
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T parse(@NotNull final String key,
|
||||
@NotNull final LookupHandler<T> handler) {
|
||||
if (!key.contains(" " + pattern + " ")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] segments = StringUtils.splitAround(key, pattern);
|
||||
|
||||
return handleSegments(segments, handler);
|
||||
}
|
||||
}
|
||||
@@ -121,6 +121,14 @@ public final class StringUtils {
|
||||
.put("§k", ChatColor.MAGIC)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Regex map for splitting values.
|
||||
*/
|
||||
private static final LoadingCache<String, Pattern> SPACE_AROUND_CHARACTER = Caffeine.newBuilder()
|
||||
.build(
|
||||
character -> Pattern.compile("( " + Pattern.quote(character) + " )")
|
||||
);
|
||||
|
||||
/**
|
||||
* Format a list of strings.
|
||||
* <p>
|
||||
@@ -560,6 +568,27 @@ public final class StringUtils {
|
||||
return tokens.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split input string around separator surrounded by spaces.
|
||||
* <p>
|
||||
* e.g. {@code splitAround("hello ? how are you", "?")} will split, but
|
||||
* {@code splitAround("hello? how are you", "?")} will not.
|
||||
*
|
||||
* @param input Input string.
|
||||
* @param separator Separator.
|
||||
* @return The split string.
|
||||
*/
|
||||
@NotNull
|
||||
public static String[] splitAround(@NotNull final String input,
|
||||
@NotNull final String separator) {
|
||||
Matcher matcher = SPACE_AROUND_CHARACTER.get(separator).matcher(input);
|
||||
List<String> groups = new ArrayList<>();
|
||||
while (matcher.find()) {
|
||||
groups.add(matcher.group());
|
||||
}
|
||||
return groups.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for formatting.
|
||||
*/
|
||||
|
||||
@@ -40,3 +40,9 @@ fun List<String>.formatEco(
|
||||
player,
|
||||
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
|
||||
)
|
||||
|
||||
/**
|
||||
* @see StringUtils.splitAround
|
||||
*/
|
||||
fun String.splitAround(separator: String): Array<String> =
|
||||
StringUtils.splitAround(this, separator)
|
||||
|
||||
29
eco-api/src/test/java/StringUtilsTest.java
Normal file
29
eco-api/src/test/java/StringUtilsTest.java
Normal file
@@ -0,0 +1,29 @@
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class StringUtilsTest {
|
||||
@Test
|
||||
public void testSplitAround() {
|
||||
Assertions.assertArrayEquals(
|
||||
new String[]{"one", "two"},
|
||||
StringUtils.splitAround("one ? two", "?")
|
||||
);
|
||||
Assertions.assertArrayEquals(
|
||||
new String[]{"one? two"},
|
||||
StringUtils.splitAround("one? two", "?")
|
||||
);
|
||||
Assertions.assertArrayEquals(
|
||||
new String[]{"one", "two", "three"},
|
||||
StringUtils.splitAround("one ? two ? three", "?")
|
||||
);
|
||||
Assertions.assertArrayEquals(
|
||||
new String[]{"one", "two"},
|
||||
StringUtils.splitAround("one || two", "||")
|
||||
);
|
||||
Assertions.assertArrayEquals(
|
||||
new String[]{"one|| two"},
|
||||
StringUtils.splitAround("one|| two", "||")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.willfp.eco.internal.lookup
|
||||
|
||||
import com.willfp.eco.lookup.LookupHandler
|
||||
import com.willfp.eco.lookup.LookupHelper
|
||||
import com.willfp.eco.lookup.SegmentParser
|
||||
|
||||
class SegmentParserGroup : SegmentParser("||") {
|
||||
override fun <T : Any> handleSegments(segments: Array<out String>, handler: LookupHandler<T>): T {
|
||||
val possibleOptions: MutableList<T> = ArrayList()
|
||||
|
||||
for (option in segments) {
|
||||
val lookup = LookupHelper.parseWith(option, handler)
|
||||
if (handler.validate(lookup)) {
|
||||
possibleOptions.add(lookup)
|
||||
}
|
||||
}
|
||||
|
||||
return handler.join(possibleOptions)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.willfp.eco.internal.lookup
|
||||
|
||||
import com.willfp.eco.lookup.LookupHandler
|
||||
import com.willfp.eco.lookup.LookupHelper
|
||||
import com.willfp.eco.lookup.SegmentParser
|
||||
|
||||
class SegmentParserUseIfPresent : SegmentParser("?") {
|
||||
override fun <T : Any> handleSegments(segments: Array<out String>, handler: LookupHandler<T>): T {
|
||||
for (option in segments) {
|
||||
val lookup = LookupHelper.parseWith(option, handler)
|
||||
if (handler.validate(lookup)) {
|
||||
return lookup
|
||||
}
|
||||
}
|
||||
|
||||
return handler.failsafe
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,8 @@ import com.willfp.eco.internal.items.ArgParserFlag
|
||||
import com.willfp.eco.internal.items.ArgParserName
|
||||
import com.willfp.eco.internal.items.ArgParserTexture
|
||||
import com.willfp.eco.internal.items.ArgParserUnbreakable
|
||||
import com.willfp.eco.internal.lookup.SegmentParserGroup
|
||||
import com.willfp.eco.internal.lookup.SegmentParserUseIfPresent
|
||||
import com.willfp.eco.internal.spigot.arrows.ArrowDataListener
|
||||
import com.willfp.eco.internal.spigot.data.DataListener
|
||||
import com.willfp.eco.internal.spigot.data.DataYml
|
||||
@@ -112,6 +114,7 @@ import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener
|
||||
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInComplex
|
||||
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInEco
|
||||
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInVanilla
|
||||
import com.willfp.eco.lookup.LookupHelper
|
||||
import com.willfp.eco.util.BlockUtils
|
||||
import com.willfp.eco.util.NumberUtils
|
||||
import com.willfp.eco.util.ServerUtils
|
||||
@@ -155,6 +158,9 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
Entities.registerArgParser(EntityArgParserSilent())
|
||||
Entities.registerArgParser(EntityArgParserEquipment())
|
||||
|
||||
LookupHelper.registerSegmentParser(SegmentParserGroup())
|
||||
LookupHelper.registerSegmentParser(SegmentParserUseIfPresent())
|
||||
|
||||
ShapedRecipeListener.registerListener(ComplexInComplex())
|
||||
ShapedRecipeListener.registerListener(ComplexInEco())
|
||||
ShapedRecipeListener.registerListener(ComplexInVanilla())
|
||||
|
||||
Reference in New Issue
Block a user