diff --git a/core/build.gradle.kts b/core/build.gradle.kts index fbdd3a116..abf703110 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -26,6 +26,7 @@ dependencies { implementation("com.nukkitx.fastutil", "fastutil-int-boolean-maps", Versions.fastutilVersion) implementation("com.nukkitx.fastutil", "fastutil-object-int-maps", Versions.fastutilVersion) implementation("com.nukkitx.fastutil", "fastutil-object-object-maps", Versions.fastutilVersion) + implementation("com.nukkitx.fastutil", "fastutil-object-reference-maps", Versions.fastutilVersion) // Network libraries implementation("org.java-websocket", "Java-WebSocket", Versions.websocketVersion) diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java index 71311b305..19e2765e8 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.extension; +import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; @@ -38,7 +40,7 @@ import java.util.Map; public class GeyserExtensionClassLoader extends URLClassLoader { private final GeyserExtensionLoader loader; - private final Map> classes = new HashMap<>(); + private final Object2ReferenceMap> classes = new Object2ReferenceOpenHashMap<>(); public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, Path path) throws MalformedURLException { super(new URL[] { path.toUri().toURL() }, parent); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index ac8da2679..676231c5b 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.extension; +import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.geyser.GeyserImpl; @@ -51,13 +53,15 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; +import java.util.stream.Stream; @RequiredArgsConstructor public class GeyserExtensionLoader extends ExtensionLoader { private static final Path EXTENSION_DIRECTORY = Paths.get("extensions"); - private static final Pattern API_VERSION_PATTERN = Pattern.compile("^[0-9]+\\.[0-9]+\\.[0-9]+$"); + private static final Pattern API_VERSION_PATTERN = Pattern.compile("^\\d+\\.\\d+\\.\\d+$"); + private static final Pattern[] EXTENSION_FILTERS = new Pattern[] { Pattern.compile("^.+\\.jar$") }; - private final Map> classes = new HashMap<>(); + private final Object2ReferenceMap> classes = new Object2ReferenceOpenHashMap<>(); private final Map classLoaders = new HashMap<>(); private final Map extensionContainers = new HashMap<>(); @@ -105,29 +109,27 @@ public class GeyserExtensionLoader extends ExtensionLoader { } public Pattern[] extensionFilters() { - return new Pattern[] { Pattern.compile("^.+\\.jar$") }; + return EXTENSION_FILTERS; } public Class classByName(final String name) throws ClassNotFoundException{ Class clazz = this.classes.get(name); - try { - for (GeyserExtensionClassLoader loader : this.classLoaders.values()) { - if (clazz != null) { - continue; - } - - clazz = loader.findClass(name, false); - } + if (clazz != null) { return clazz; - } catch (NullPointerException s) { - return null; } + + for (GeyserExtensionClassLoader loader : this.classLoaders.values()) { + clazz = loader.findClass(name, false); + if (clazz != null) { + break; + } + } + + return clazz; } void setClass(String name, final Class clazz) { - if (!this.classes.containsKey(name)) { - this.classes.put(name,clazz); - } + this.classes.putIfAbsent(name, clazz); } @Override @@ -149,60 +151,61 @@ public class GeyserExtensionLoader extends ExtensionLoader { Map loadedExtensions = new LinkedHashMap<>(); Pattern[] extensionFilters = this.extensionFilters(); - - Files.walk(EXTENSION_DIRECTORY).forEach(path -> { - if (Files.isDirectory(path)) { - return; - } - - for (Pattern filter : extensionFilters) { - if (!filter.matcher(path.getFileName().toString()).matches()) { - return; - } - } - - try { - GeyserExtensionDescription description = this.extensionDescription(path); - if (description == null) { + try (Stream entries = Files.walk(EXTENSION_DIRECTORY)) { + entries.forEach(path -> { + if (Files.isDirectory(path)) { return; } - String name = description.name(); - if (extensions.containsKey(name) || extensionManager.extension(name) != null) { - GeyserImpl.getInstance().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, path.toString())); - return; + for (Pattern filter : extensionFilters) { + if (!filter.matcher(path.getFileName().toString()).matches()) { + return; + } } try { - // Check the format: majorVersion.minorVersion.patch - if (!API_VERSION_PATTERN.matcher(description.apiVersion()).matches()) { - throw new IllegalArgumentException(); + GeyserExtensionDescription description = this.extensionDescription(path); + if (description == null) { + return; } - } catch (NullPointerException | IllegalArgumentException e) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, apiVersion[0] + "." + apiVersion[1])); - return; + + String name = description.name(); + if (extensions.containsKey(name) || extensionManager.extension(name) != null) { + GeyserImpl.getInstance().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, path.toString())); + return; + } + + try { + // Check the format: majorVersion.minorVersion.patch + if (!API_VERSION_PATTERN.matcher(description.apiVersion()).matches()) { + throw new IllegalArgumentException(); + } + } catch (NullPointerException | IllegalArgumentException e) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, apiVersion[0] + "." + apiVersion[1])); + return; + } + + String[] versionArray = description.apiVersion().split("\\."); + + // Completely different API version + if (!Objects.equals(Integer.valueOf(versionArray[0]), Integer.valueOf(apiVersion[0]))) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, apiVersion[0] + "." + apiVersion[1])); + return; + } + + // If the extension requires new API features, being backwards compatible + if (Integer.parseInt(versionArray[1]) > Integer.parseInt(apiVersion[1])) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, apiVersion[0] + "." + apiVersion[1])); + return; + } + + extensions.put(name, path); + loadedExtensions.put(name, this.loadExtension(path, description)); + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_with_name", path.getFileName(), path.toAbsolutePath()), e); } - - String[] versionArray = description.apiVersion().split("\\."); - - // Completely different API version - if (!Objects.equals(Integer.valueOf(versionArray[0]), Integer.valueOf(apiVersion[0]))) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, apiVersion[0] + "." + apiVersion[1])); - return; - } - - // If the extension requires new API features, being backwards compatible - if (Integer.parseInt(versionArray[1]) > Integer.parseInt(apiVersion[1])) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, apiVersion[0] + "." + apiVersion[1])); - return; - } - - extensions.put(name, path); - loadedExtensions.put(name, this.loadExtension(path, description)); - } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_with_name", path.getFileName(), path.toAbsolutePath()), e); - } - }); + }); + } for (GeyserExtensionContainer container : loadedExtensions.values()) { this.extensionContainers.put(container.extension(), container);