diff --git a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java index 115c809d8..8792e8a95 100644 --- a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java @@ -76,6 +76,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.nio.ByteBuffer; import java.time.Duration; import java.time.temporal.ChronoUnit; +import java.util.ArrayDeque; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -83,6 +85,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.Locale; import java.util.Map; +import java.util.Queue; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -126,14 +129,35 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, } public static PlotPlayer from(final @NonNull T object) { - if (!converters.containsKey(object.getClass())) { - throw new IllegalArgumentException(String - .format( - "There is no registered PlotPlayer converter for type %s", - object.getClass().getSimpleName() - )); + // fast path + if (converters.containsKey(object.getClass())) { + return converters.get(object.getClass()).convert(object); } - return converters.get(object.getClass()).convert(object); + // slow path, meant to only run once per object#getClass instance + Queue> toVisit = new ArrayDeque<>(); + toVisit.add(object.getClass()); + Class current; + while ((current = toVisit.poll()) != null) { + PlotPlayerConverter converter = converters.get(current); + if (converter != null) { + if (current != object.getClass()) { + // register shortcut for this sub type to avoid further loops + converters.put(object.getClass(), converter); + LOGGER.info("Registered {} as with converter for {}", object.getClass(), current); + } + return converter.convert(object); + } + // no converter found yet + if (current.getSuperclass() != null) { + toVisit.add(current.getSuperclass()); // add super class if available + } + toVisit.addAll(Arrays.asList(current.getInterfaces())); // add interfaces + } + throw new IllegalArgumentException(String + .format( + "There is no registered PlotPlayer converter for type %s", + object.getClass().getSimpleName() + )); } public static void registerConverter(