mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-01 05:58:00 +01:00
Cleanup and improve extension changes.
This commit is contained in:
parent
535e8946b6
commit
5217964259
@ -2,13 +2,114 @@ package net.minestom.server.extensions;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Slf4j
|
||||
class DiscoveredExtension {
|
||||
private static String NAME_REGEX = "[A-Za-z][_A-Za-z0-9]+";
|
||||
@Slf4j(topic = "minestom-extensions")
|
||||
final class DiscoveredExtension {
|
||||
public static final String NAME_REGEX = "[A-Za-z][_A-Za-z0-9]+";
|
||||
private String name;
|
||||
private String entrypoint;
|
||||
private String version;
|
||||
private String mixinConfig;
|
||||
private String[] authors;
|
||||
private String[] codeModifiers;
|
||||
private Dependencies dependencies;
|
||||
transient File[] files = new File[0];
|
||||
transient LoadStatus loadStatus = LoadStatus.LOAD_SUCCESS;
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String[] getCodeModifiers() {
|
||||
if (codeModifiers == null) {
|
||||
codeModifiers = new String[0];
|
||||
}
|
||||
return codeModifiers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getMixinConfig() {
|
||||
return mixinConfig;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String[] getAuthors() {
|
||||
return authors;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getEntrypoint() {
|
||||
return entrypoint;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Dependencies getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
static void verifyIntegrity(@NotNull DiscoveredExtension extension) {
|
||||
if (extension.name == null) {
|
||||
StringBuilder fileList = new StringBuilder();
|
||||
for (File f : extension.files) {
|
||||
fileList.append(f.getAbsolutePath()).append(", ");
|
||||
}
|
||||
log.error("Extension with no name. (at {}})", fileList);
|
||||
log.error("Extension at ({}) will not be loaded.", fileList);
|
||||
extension.loadStatus = DiscoveredExtension.LoadStatus.INVALID_NAME;
|
||||
|
||||
// To ensure @NotNull: name = INVALID_NAME
|
||||
extension.name = extension.loadStatus.name();
|
||||
return;
|
||||
}
|
||||
if (!extension.name.matches(NAME_REGEX)) {
|
||||
log.error("Extension '{}' specified an invalid name.", extension.name);
|
||||
log.error("Extension '{}' will not be loaded.", extension.name);
|
||||
extension.loadStatus = DiscoveredExtension.LoadStatus.INVALID_NAME;
|
||||
|
||||
// To ensure @NotNull: name = INVALID_NAME
|
||||
extension.name = extension.loadStatus.name();
|
||||
return;
|
||||
}
|
||||
if (extension.entrypoint == null) {
|
||||
log.error("Extension '{}' did not specify an entry point (via 'entrypoint').", extension.name);
|
||||
log.error("Extension '{}' will not be loaded.", extension.name);
|
||||
extension.loadStatus = DiscoveredExtension.LoadStatus.NO_ENTRYPOINT;
|
||||
|
||||
// To ensure @NotNull: entrypoint = NO_ENTRYPOINT
|
||||
extension.entrypoint = extension.loadStatus.name();
|
||||
return;
|
||||
}
|
||||
// Handle defaults
|
||||
// If we reach this code, then the extension will most likely be loaded:
|
||||
if (extension.version == null) {
|
||||
log.warn("Extension '{}' did not specify a version.", extension.name);
|
||||
log.warn("Extension '{}' will continue to load but should specify a plugin version.", extension.name);
|
||||
extension.version = "Unspecified";
|
||||
}
|
||||
if (extension.mixinConfig == null) {
|
||||
extension.mixinConfig = "";
|
||||
}
|
||||
if (extension.authors == null) {
|
||||
extension.authors = new String[0];
|
||||
}
|
||||
if (extension.codeModifiers == null) {
|
||||
extension.codeModifiers = new String[0];
|
||||
}
|
||||
// No dependencies were specified
|
||||
if (extension.dependencies == null) {
|
||||
extension.dependencies = new Dependencies();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum LoadStatus {
|
||||
LOAD_SUCCESS("Actually, it did not fail. This message should not have been printed."),
|
||||
@ -19,102 +120,23 @@ class DiscoveredExtension {
|
||||
|
||||
private final String message;
|
||||
|
||||
LoadStatus(String message) {
|
||||
LoadStatus(@NotNull String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
static class Dependencies {
|
||||
static final class Dependencies {
|
||||
Repository[] repositories = new Repository[0];
|
||||
String[] artifacts = new String[0];
|
||||
|
||||
static class Repository {
|
||||
String name;
|
||||
String url;
|
||||
String name = "";
|
||||
String url = "";
|
||||
}
|
||||
|
||||
Repository[] repositories;
|
||||
String[] artifacts;
|
||||
}
|
||||
|
||||
transient File[] files = new File[0];
|
||||
transient LoadStatus loadStatus = LoadStatus.LOAD_SUCCESS;
|
||||
|
||||
private String[] codeModifiers;
|
||||
private String[] authors;
|
||||
private String mixinConfig;
|
||||
private String name;
|
||||
private String version;
|
||||
private String entrypoint;
|
||||
private Dependencies dependencies;
|
||||
|
||||
void checkIntegrity() {
|
||||
if(name == null) {
|
||||
StringBuilder fileList = new StringBuilder();
|
||||
for(File f : files) {
|
||||
fileList.append(f.getAbsolutePath()).append(", ");
|
||||
}
|
||||
log.error("Extension with no name. (at {}})", fileList);
|
||||
log.error("Extension at ({}) will not be loaded.", fileList);
|
||||
loadStatus = LoadStatus.INVALID_NAME;
|
||||
return;
|
||||
}
|
||||
if(!name.matches(NAME_REGEX)) {
|
||||
log.error("Extension '{}' specified an invalid name.", name);
|
||||
log.error("Extension '{}' will not be loaded.", name);
|
||||
loadStatus = LoadStatus.INVALID_NAME;
|
||||
return;
|
||||
}
|
||||
if(entrypoint == null) {
|
||||
log.error("Extension '{}' did not specify an entry point (via 'entrypoint').", name);
|
||||
log.error("Extension '{}' will not be loaded.", name);
|
||||
loadStatus = LoadStatus.NO_ENTRYPOINT;
|
||||
return;
|
||||
}
|
||||
if(codeModifiers == null) {
|
||||
codeModifiers = new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
if(name == null) {
|
||||
throw new IllegalStateException("Missing extension name");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String[] getCodeModifiers() {
|
||||
if(codeModifiers == null) {
|
||||
codeModifiers = new String[0];
|
||||
}
|
||||
return codeModifiers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMixinConfig() {
|
||||
return mixinConfig;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String[] getAuthors() {
|
||||
return authors;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getEntrypoint() {
|
||||
return entrypoint;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Dependencies getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
package net.minestom.server.extensions;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class Extension {
|
||||
// Set by reflection
|
||||
@SuppressWarnings("unused")
|
||||
private ExtensionDescription description;
|
||||
// Set by reflection
|
||||
@SuppressWarnings("unused")
|
||||
private Logger logger;
|
||||
|
||||
protected Extension() {
|
||||
@ -35,23 +37,25 @@ public abstract class Extension {
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ExtensionDescription getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
protected static class ExtensionDescription {
|
||||
public static class ExtensionDescription {
|
||||
private final String name;
|
||||
private final String version;
|
||||
private final List<String> authors;
|
||||
|
||||
protected ExtensionDescription(@NotNull String name, @NotNull String version, @Nullable List<String> authors) {
|
||||
ExtensionDescription(@NotNull String name, @NotNull String version, @NotNull List<String> authors) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.authors = authors != null ? authors : new ArrayList<>();
|
||||
this.authors = authors;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
@ -22,10 +22,15 @@ import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
@Slf4j
|
||||
@Slf4j(topic = "Minestom-Extensions")
|
||||
public class ExtensionManager {
|
||||
|
||||
private final static String INDEV_CLASSES_FOLDER = "minestom.extension.indevfolder.classes";
|
||||
@ -78,28 +83,14 @@ public class ExtensionManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get ExtensionDescription (authors, version etc.)
|
||||
// Create ExtensionDescription (authors, version etc.)
|
||||
String extensionName = discoveredExtension.getName();
|
||||
String mainClass = discoveredExtension.getEntrypoint();
|
||||
Extension.ExtensionDescription extensionDescription;
|
||||
{
|
||||
String version;
|
||||
if (discoveredExtension.getVersion() == null) {
|
||||
log.warn("Extension '{}' did not specify a version.", extensionName);
|
||||
log.warn("Extension '{}' will continue to load but should specify a plugin version.", extensionName);
|
||||
version = "Not Specified";
|
||||
} else {
|
||||
version = discoveredExtension.getVersion();
|
||||
}
|
||||
List<String> authors;
|
||||
if (discoveredExtension.getAuthors() == null) {
|
||||
authors = new ArrayList<>();
|
||||
} else {
|
||||
authors = Arrays.asList(discoveredExtension.getAuthors());
|
||||
}
|
||||
|
||||
extensionDescription = new Extension.ExtensionDescription(extensionName, version, authors);
|
||||
}
|
||||
Extension.ExtensionDescription extensionDescription = new Extension.ExtensionDescription(
|
||||
extensionName,
|
||||
discoveredExtension.getVersion(),
|
||||
Arrays.asList(discoveredExtension.getAuthors())
|
||||
);
|
||||
|
||||
extensionLoaders.put(extensionName.toLowerCase(), loader);
|
||||
|
||||
@ -165,9 +156,9 @@ public class ExtensionManager {
|
||||
|
||||
// Set logger
|
||||
try {
|
||||
Field descriptionField = extensionClass.getSuperclass().getDeclaredField("logger");
|
||||
descriptionField.setAccessible(true);
|
||||
descriptionField.set(extension, LoggerFactory.getLogger(extensionClass));
|
||||
Field loggerField = extensionClass.getSuperclass().getDeclaredField("logger");
|
||||
loggerField.setAccessible(true);
|
||||
loggerField.set(extension, LoggerFactory.getLogger(extensionClass));
|
||||
} catch (IllegalAccessException e) {
|
||||
// We made it accessible, should not occur
|
||||
e.printStackTrace();
|
||||
@ -181,29 +172,29 @@ public class ExtensionManager {
|
||||
}
|
||||
|
||||
private void loadDependencies(List<DiscoveredExtension> extensions) {
|
||||
for(DiscoveredExtension ext : extensions) {
|
||||
for (DiscoveredExtension ext : extensions) {
|
||||
try {
|
||||
DependencyGetter getter = new DependencyGetter();
|
||||
DiscoveredExtension.Dependencies dependencies = ext.getDependencies();
|
||||
if(dependencies.repositories == null) {
|
||||
throw new IllegalStateException("Missing 'repositories' array.");
|
||||
}
|
||||
if(dependencies.artifacts == null) {
|
||||
throw new IllegalStateException("Missing 'artifacts' array.");
|
||||
}
|
||||
List<MavenRepository> repoList = new LinkedList<>();
|
||||
for(var repository : dependencies.repositories) {
|
||||
if(repository.name == null) {
|
||||
for (var repository : dependencies.repositories) {
|
||||
if (repository.name == null) {
|
||||
throw new IllegalStateException("Missing 'name' element in repository object.");
|
||||
}
|
||||
if(repository.url == null) {
|
||||
if (repository.name.isEmpty()) {
|
||||
throw new IllegalStateException("Invalid 'name' element in repository object.");
|
||||
}
|
||||
if (repository.url == null) {
|
||||
throw new IllegalStateException("Missing 'url' element in repository object.");
|
||||
}
|
||||
if (repository.url.isEmpty()) {
|
||||
throw new IllegalStateException("Invalid 'url' element in repository object.");
|
||||
}
|
||||
repoList.add(new MavenRepository(repository.name, repository.url));
|
||||
}
|
||||
getter.addMavenResolver(repoList);
|
||||
|
||||
for(var artifact : dependencies.artifacts) {
|
||||
for (var artifact : dependencies.artifacts) {
|
||||
var resolved = getter.get(artifact, dependenciesFolder);
|
||||
injectIntoClasspath(resolved.getContentsLocation(), ext);
|
||||
log.trace("Dependency of extension {}: {}", ext.getName(), resolved);
|
||||
@ -227,7 +218,7 @@ public class ExtensionManager {
|
||||
addURL.setAccessible(true);
|
||||
addURL.invoke(cl, dependency);
|
||||
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
throw new RuntimeException("Failed to inject URL "+dependency+" into classpath. From extension "+extension.getName(), e);
|
||||
throw new RuntimeException("Failed to inject URL " + dependency + " into classpath. From extension " + extension.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,8 +237,11 @@ public class ExtensionManager {
|
||||
|
||||
DiscoveredExtension extension = GSON.fromJson(reader, DiscoveredExtension.class);
|
||||
extension.files = new File[]{file};
|
||||
extension.checkIntegrity();
|
||||
if(extension.loadStatus == DiscoveredExtension.LoadStatus.LOAD_SUCCESS) {
|
||||
|
||||
// Verify integrity and ensure defaults
|
||||
DiscoveredExtension.verifyIntegrity(extension);
|
||||
|
||||
if (extension.loadStatus == DiscoveredExtension.LoadStatus.LOAD_SUCCESS) {
|
||||
extensions.add(extension);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@ -263,8 +257,11 @@ public class ExtensionManager {
|
||||
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(new File(extensionResources, "extension.json")))) {
|
||||
DiscoveredExtension extension = GSON.fromJson(reader, DiscoveredExtension.class);
|
||||
extension.files = new File[]{new File(extensionClasses), new File(extensionResources)};
|
||||
extension.checkIntegrity();
|
||||
if(extension.loadStatus == DiscoveredExtension.LoadStatus.LOAD_SUCCESS) {
|
||||
|
||||
// Verify integrity and ensure defaults
|
||||
DiscoveredExtension.verifyIntegrity(extension);
|
||||
|
||||
if (extension.loadStatus == DiscoveredExtension.LoadStatus.LOAD_SUCCESS) {
|
||||
extensions.add(extension);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@ -320,7 +317,7 @@ public class ExtensionManager {
|
||||
for (String codeModifierClass : extension.getCodeModifiers()) {
|
||||
modifiableClassLoader.loadModifier(extension.files, codeModifierClass);
|
||||
}
|
||||
if (extension.getMixinConfig() != null) {
|
||||
if (!extension.getMixinConfig().isEmpty()) {
|
||||
final String mixinConfigFile = extension.getMixinConfig();
|
||||
Mixins.addConfiguration(mixinConfigFile);
|
||||
log.info("Found mixin in extension " + extension.getName() + ": " + mixinConfigFile);
|
||||
|
Loading…
Reference in New Issue
Block a user