3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-11-20 06:50:09 +01:00

Optimizations to extension loading

Dieser Commit ist enthalten in:
RednedEpic 2022-04-24 14:53:47 -05:00
Ursprung 7c8bf330a9
Commit 7f0e5b409f
3 geänderte Dateien mit 69 neuen und 63 gelöschten Zeilen

Datei anzeigen

@ -26,6 +26,7 @@ dependencies {
implementation("com.nukkitx.fastutil", "fastutil-int-boolean-maps", Versions.fastutilVersion) 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-int-maps", Versions.fastutilVersion)
implementation("com.nukkitx.fastutil", "fastutil-object-object-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 // Network libraries
implementation("org.java-websocket", "Java-WebSocket", Versions.websocketVersion) implementation("org.java-websocket", "Java-WebSocket", Versions.websocketVersion)

Datei anzeigen

@ -25,6 +25,8 @@
package org.geysermc.geyser.extension; 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.Extension;
import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.ExtensionDescription;
import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException;
@ -38,7 +40,7 @@ import java.util.Map;
public class GeyserExtensionClassLoader extends URLClassLoader { public class GeyserExtensionClassLoader extends URLClassLoader {
private final GeyserExtensionLoader loader; private final GeyserExtensionLoader loader;
private final Map<String, Class<?>> classes = new HashMap<>(); private final Object2ReferenceMap<String, Class<?>> classes = new Object2ReferenceOpenHashMap<>();
public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, Path path) throws MalformedURLException { public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, Path path) throws MalformedURLException {
super(new URL[] { path.toUri().toURL() }, parent); super(new URL[] { path.toUri().toURL() }, parent);

Datei anzeigen

@ -25,6 +25,8 @@
package org.geysermc.geyser.extension; package org.geysermc.geyser.extension;
import it.unimi.dsi.fastutil.objects.Object2ReferenceMap;
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
@ -51,13 +53,15 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Stream;
@RequiredArgsConstructor @RequiredArgsConstructor
public class GeyserExtensionLoader extends ExtensionLoader { public class GeyserExtensionLoader extends ExtensionLoader {
private static final Path EXTENSION_DIRECTORY = Paths.get("extensions"); 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<String, Class<?>> classes = new HashMap<>(); private final Object2ReferenceMap<String, Class<?>> classes = new Object2ReferenceOpenHashMap<>();
private final Map<String, GeyserExtensionClassLoader> classLoaders = new HashMap<>(); private final Map<String, GeyserExtensionClassLoader> classLoaders = new HashMap<>();
private final Map<Extension, GeyserExtensionContainer> extensionContainers = new HashMap<>(); private final Map<Extension, GeyserExtensionContainer> extensionContainers = new HashMap<>();
@ -105,29 +109,27 @@ public class GeyserExtensionLoader extends ExtensionLoader {
} }
public Pattern[] extensionFilters() { public Pattern[] extensionFilters() {
return new Pattern[] { Pattern.compile("^.+\\.jar$") }; return EXTENSION_FILTERS;
} }
public Class<?> classByName(final String name) throws ClassNotFoundException{ public Class<?> classByName(final String name) throws ClassNotFoundException{
Class<?> clazz = this.classes.get(name); Class<?> clazz = this.classes.get(name);
try { if (clazz != null) {
for (GeyserExtensionClassLoader loader : this.classLoaders.values()) {
if (clazz != null) {
continue;
}
clazz = loader.findClass(name, false);
}
return clazz; 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) { void setClass(String name, final Class<?> clazz) {
if (!this.classes.containsKey(name)) { this.classes.putIfAbsent(name, clazz);
this.classes.put(name,clazz);
}
} }
@Override @Override
@ -149,60 +151,61 @@ public class GeyserExtensionLoader extends ExtensionLoader {
Map<String, GeyserExtensionContainer> loadedExtensions = new LinkedHashMap<>(); Map<String, GeyserExtensionContainer> loadedExtensions = new LinkedHashMap<>();
Pattern[] extensionFilters = this.extensionFilters(); Pattern[] extensionFilters = this.extensionFilters();
try (Stream<Path> entries = Files.walk(EXTENSION_DIRECTORY)) {
Files.walk(EXTENSION_DIRECTORY).forEach(path -> { entries.forEach(path -> {
if (Files.isDirectory(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) {
return; return;
} }
String name = description.name(); for (Pattern filter : extensionFilters) {
if (extensions.containsKey(name) || extensionManager.extension(name) != null) { if (!filter.matcher(path.getFileName().toString()).matches()) {
GeyserImpl.getInstance().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, path.toString())); return;
return; }
} }
try { try {
// Check the format: majorVersion.minorVersion.patch GeyserExtensionDescription description = this.extensionDescription(path);
if (!API_VERSION_PATTERN.matcher(description.apiVersion()).matches()) { if (description == null) {
throw new IllegalArgumentException(); return;
} }
} catch (NullPointerException | IllegalArgumentException e) {
GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_format", name, apiVersion[0] + "." + apiVersion[1])); String name = description.name();
return; 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()) { for (GeyserExtensionContainer container : loadedExtensions.values()) {
this.extensionContainers.put(container.extension(), container); this.extensionContainers.put(container.extension(), container);