mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-23 19:16:14 +01:00
Optimize class lookups
This commit is contained in:
parent
df3b68df4c
commit
0c6fa46871
@ -414,7 +414,7 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
||||
} else if (methods.size() == 1) {
|
||||
// We're in 1.2.5
|
||||
alwaysSync = true;
|
||||
} else if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) {
|
||||
} else if (MinecraftVersion.BOUNTIFUL_UPDATE.atOrAbove()) {
|
||||
// The centralized async marker was removed in 1.8
|
||||
// Incoming chat packets can be async
|
||||
if (event.getPacketType() == PacketType.Play.Client.CHAT) {
|
||||
|
@ -137,8 +137,8 @@ public class StructureCache {
|
||||
Class<?> packetClass = PacketRegistry.getPacketClassFromType(type);
|
||||
|
||||
// We need to map the Bundle Delimiter to the synthetic bundle packet which contains a list of all packets in a bundle
|
||||
if (MinecraftVersion.atOrAbove(MinecraftVersion.FEATURE_PREVIEW_2) && packetClass.equals(MinecraftReflection.getBundleDelimiterClass())) {
|
||||
packetClass = MinecraftReflection.getPackedBundlePacketClass();
|
||||
if (MinecraftReflection.isBundleDelimiter(packetClass)) {
|
||||
packetClass = MinecraftReflection.getPackedBundlePacketClass().get();
|
||||
}
|
||||
|
||||
return new StructureModifier<>(packetClass, MinecraftReflection.getPacketClass(), true);
|
||||
|
@ -204,15 +204,10 @@ public class NettyChannelInjector implements Injector {
|
||||
return false;
|
||||
}
|
||||
|
||||
String anchorHandler = "decoder";
|
||||
if (MinecraftVersion.FEATURE_PREVIEW_2.atOrAbove()) {
|
||||
anchorHandler = "unbundler";
|
||||
}
|
||||
|
||||
// inject our handlers
|
||||
this.wrappedChannel.pipeline().addAfter("encoder", WIRE_PACKET_ENCODER_NAME, WIRE_PACKET_ENCODER);
|
||||
this.wrappedChannel.pipeline().addAfter(
|
||||
anchorHandler,
|
||||
"decoder",
|
||||
INTERCEPTOR_NAME,
|
||||
new InboundPacketInterceptor(this, this.channelListener));
|
||||
|
||||
|
@ -36,7 +36,7 @@ final class CachedPackage {
|
||||
* @param packageName - the name of the current package.
|
||||
* @param source - the class source.
|
||||
*/
|
||||
public CachedPackage(String packageName, ClassSource source) {
|
||||
CachedPackage(String packageName, ClassSource source) {
|
||||
this.source = source;
|
||||
this.packageName = packageName;
|
||||
this.cache = new ConcurrentHashMap<>();
|
||||
@ -71,6 +71,16 @@ final class CachedPackage {
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Class<?>> resolveClass(String className) {
|
||||
return source.loadClass(combine(packageName, className));
|
||||
}
|
||||
|
||||
public Class<?> requireClass(String className) throws ClassNotFoundException {
|
||||
String canonicalName = combine(packageName, className);
|
||||
return source.loadClass(canonicalName)
|
||||
.orElseThrow(() -> new ClassNotFoundException(className));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the class object of a specific class in the current package.
|
||||
*
|
||||
@ -78,13 +88,21 @@ final class CachedPackage {
|
||||
* @return Class object.
|
||||
* @throws RuntimeException If we are unable to find the given class.
|
||||
*/
|
||||
public Optional<Class<?>> getPackageClass(final String className) {
|
||||
return this.cache.computeIfAbsent(className, x -> {
|
||||
try {
|
||||
return Optional.ofNullable(this.source.loadClass(combine(this.packageName, className)));
|
||||
} catch (ClassNotFoundException ex) {
|
||||
return Optional.empty();
|
||||
public Optional<Class<?>> getPackageClass(String className, String... aliases) {
|
||||
return cache.computeIfAbsent(className, x -> {
|
||||
Optional<Class<?>> clazz = resolveClass(className);
|
||||
if (clazz.isPresent()) {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
for (String alias : aliases) {
|
||||
clazz = resolveClass(className);
|
||||
if (clazz.isPresent()) {
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package com.comphenix.protocol.utility;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Represents an abstract class loader that can only retrieve classes by their canonical name.
|
||||
@ -37,27 +39,25 @@ public interface ClassSource {
|
||||
* @return The corresponding class source.
|
||||
*/
|
||||
static ClassSource fromClassLoader(final ClassLoader loader) {
|
||||
return loader::loadClass;
|
||||
return canonicalName -> {
|
||||
try {
|
||||
return Optional.of(loader.loadClass(canonicalName));
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class source from a mapping of canonical names and the corresponding classes. If the map is null, it
|
||||
* will be interpreted as an empty map. If the map does not contain a Class with the specified name, or that string
|
||||
* maps to NULL explicitly, a {@link ClassNotFoundException} will be thrown.
|
||||
* maps to NULL explicitly, an empty optional will be returned
|
||||
*
|
||||
* @param map - map of class names and classes.
|
||||
* @return The class source.
|
||||
*/
|
||||
static ClassSource fromMap(final Map<String, Class<?>> map) {
|
||||
return canonicalName -> {
|
||||
Class<?> loaded = map == null ? null : map.get(canonicalName);
|
||||
if (loaded == null) {
|
||||
// Throw the appropriate exception if we can't load the class
|
||||
throw new ClassNotFoundException("The specified class could not be found by this ClassLoader.");
|
||||
}
|
||||
|
||||
return loaded;
|
||||
};
|
||||
return canonicalName -> Optional.ofNullable(map.get(canonicalName));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,14 +94,8 @@ public interface ClassSource {
|
||||
* @param other - the other class source.
|
||||
* @return A new class source.
|
||||
*/
|
||||
default ClassSource retry(final ClassSource other) {
|
||||
return canonicalName -> {
|
||||
try {
|
||||
return ClassSource.this.loadClass(canonicalName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return other.loadClass(canonicalName);
|
||||
}
|
||||
};
|
||||
default ClassSource retry(ClassSource other) {
|
||||
return canonicalName -> Optionals.or(loadClass(canonicalName), () -> other.loadClass(canonicalName));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,12 +109,9 @@ public interface ClassSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class by name.
|
||||
*
|
||||
* @param canonicalName - the full canonical name of the class.
|
||||
* @return The corresponding class. If the class is not found, NULL should <b>not</b> be returned, instead a {@code
|
||||
* ClassNotFoundException} exception should be thrown.
|
||||
* @throws ClassNotFoundException If the class could not be found.
|
||||
* Retrieve a class by its canonical name
|
||||
* @param canonicalName The class's canonical name, i.e. java.lang.Object
|
||||
* @return Optional that may contain a Class
|
||||
*/
|
||||
Class<?> loadClass(String canonicalName) throws ClassNotFoundException;
|
||||
Optional<Class<?>> loadClass(String canonicalName);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import java.lang.reflect.ParameterizedType;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@ -628,16 +629,20 @@ public final class MinecraftReflection {
|
||||
return getMinecraftClass("network.chat.IChatBaseComponent", "network.chat.IChatbaseComponent", "network.chat.Component", "IChatBaseComponent");
|
||||
}
|
||||
|
||||
public static Class<?> getPackedBundlePacketClass() {
|
||||
return getMinecraftClass("network.protocol.game.ClientboundBundlePacket", "ClientboundBundlePacket");
|
||||
public static Optional<Class<?>> getPackedBundlePacketClass() {
|
||||
return getOptionalNMS("network.protocol.game.ClientboundBundlePacket", "ClientboundBundlePacket");
|
||||
}
|
||||
|
||||
public static boolean isBundlePacket(Class<?> packetClass) {
|
||||
return MinecraftVersion.FEATURE_PREVIEW_2.atOrAbove() && packetClass.equals(getPackedBundlePacketClass());
|
||||
return Optionals.Equals(getPackedBundlePacketClass(), packetClass);
|
||||
}
|
||||
|
||||
public static Class<?> getBundleDelimiterClass() {
|
||||
return getMinecraftClass("network.protocol.BundleDelimiterPacket","BundleDelimiterPacket");
|
||||
public static boolean isBundleDelimiter(Class<?> packetClass) {
|
||||
return Optionals.Equals(getBundleDelimiterClass(), packetClass);
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> getBundleDelimiterClass() {
|
||||
return getOptionalNMS("network.protocol.BundleDelimiterPacket","BundleDelimiterPacket");
|
||||
}
|
||||
|
||||
public static Class<?> getIChatBaseComponentArrayClass() {
|
||||
@ -1337,11 +1342,8 @@ public final class MinecraftReflection {
|
||||
* @return The class.
|
||||
*/
|
||||
private static Class<?> getClass(String className) {
|
||||
try {
|
||||
return getClassSource().loadClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Cannot find class " + className, e);
|
||||
}
|
||||
return getClassSource().loadClass(className)
|
||||
.orElseThrow(() -> new RuntimeException("Cannot find class " + className));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1376,12 +1378,34 @@ public final class MinecraftReflection {
|
||||
.orElseThrow(() -> new RuntimeException("Failed to find NMS class: " + className));
|
||||
}
|
||||
|
||||
public static Class<?> getNullableNMS(String className, String... aliases) {
|
||||
try {
|
||||
return getMinecraftClass(className, aliases);
|
||||
} catch (RuntimeException ex) {
|
||||
return null;
|
||||
/**
|
||||
* Optionally retrieve the class object of a NMS (net.minecraft.server) class.
|
||||
* If the class does not exist, the optional will be empty
|
||||
*
|
||||
* @param className NMS class name
|
||||
* @param aliases Potential aliases
|
||||
* @return Optional that may contain the class
|
||||
*/
|
||||
private static Optional<Class<?>> getOptionalNMS(String className, String... aliases) {
|
||||
if (minecraftPackage == null) {
|
||||
minecraftPackage = new CachedPackage(getMinecraftPackage(), getClassSource());
|
||||
}
|
||||
|
||||
return minecraftPackage.getPackageClass(className, aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a nullable NMS (net.minecraft.server) class. We will attempt to
|
||||
* look up the class and its aliases, but will return null if none is found.
|
||||
*
|
||||
* @deprecated - Use getOptionalNMS where possible
|
||||
* @param className NMS class name
|
||||
* @param aliases Potential aliases
|
||||
* @return The class, or null if not found
|
||||
*/
|
||||
@Deprecated
|
||||
public static Class<?> getNullableNMS(String className, String... aliases) {
|
||||
return getOptionalNMS(className, aliases).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1418,29 +1442,8 @@ public final class MinecraftReflection {
|
||||
* @throws RuntimeException If we are unable to find any of the given classes.
|
||||
*/
|
||||
public static Class<?> getMinecraftClass(String className, String... aliases) {
|
||||
if (minecraftPackage == null) {
|
||||
minecraftPackage = new CachedPackage(getMinecraftPackage(), getClassSource());
|
||||
}
|
||||
|
||||
return minecraftPackage.getPackageClass(className).orElseGet(() -> {
|
||||
Class<?> resolved = null;
|
||||
for (String alias : aliases) {
|
||||
// try to resolve the class and stop searching if we found it
|
||||
resolved = minecraftPackage.getPackageClass(alias).orElse(null);
|
||||
if (resolved != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we resolved the class cache it and return the result
|
||||
if (resolved != null) {
|
||||
minecraftPackage.setPackageClass(className, resolved);
|
||||
return resolved;
|
||||
}
|
||||
|
||||
// unable to find the class
|
||||
throw new RuntimeException(String.format("Unable to find %s (%s)", className, String.join(", ", aliases)));
|
||||
});
|
||||
return getOptionalNMS(className, aliases)
|
||||
.orElseThrow(() -> new RuntimeException(String.format("Unable to find %s (%s)", className, String.join(", ", aliases))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -273,7 +273,7 @@ public final class MinecraftVersion implements Comparable<MinecraftVersion>, Ser
|
||||
currentVersion = version;
|
||||
}
|
||||
|
||||
public static boolean atOrAbove(MinecraftVersion version) {
|
||||
private static boolean atOrAbove(MinecraftVersion version) {
|
||||
return getCurrentVersion().isAtLeast(version);
|
||||
}
|
||||
|
||||
@ -354,7 +354,7 @@ public final class MinecraftVersion implements Comparable<MinecraftVersion>, Ser
|
||||
*/
|
||||
public boolean atOrAbove() {
|
||||
if (this.atCurrentOrAbove == null) {
|
||||
this.atCurrentOrAbove = MinecraftVersion.atOrAbove(this);
|
||||
this.atCurrentOrAbove = atOrAbove(this);
|
||||
}
|
||||
|
||||
return this.atCurrentOrAbove;
|
||||
|
45
src/main/java/com/comphenix/protocol/utility/Optionals.java
Normal file
45
src/main/java/com/comphenix/protocol/utility/Optionals.java
Normal file
@ -0,0 +1,45 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Utility methods for operating with Optionals
|
||||
*/
|
||||
public final class Optionals {
|
||||
|
||||
/**
|
||||
* Chains two optionals together by returning the secondary
|
||||
* optional if the primary does not contain a value
|
||||
* @param primary Primary optional
|
||||
* @param secondary Supplier of secondary optional
|
||||
* @return The resulting optional
|
||||
* @param <T> Type
|
||||
*/
|
||||
public static <T> Optional<T> or(Optional<T> primary, Supplier<Optional<T>> secondary) {
|
||||
return primary.isPresent() ? primary : secondary.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the provided predicate against the optional only if it is present
|
||||
* @param optional Optional
|
||||
* @param predicate Test to run against potential value
|
||||
* @return True if the optional is present and the predicate passes
|
||||
* @param <T> Type
|
||||
*/
|
||||
public static <T> boolean TestIfPresent(Optional<T> optional, Predicate<T> predicate) {
|
||||
return optional.isPresent() && predicate.test(optional.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the optional has a value and its value equals the provided value
|
||||
* @param optional Optional
|
||||
* @param contents Contents to test for
|
||||
* @return True if the optional has a value and that value equals the parameter
|
||||
* @param <T> Type
|
||||
*/
|
||||
public static <T> boolean Equals(Optional<T> optional, Class<?> contents) {
|
||||
return optional.isPresent() && contents.equals(optional.get());
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -144,14 +145,8 @@ public class TroveWrapper {
|
||||
throw new IllegalArgumentException("trove instance cannot be non-null.");
|
||||
|
||||
AbstractFuzzyMatcher<Class<?>> match = FuzzyMatchers.matchSuper(trove.getClass());
|
||||
Class<?> decorators = null;
|
||||
|
||||
try {
|
||||
// Attempt to get decorator class
|
||||
decorators = getClassSource(trove.getClass()).loadClass("TDecorators");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException(e.getMessage(), e);
|
||||
}
|
||||
Class<?> decorators = getClassSource(trove.getClass()).loadClass("TDecorator")
|
||||
.orElseThrow(() -> new IllegalStateException("TDecorators class not found"));
|
||||
|
||||
// Find an appropriate wrapper method in TDecorators
|
||||
for (Method method : decorators.getMethods()) {
|
||||
|
@ -22,7 +22,7 @@ import com.google.common.base.Preconditions;
|
||||
* @author Kristian
|
||||
*/
|
||||
public class WrappedAttributeModifier extends AbstractWrapper {
|
||||
private static final boolean OPERATION_ENUM = MinecraftVersion.atOrAbove(MinecraftVersion.VILLAGE_UPDATE);
|
||||
private static final boolean OPERATION_ENUM = MinecraftVersion.VILLAGE_UPDATE.atOrAbove();
|
||||
private static final Class<?> OPERATION_CLASS;
|
||||
private static final EquivalentConverter<Operation> OPERATION_CONVERTER;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user