Began rewriting lookups to reusable system

This commit is contained in:
Auxilor
2022-02-28 13:18:58 +00:00
parent fb89415636
commit ebb30e3a70
12 changed files with 324 additions and 16 deletions

View File

@@ -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)) {

View File

@@ -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();
}

View File

@@ -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!");
}
}

View File

@@ -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);
}

View File

@@ -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");
}
}

View File

@@ -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);
}
}

View File

@@ -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.
*/

View File

@@ -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)

View 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", "||")
);
}
}

View File

@@ -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)
}
}

View File

@@ -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
}
}

View File

@@ -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())