diff --git a/src/main/java/net/minestom/server/Bootstrap.java b/src/main/java/net/minestom/server/Bootstrap.java deleted file mode 100644 index 1ae15c8bc..000000000 --- a/src/main/java/net/minestom/server/Bootstrap.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.minestom.server; - -import net.minestom.server.extras.selfmodification.MinestomRootClassLoader; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Used to launch Minestom with the {@link MinestomRootClassLoader} to allow for self-modifications - */ -public final class Bootstrap { - - public static void bootstrap(String mainClassFullName, String[] args) { - try { - ClassLoader classLoader = MinestomRootClassLoader.getInstance(); - - Class mainClass = classLoader.loadClass(mainClassFullName); - Method main = mainClass.getDeclaredMethod("main", String[].class); - main.setAccessible(true); - main.invoke(null, new Object[]{args}); - } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException | ClassNotFoundException e) { - e.printStackTrace(); - } - } -} diff --git a/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java b/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java index d2e960349..637e20da1 100644 --- a/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java +++ b/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java @@ -2,8 +2,7 @@ package net.minestom.server.extensions; import com.google.gson.JsonObject; import net.minestom.server.MinecraftServer; -import net.minestom.server.extras.selfmodification.MinestomExtensionClassLoader; -import net.minestom.server.extras.selfmodification.MinestomRootClassLoader; +import net.minestom.server.extensions.isolation.MinestomExtensionClassLoader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -15,7 +14,6 @@ import java.nio.file.Path; import java.util.Arrays; import java.util.LinkedList; import java.util.List; -import java.util.Locale; /** * Represents an extension from an `extension.json` that is capable of powering an Extension object. @@ -211,7 +209,7 @@ public final class DiscoveredExtension { public MinestomExtensionClassLoader makeClassLoader(List discoveredExtensions) { final URL[] urls = this.files.toArray(new URL[0]); - MinestomExtensionClassLoader loader = new MinestomExtensionClassLoader(this.getName(), this.getEntrypoint(), urls, MinecraftServer.class.getClassLoader()); + MinestomExtensionClassLoader loader = new MinestomExtensionClassLoader(this.getName(), urls); System.out.println("CREATED " + loader + " WITH " + Arrays.toString(urls)); diff --git a/src/main/java/net/minestom/server/extensions/ExtensionManager.java b/src/main/java/net/minestom/server/extensions/ExtensionManager.java index cc3189267..4c8b90960 100644 --- a/src/main/java/net/minestom/server/extensions/ExtensionManager.java +++ b/src/main/java/net/minestom/server/extensions/ExtensionManager.java @@ -7,8 +7,7 @@ import net.minestom.dependencies.maven.MavenRepository; import net.minestom.server.MinecraftServer; import net.minestom.server.event.Event; import net.minestom.server.event.EventNode; -import net.minestom.server.extras.selfmodification.MinestomExtensionClassLoader; -import net.minestom.server.extras.selfmodification.MinestomRootClassLoader; +import net.minestom.server.extensions.isolation.MinestomExtensionClassLoader; import net.minestom.server.ping.ResponseDataConsumer; import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.validate.Check; @@ -644,7 +643,8 @@ public class ExtensionManager { } catch (IOException e) { MinecraftServer.getExceptionManager().handleException(e); } - MinestomRootClassLoader.getInstance().removeChildInHierarchy(classloader); + //TODO : Remove extension from dependents +// MinestomRootClassLoader.getInstance().removeChildInHierarchy(classloader); } public boolean reload(@NotNull String extensionName) { diff --git a/src/main/java/net/minestom/server/extras/selfmodification/HierarchyClassLoader.java b/src/main/java/net/minestom/server/extensions/isolation/HierarchyClassLoader.java similarity index 63% rename from src/main/java/net/minestom/server/extras/selfmodification/HierarchyClassLoader.java rename to src/main/java/net/minestom/server/extensions/isolation/HierarchyClassLoader.java index be464fb26..2542c448b 100644 --- a/src/main/java/net/minestom/server/extras/selfmodification/HierarchyClassLoader.java +++ b/src/main/java/net/minestom/server/extensions/isolation/HierarchyClassLoader.java @@ -1,4 +1,4 @@ -package net.minestom.server.extras.selfmodification; +package net.minestom.server.extensions.isolation; import org.jetbrains.annotations.NotNull; @@ -22,6 +22,24 @@ public abstract class HierarchyClassLoader extends URLClassLoader { children.add(loader); } + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + try { + System.out.println("TRYING 2 LOAD " + name + " IN " + getName()); + return super.loadClass(name, resolve); + } catch (ClassNotFoundException e) { + System.out.println("COULD NOT LOAD 2, TRYING CHILDREN"); + for (MinestomExtensionClassLoader child : children) { + try { + return child.loadClass(name, resolve); + } catch (ClassNotFoundException ignored) { + System.out.println("NOT FOUND IN " + child.getName() + " EITHER"); + } + } + throw e; + } + } + public InputStream getResourceAsStreamWithChildren(@NotNull String name) { InputStream in = getResourceAsStream(name); if (in != null) return in; diff --git a/src/main/java/net/minestom/server/extensions/isolation/MinestomExtensionClassLoader.java b/src/main/java/net/minestom/server/extensions/isolation/MinestomExtensionClassLoader.java new file mode 100644 index 000000000..8918882e1 --- /dev/null +++ b/src/main/java/net/minestom/server/extensions/isolation/MinestomExtensionClassLoader.java @@ -0,0 +1,47 @@ +package net.minestom.server.extensions.isolation; + +import net.minestom.server.MinecraftServer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URL; + +public class MinestomExtensionClassLoader extends HierarchyClassLoader { + private final Logger logger = LoggerFactory.getLogger(MinestomExtensionClassLoader.class); + + public MinestomExtensionClassLoader(String extensionName, URL[] urls) { + super("Ext_" + extensionName, urls, MinecraftServer.class.getClassLoader()); + } + + /** + * Returns the name of the extension linked to this classloader + * @return the name of the extension linked to this classloader + */ + public String getExtensionName() { + // simply calls ClassLoader#getName as the extension name is used to name this classloader + // this method is simply for ease-of-use + return getName(); + } + + /** + * Tries to know which extension created this object, based on the classloader of the object. This can only check that the class of the object has been loaded + * by an extension. + * + * While not perfect, this should detect any callback created via extension code. + * It is possible this current version of the implementation might struggle with callbacks created through external + * libraries, but as libraries are loaded separately for each extension, this *should not*(tm) be a problem. + * + * @param obj the object to get the extension of + * @return null if no extension has been found, otherwise the extension name + */ + @Nullable + public static String findExtensionObjectOwner(@NotNull Object obj) { + ClassLoader cl = obj.getClass().getClassLoader(); + if (cl instanceof MinestomExtensionClassLoader extensionClassLoader) { + return extensionClassLoader.getExtensionName(); + } + return null; + } +} diff --git a/src/main/java/net/minestom/server/extras/selfmodification/MinestomExtensionClassLoader.java b/src/main/java/net/minestom/server/extras/selfmodification/MinestomExtensionClassLoader.java deleted file mode 100644 index c44d5f05e..000000000 --- a/src/main/java/net/minestom/server/extras/selfmodification/MinestomExtensionClassLoader.java +++ /dev/null @@ -1,146 +0,0 @@ -package net.minestom.server.extras.selfmodification; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -public class MinestomExtensionClassLoader extends HierarchyClassLoader { - /** - * Root ClassLoader, everything goes through it before any attempt at loading is done inside this classloader - */ - private final ClassLoader root; - - /** - * Main of the main class of the extension linked to this classloader - */ - private final String mainClassName; - - private final Logger logger = LoggerFactory.getLogger(MinestomExtensionClassLoader.class); - - public MinestomExtensionClassLoader(String extensionName, String mainClassName, URL[] urls, ClassLoader root) { - super(extensionName, urls, root); - this.root = root; - this.mainClassName = mainClassName; - } - - /** - * Returns the name of the extension linked to this classloader - * @return the name of the extension linked to this classloader - */ - public String getExtensionName() { - // simply calls ClassLoader#getName as the extension name is used to name this classloader - // this method is simply for ease-of-use - return getName(); - } - - /** - * Returns the main class name linked to the extension responsible for this classloader. - * Used by the root classloader to let extensions load themselves in a dev environment. - * @return the main class name linked to the extension responsible for this classloader - */ - public String getMainClassName() { - return mainClassName; - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - try { - System.out.println("TRYING TO LOAD " + name + " IN " + getName()); - return super.loadClass(name); - } catch (ClassNotFoundException e) { - System.out.println("COULD NOT LOAD, TRYING CHILDREN"); - for (MinestomExtensionClassLoader child : children) { - try { - return child.loadClass(name); - } catch (ClassNotFoundException ignored) { - System.out.println("NOT FOUND IN " + child.getName() + " EITHER"); - } - } - throw e; - } - } - - @Override - protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - try { - System.out.println("TRYING 2 LOAD " + name + " IN " + getName()); - return super.loadClass(name, resolve); - } catch (ClassNotFoundException e) { - System.out.println("COULD NOT LOAD 2, TRYING CHILDREN"); - for (MinestomExtensionClassLoader child : children) { - try { - return child.loadClass(name, resolve); - } catch (ClassNotFoundException ignored) { - System.out.println("NOT FOUND IN " + child.getName() + " EITHER"); - } - } - throw e; - } - } - - /** - * Assumes the name is not null, nor it does represent a protected class - * @param name - * @return - * @throws ClassNotFoundException if the class is not found inside this classloader - */ - public Class loadClassAsChild(String name, boolean resolve) throws ClassNotFoundException { - throw new RuntimeException("Cannot load " + name + " using old mechanism"); -// logger.info("Loading class " + name + " as child of " + getName()); -// Class loadedClass = findLoadedClass(name); -// if(loadedClass != null) { -// logger.info("Found loaded class"); -// return loadedClass; -// } -// -// try { -// // not in children, attempt load in this classloader -// String path = name.replace(".", "/") + ".class"; -// InputStream in = getResourceAsStream(path); -// if (in == null) { -// throw new ClassNotFoundException("Could not load class " + name); -// } -// logger.info("Found in resources"); -// try (in) { -// byte[] bytes = in.readAllBytes(); -// Class clazz = defineClass(name, bytes, 0, bytes.length); -// if (resolve) { -// resolveClass(clazz); -// } -// return clazz; -// } catch (IOException e) { -// throw new ClassNotFoundException("Could not load class " + name, e); -// } -// } catch (ClassNotFoundException e) { -// for(MinestomExtensionClassLoader child : children) { -// try { -// return child.loadClassAsChild(name, resolve); -// } catch (ClassNotFoundException e1) { -// // move on to next child -// } -// } -// throw e; -// } - } - - /** - * Is the given class name the name of the entry point of one the extensions from this classloader chain? - * @param name the class name to check - * @return whether the given class name the name of the entry point of one the extensions from this classloader chain - * @see MinestomRootClassLoader#loadBytes(String, boolean) for more information - */ - protected boolean isMainExtensionClass(String name) { - - if (mainClassName.equals(name)) - return true; - - for (MinestomExtensionClassLoader child : children) { - if (child.isMainExtensionClass(name)) return true; - } - - return false; - } -} diff --git a/src/main/java/net/minestom/server/extras/selfmodification/MinestomRootClassLoader.java b/src/main/java/net/minestom/server/extras/selfmodification/MinestomRootClassLoader.java deleted file mode 100644 index bbd67b4d4..000000000 --- a/src/main/java/net/minestom/server/extras/selfmodification/MinestomRootClassLoader.java +++ /dev/null @@ -1,262 +0,0 @@ -package net.minestom.server.extras.selfmodification; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.extensions.ExtensionManager; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -/** - * Class Loader that can modify class bytecode when they are loaded - */ -public class MinestomRootClassLoader extends HierarchyClassLoader { - - public final static Logger LOGGER = LoggerFactory.getLogger(MinestomRootClassLoader.class); - - private static volatile MinestomRootClassLoader INSTANCE; - - /** - * Classes that cannot be loaded/modified by this classloader. - * Will go through parent class loader - */ - public final Set protectedClasses = new HashSet<>() { - { - add("net.minestom.server.extras.selfmodification.CodeModifier"); - add("net.minestom.server.extras.selfmodification.MinestomOverwriteClassLoader"); - } - }; - public final Set protectedPackages = new HashSet<>() { - { - add("com.google.j2objc"); - add("com.google.common"); // guava - add("com.google.errorprone"); - add("com.google.gson"); - add("com.mojang"); - add("org.objectweb.asm"); - add("org.slf4j"); - add("org.apache.logging"); - add("org.spongepowered.asm"); // Mixin - add("org.spongepowered.tools"); // Mixin - add("net.minestom.server.extras.selfmodification"); - add("org.jboss.shrinkwrap.resolver"); - add("kotlin"); - } - }; - - /** - * Used to let ASM find out common super types, without actually commiting to loading them - * Otherwise ASM would accidentally load classes we might want to modify - */ - private final URLClassLoader asmClassLoader; - - // TODO: replace by tree to optimize lookup times. We can use the fact that package names are split with '.' to allow for fast lookup - // TODO: eg. Node("java", Node("lang"), Node("io")). Loading "java.nio.Channel" would apply modifiers from "java", but not "java.io" or "java.lang". - // TODO: that's an example, please don't modify standard library classes. And this classloader should not let you do it because it first asks the platform classloader - - /** - * Whether Minestom detected that it is running in a dev environment. - * Determined by the existence of the system property {@link ExtensionManager#INDEV_CLASSES_FOLDER} - */ - private boolean inDevEnvironment = false; - - /** - * List of already loaded code modifier class names. This prevents loading the same class twice. - */ - private final Set alreadyLoadedCodeModifiers = new HashSet<>(); - - private MinestomRootClassLoader(ClassLoader parent) { - super("Minestom Root ClassLoader", extractURLsFromClasspath(), parent); - asmClassLoader = newChild(new URL[0]); - inDevEnvironment = System.getProperty(ExtensionManager.INDEV_CLASSES_FOLDER) != null; - } - - public static MinestomRootClassLoader getInstance() { - if (INSTANCE == null) { - synchronized (MinestomRootClassLoader.class) { - if (INSTANCE == null) { - INSTANCE = new MinestomRootClassLoader(MinestomRootClassLoader.class.getClassLoader()); - } - } - } - return INSTANCE; - } - - private static URL[] extractURLsFromClasspath() { - String classpath = System.getProperty("java.class.path"); - String[] parts = classpath.split(";"); - URL[] urls = new URL[parts.length]; - for (int i = 0; i < urls.length; i++) { - try { - String part = parts[i]; - String protocol; - if (part.contains("!")) { - protocol = "jar://"; - } else { - protocol = "file://"; - } - urls[i] = new URL(protocol + part); - } catch (MalformedURLException e) { - throw new Error(e); - } - } - return urls; - } - - @Override - public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - Class loadedClass = findLoadedClass(name); - if (loadedClass != null) - return loadedClass; - - try { - // we do not load system classes by ourselves - Class systemClass = ClassLoader.getPlatformClassLoader().loadClass(name); - LOGGER.info("System class: {}", systemClass); - return systemClass; - } catch (ClassNotFoundException e) { - try { - if (isProtected(name)) { - LOGGER.info("Protected: {}", name); - return super.loadClass(name, resolve); - } - - LOGGER.info("Define: {}", name); - return define(name, resolve); - } catch (Exception ex) { - LOGGER.info("Fail to load class, resorting to parent loader: " + name, ex); - // fail to load class, let parent load - // this forbids code modification, but at least it will load - return super.loadClass(name, resolve); - } - } - } - - private boolean isProtected(String name) { - if (!protectedClasses.contains(name)) { - for (String start : protectedPackages) { - if (name.startsWith(start)) - return true; - } - return false; - } - return true; - } - - private Class define(String name, boolean resolve) throws IOException, ClassNotFoundException { - try { - byte[] bytes = loadBytes(name, true); - Class defined = defineClass(name, bytes, 0, bytes.length); - LOGGER.trace("Loaded with code modifiers: {}", name); - if (resolve) { - resolveClass(defined); - } - return defined; - } catch (ClassNotFoundException e) { - // could not load inside this classloader, attempt with children - Class defined = null; - for (MinestomExtensionClassLoader subloader : children) { - try { - defined = subloader.loadClassAsChild(name, resolve); - LOGGER.trace("Loaded from child {}: {}", subloader, name); - return defined; - } catch (ClassNotFoundException e1) { - // not found inside this child, move on to next - } - } - throw e; - } - } - - /** - * Loads and possibly transforms class bytecode corresponding to the given binary name. - * - * @param name - * @param transform - * @return - * @throws IOException - * @throws ClassNotFoundException - */ - public byte[] loadBytes(String name, boolean transform) throws IOException, ClassNotFoundException { - if (name == null) - throw new ClassNotFoundException(); - String path = name.replace(".", "/") + ".class"; - - if(inDevEnvironment) { - // check if the class to load is the entry point of the extension - boolean isMainExtensionClass = false; - for(MinestomExtensionClassLoader c : children) { - if(c.isMainExtensionClass(name)) { - isMainExtensionClass = true; - break; - } - } - if(isMainExtensionClass) { // entry point of the extension, force load through extension classloader - throw new ClassNotFoundException("The class "+name+" is the entry point of an extension. " + - "Because we are in a dev environment, we force its load through its extension classloader, " + - "even though the root classloader has access."); - } - } - InputStream input = getResourceAsStream(path); - if (input == null) { - throw new ClassNotFoundException("Could not find resource " + path); - } - return input.readAllBytes(); - } - - public byte[] loadBytesWithChildren(@NotNull String name, boolean transform) throws IOException, ClassNotFoundException { - String path = name.replace(".", "/") + ".class"; - InputStream input = getResourceAsStreamWithChildren(path); - if (input == null) { - throw new ClassNotFoundException("Could not find resource " + path); - } - return input.readAllBytes(); - } - - // overriden to increase access (from protected to public) - @Override - public Class findClass(String name) throws ClassNotFoundException { - return super.findClass(name); - } - - @NotNull - public URLClassLoader newChild(@NotNull URL[] urls) { - return URLClassLoader.newInstance(urls, this); - } - - @Override - public void addURL(URL url) { - super.addURL(url); - } - - /** - * Tries to know which extension created this object, based on the classloader of the object. This can only check that the class of the object has been loaded - * by an extension. - * - * While not perfect, this should detect any callback created via extension code. - * It is possible this current version of the implementation might struggle with callbacks created through external - * libraries, but as libraries are loaded separately for each extension, this *should not*(tm) be a problem. - * - * @param obj the object to get the extension of - * @return null if no extension has been found, otherwise the extension name - */ - @Nullable - public static String findExtensionObjectOwner(@NotNull Object obj) { - ClassLoader cl = obj.getClass().getClassLoader(); - if (cl instanceof MinestomExtensionClassLoader) { - return ((MinestomExtensionClassLoader) cl).getExtensionName(); - } - return null; - } -} diff --git a/src/test/java/demo/Start.java b/src/test/java/demo/Start.java deleted file mode 100644 index cbe8595c8..000000000 --- a/src/test/java/demo/Start.java +++ /dev/null @@ -1,11 +0,0 @@ -package demo; - -import net.minestom.server.Bootstrap; - -public class Start { - - public static void main(String[] args) { - Bootstrap.bootstrap("demo.Main", new String[0]); - } - -} diff --git a/src/test/java/improveextensions/DisableEarlyLoad.java b/src/test/java/improveextensions/DisableEarlyLoad.java deleted file mode 100644 index 53bf3f4e6..000000000 --- a/src/test/java/improveextensions/DisableEarlyLoad.java +++ /dev/null @@ -1,34 +0,0 @@ -package improveextensions; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.extensions.Extension; -import net.minestom.server.instance.InstanceContainer; -import net.minestom.server.world.DimensionType; -import org.junit.jupiter.api.Assertions; -import org.opentest4j.AssertionFailedError; - -import java.util.UUID; - -/** - * Extensions should be able to use Mixins for classes loaded very early by Minestom (InstanceContainer for instance) - */ -public class DisableEarlyLoad extends Extension { - - @Override - public void initialize() { - // force load of InstanceContainer class - InstanceContainer c = new InstanceContainer(UUID.randomUUID(), DimensionType.OVERWORLD); - System.out.println(c.toString()); - try { - Assertions.assertFalse(MixinIntoMinestomCore.success, "InstanceContainer must NOT have been mixed in with improveextensions.InstanceContainerMixin, because early loading has been disabled"); - } catch (AssertionFailedError e) { - e.printStackTrace(); - } - MinecraftServer.stopCleanly(); - } - - @Override - public void terminate() { - getLogger().info("Terminate extension"); - } -} diff --git a/src/test/java/improveextensions/MixinIntoMinestomCore.java b/src/test/java/improveextensions/MixinIntoMinestomCore.java deleted file mode 100644 index 88a3723f8..000000000 --- a/src/test/java/improveextensions/MixinIntoMinestomCore.java +++ /dev/null @@ -1,37 +0,0 @@ -package improveextensions; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.extensions.Extension; -import net.minestom.server.instance.InstanceContainer; -import net.minestom.server.world.DimensionType; -import org.junit.jupiter.api.Assertions; -import org.opentest4j.AssertionFailedError; - -import java.util.UUID; - -/** - * Extensions should be able to use Mixins for classes loaded very early by Minestom (InstanceContainer for instance) - */ -public class MixinIntoMinestomCore extends Extension { - - public static boolean success = false; - - @Override - public void initialize() { - // force load of InstanceContainer class - InstanceContainer c = new InstanceContainer(UUID.randomUUID(), DimensionType.OVERWORLD); - System.out.println(c.toString()); -// try { -// Assertions.assertTrue(success, "InstanceContainer must have been mixed in with improveextensions.InstanceContainerMixin"); -// Assertions.assertEquals(1, MinecraftServer.getExtensionManager().getExtensions().stream().map(extension -> extension.getOrigin().getMinestomExtensionClassLoader()).toArray().length, "Only one extension classloader (this extension's) must be active."); -// } catch (AssertionFailedError e) { -// e.printStackTrace(); -// } - MinecraftServer.stopCleanly(); - } - - @Override - public void terminate() { - getLogger().info("Terminate extension"); - } -} diff --git a/src/test/java/improveextensions/MixinIntoMinestomCoreLauncher.java b/src/test/java/improveextensions/MixinIntoMinestomCoreLauncher.java deleted file mode 100644 index 8079a1730..000000000 --- a/src/test/java/improveextensions/MixinIntoMinestomCoreLauncher.java +++ /dev/null @@ -1,21 +0,0 @@ -package improveextensions; - -import net.minestom.server.Bootstrap; - -// To launch with VM arguments: - -// To test early Mixin injections: -// -Dminestom.extension.indevfolder.classes=build/classes/java/test/ -Dminestom.extension.indevfolder.resources=build/resources/test/improveextensions -// To test disabling early Mixin injections: -// -Dminestom.extension.disable_early_load=true -Dminestom.extension.indevfolder.classes=build/classes/java/test/ -Dminestom.extension.indevfolder.resources=build/resources/test/improveextensions/disableearlyload - -// To test extension termination when the server quits: -// -Dminestom.extension.indevfolder.classes=build/classes/java/test/ -Dminestom.extension.indevfolder.resources=build/resources/test/improveextensions/unloadonstop - -// To test report of failure when a mixin configuration cannot be loaded, or code modifiers are missing -// -Dminestom.extension.indevfolder.classes=build/classes/java/test/ -Dminestom.extension.indevfolder.resources=build/resources/test/improveextensions/missingmodifiers -public class MixinIntoMinestomCoreLauncher { - public static void main(String[] args) { - Bootstrap.bootstrap("demo.MainDemo", args); - } -} diff --git a/src/test/java/improveextensions/MixinIntoMinestomCoreWithJava9ModuleOnClasspath.java b/src/test/java/improveextensions/MixinIntoMinestomCoreWithJava9ModuleOnClasspath.java deleted file mode 100644 index 7d6bfdfd5..000000000 --- a/src/test/java/improveextensions/MixinIntoMinestomCoreWithJava9ModuleOnClasspath.java +++ /dev/null @@ -1,43 +0,0 @@ -package improveextensions; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.extensions.Extension; -import net.minestom.server.instance.InstanceContainer; -import net.minestom.server.world.DimensionType; -import org.junit.jupiter.api.Assertions; -import org.opentest4j.AssertionFailedError; - -import java.util.List; -import java.util.UUID; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Extensions should be able to use Mixins for classes loaded very early by Minestom (InstanceContainer for instance) - */ -public class MixinIntoMinestomCoreWithJava9ModuleOnClasspath extends Extension { - - @Override - public void initialize() { - // use Mockito only to ensure J9 modules on the classpath are supported - List mockedList = mock(List.class); - when(mockedList.get(0)).thenReturn("Test"); - // force load of InstanceContainer class - InstanceContainer c = new InstanceContainer(UUID.randomUUID(), DimensionType.OVERWORLD); - System.out.println(c.toString()); - try { - Assertions.assertTrue(MixinIntoMinestomCore.success, "InstanceContainer must have been mixed in with improveextensions.InstanceContainerMixin"); - Assertions.assertEquals(1, MinecraftServer.getExtensionManager().getExtensions().stream().map(extension -> extension.getOrigin().getMinestomExtensionClassLoader()).toArray().length, "Only one extension classloader (this extension's) must be active."); - Assertions.assertEquals("Test", mockedList.get(0)); - } catch (AssertionFailedError e) { - e.printStackTrace(); - } - MinecraftServer.stopCleanly(); - } - - @Override - public void terminate() { - getLogger().info("Terminate extension"); - } -} diff --git a/src/test/java/improveextensions/missingmodifiers/MissingCodeModifiersExtension.java b/src/test/java/improveextensions/missingmodifiers/MissingCodeModifiersExtension.java deleted file mode 100644 index c281953e6..000000000 --- a/src/test/java/improveextensions/missingmodifiers/MissingCodeModifiersExtension.java +++ /dev/null @@ -1,31 +0,0 @@ -package improveextensions.missingmodifiers; - -import net.minestom.server.MinecraftServer; -import net.minestom.server.extensions.Extension; -import org.junit.jupiter.api.Assertions; -import org.opentest4j.AssertionFailedError; - -public class MissingCodeModifiersExtension extends Extension { - - @Override - public void initialize() { - // force load of InstanceContainer class - try { -// Assertions.assertFalse(areCodeModifiersAllLoadedCorrectly(), "Mixin configuration could not be loaded and code modifiers are unavailable, the failure should be reported"); -// Assertions.assertTrue(getOrigin().hasFailedToLoadMixin(), "Mixin configuration does not exist and should not be loaded"); -// Assertions.assertEquals(1, getOrigin().getMissingCodeModifiers().size(), "Code modifier does not exist, it should be reported as missing"); -// Assertions.assertEquals("InvalidCodeModifierClass", getOrigin().getMissingCodeModifiers().get(0)); - System.out.println("All tests passed."); - } catch (AssertionFailedError e) { - e.printStackTrace(); - } - MinecraftServer.stopCleanly(); - } - - @Override - public void terminate() { - getLogger().info("Terminate extension"); - } - - -} diff --git a/src/test/java/improveextensions/mixins/InstanceContainerMixin.java b/src/test/java/improveextensions/mixins/InstanceContainerMixin.java deleted file mode 100644 index 3c86e1ce5..000000000 --- a/src/test/java/improveextensions/mixins/InstanceContainerMixin.java +++ /dev/null @@ -1,12 +0,0 @@ -package improveextensions.mixins; - -//@Mixin(InstanceContainer.class) -public class InstanceContainerMixin { - -// @Inject(method = "", at = @At("RETURN"), require = 1) -// private void constructorHead(CallbackInfo ci) { -// System.out.println("Mixin into InstanceContainerMixin"); -// MixinIntoMinestomCore.success = true; -// } - -} diff --git a/src/test/java/improveextensions/unloadcallbacks/UnloadCallbacksExtension.java b/src/test/java/improveextensions/unloadcallbacks/UnloadCallbacksExtension.java index d823d77f5..9ee5e211e 100644 --- a/src/test/java/improveextensions/unloadcallbacks/UnloadCallbacksExtension.java +++ b/src/test/java/improveextensions/unloadcallbacks/UnloadCallbacksExtension.java @@ -8,7 +8,7 @@ import net.minestom.server.event.GlobalEventHandler; import net.minestom.server.event.entity.EntityTickEvent; import net.minestom.server.event.instance.InstanceTickEvent; import net.minestom.server.extensions.Extension; -import net.minestom.server.extras.selfmodification.MinestomRootClassLoader; +import net.minestom.server.extensions.isolation.MinestomExtensionClassLoader; import net.minestom.server.instance.Instance; import net.minestom.server.utils.time.TimeUnit; import org.junit.jupiter.api.Assertions; @@ -65,8 +65,8 @@ public class UnloadCallbacksExtension extends Extension { }).repeat(100L, TimeUnit.MILLISECOND).schedule(); try { - Assertions.assertNotNull(MinestomRootClassLoader.findExtensionObjectOwner(callback)); - Assertions.assertEquals("UnloadCallbacksExtension", MinestomRootClassLoader.findExtensionObjectOwner(callback)); + Assertions.assertNotNull(MinestomExtensionClassLoader.findExtensionObjectOwner(callback)); + Assertions.assertEquals("UnloadCallbacksExtension", MinestomExtensionClassLoader.findExtensionObjectOwner(callback)); } catch (AssertionFailedError e) { e.printStackTrace(); System.exit(-1); diff --git a/src/test/java/testextension/TestDemoLauncher.java b/src/test/java/testextension/TestDemoLauncher.java deleted file mode 100644 index 775d2daa4..000000000 --- a/src/test/java/testextension/TestDemoLauncher.java +++ /dev/null @@ -1,11 +0,0 @@ -package testextension; - -import net.minestom.server.Bootstrap; - -public class TestDemoLauncher { - - public static void main(String[] args) { - Bootstrap.bootstrap("demo.Main", args); - } - -} diff --git a/src/test/java/testextension/TestExtensionLauncherArgs.java b/src/test/java/testextension/TestExtensionLauncherArgs.java deleted file mode 100644 index eb36cab23..000000000 --- a/src/test/java/testextension/TestExtensionLauncherArgs.java +++ /dev/null @@ -1,17 +0,0 @@ -package testextension; - -import net.minestom.server.Bootstrap; - -// To launch with VM arguments: -// -Dminestom.extension.indevfolder.classes=build/classes/java/test/ -Dminestom.extension.indevfolder.resources=build/resources/test/ -public class TestExtensionLauncherArgs { - - public static void main(String[] args) { - String[] argsWithMixins = new String[args.length+2]; - System.arraycopy(args, 0, argsWithMixins, 0, args.length); - argsWithMixins[argsWithMixins.length-2] = "--mixin"; - argsWithMixins[argsWithMixins.length-1] = "mixins.testextension.json"; - Bootstrap.bootstrap("demo.MainDemo", argsWithMixins); - } - -} diff --git a/src/test/java/testextension/TestExtensionLauncherNoSetup.java b/src/test/java/testextension/TestExtensionLauncherNoSetup.java deleted file mode 100644 index 16e2d5e66..000000000 --- a/src/test/java/testextension/TestExtensionLauncherNoSetup.java +++ /dev/null @@ -1,13 +0,0 @@ -package testextension; - -import net.minestom.server.Bootstrap; - -// To launch with VM arguments: -// -Dminestom.extension.indevfolder.classes=build/classes/java/test/ -Dminestom.extension.indevfolder.resources=build/resources/test/ -public class TestExtensionLauncherNoSetup { - - public static void main(String[] args) { - Bootstrap.bootstrap("demo.MainDemo", args); - } - -} diff --git a/src/test/java/testextension/TestModifier.java b/src/test/java/testextension/TestModifier.java deleted file mode 100644 index a5ab44c6e..000000000 --- a/src/test/java/testextension/TestModifier.java +++ /dev/null @@ -1,37 +0,0 @@ -package testextension; - -//import net.minestom.server.extras.selfmodification.CodeModifier; -//import org.objectweb.asm.Opcodes; -//import org.objectweb.asm.tree.*; - -import java.util.List; - -public class TestModifier {// extends CodeModifier implements Opcodes { -// @Override -// public boolean transform(ClassNode source) { -// if(source.name.equals("net/minestom/server/instance/InstanceContainer")) { -// System.out.println("Modifying code of "+source.name); -// MethodNode constructor = findConstructor(source.methods); -// constructor.instructions.insert(constructor.instructions.getFirst(), buildInjectionCode()); -// return true; -// } -// return false; -// } -// -// private InsnList buildInjectionCode() { -// InsnList list = new InsnList(); -// list.add(new FieldInsnNode(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;")); -// list.add(new LdcInsnNode("Hello from modified code!!")); -// list.add(new MethodInsnNode(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false)); -// return list; -// } -// -// private MethodNode findConstructor(List methods) { -// return methods.stream().filter(m -> m.name.equals("")).findFirst().orElseThrow(); -// } -// -// @Override -// public String getNamespace() { -// return "net.minestom.server"; -// } -} diff --git a/src/test/java/testextension/mixins/DynamicChunkMixin.java b/src/test/java/testextension/mixins/DynamicChunkMixin.java deleted file mode 100644 index c9bfcdea7..000000000 --- a/src/test/java/testextension/mixins/DynamicChunkMixin.java +++ /dev/null @@ -1,18 +0,0 @@ -package testextension.mixins; - -import net.minestom.server.instance.DynamicChunk; -import net.minestom.server.instance.block.Block; -//import org.spongepowered.asm.mixin.Mixin; -//import org.spongepowered.asm.mixin.injection.At; -//import org.spongepowered.asm.mixin.injection.ModifyVariable; - -//@Mixin(DynamicChunk.class) -public class DynamicChunkMixin { - -// @ModifyVariable(method = "setBlock", at = @At("HEAD"), index = 4, require = 1, argsOnly = true, remap = false) -// public int oopsAllTnt(short blockStateId) { -// if(blockStateId != 0) -// return Block.TNT.id(); -// return 0; -// } -} diff --git a/src/test/java/testextension/mixins/InstanceContainerMixin.java b/src/test/java/testextension/mixins/InstanceContainerMixin.java deleted file mode 100644 index d537121ef..000000000 --- a/src/test/java/testextension/mixins/InstanceContainerMixin.java +++ /dev/null @@ -1,17 +0,0 @@ -package testextension.mixins; - -import net.minestom.server.instance.InstanceContainer; -//import org.spongepowered.asm.mixin.Mixin; -//import org.spongepowered.asm.mixin.injection.At; -//import org.spongepowered.asm.mixin.injection.Inject; -//import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -//@Mixin(InstanceContainer.class) -public class InstanceContainerMixin { - -// @Inject(method = "", at = @At("RETURN")) -// private void onRunHead(CallbackInfo ci) { -// System.out.println("Hello from Mixin!!!"); -// } - -} diff --git a/src/test/resources/extension.json b/src/test/resources/extension.json index 46a91d0b9..8e87d0de3 100644 --- a/src/test/resources/extension.json +++ b/src/test/resources/extension.json @@ -1,8 +1,4 @@ { "entrypoint": "testextension.TestExtension", - "name": "Test_extension", - "codeModifiers": [ - "testextension.TestModifier" - ], - "mixinConfig": "mixins.testextension.json" + "name": "Test_extension" } \ No newline at end of file diff --git a/src/test/resources/improveextensions/disableearlyload/extension.json b/src/test/resources/improveextensions/disableearlyload/extension.json deleted file mode 100644 index c26927c24..000000000 --- a/src/test/resources/improveextensions/disableearlyload/extension.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "entrypoint": "improveextensions.DisableEarlyLoad", - "name": "DisableEarlyLoad", - "codeModifiers": [], - "mixinConfig": "mixins.minestomcore.json" -} \ No newline at end of file diff --git a/src/test/resources/improveextensions/disableearlyload/mixins.minestomcore.json b/src/test/resources/improveextensions/disableearlyload/mixins.minestomcore.json deleted file mode 100644 index 7c8c03fe2..000000000 --- a/src/test/resources/improveextensions/disableearlyload/mixins.minestomcore.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "improveextensions.mixins", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_11", - "mixins": [ - "InstanceContainerMixin" - ] -} \ No newline at end of file diff --git a/src/test/resources/improveextensions/extension.json b/src/test/resources/improveextensions/extension.json deleted file mode 100644 index abbe3eb02..000000000 --- a/src/test/resources/improveextensions/extension.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "entrypoint": "improveextensions.MixinIntoMinestomCore", - "name": "MixinIntoMinestomCore", - "codeModifiers": [], - "mixinConfig": "mixins.minestomcore.json" -} \ No newline at end of file diff --git a/src/test/resources/improveextensions/j9modules/extension.json b/src/test/resources/improveextensions/j9modules/extension.json deleted file mode 100644 index ba409d029..000000000 --- a/src/test/resources/improveextensions/j9modules/extension.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "entrypoint": "improveextensions.MixinIntoMinestomCoreWithJava9ModuleOnClasspath", - "name": "MixinIntoMinestomCoreWithJava9ModuleOnClasspath", - "codeModifiers": [], - "mixinConfig": "mixins.minestomcore.json", - "externalDependencies": { - "repositories": [ - {"name": "JCentral", "url": "https://jcenter.bintray.com/"} - ], - "artifacts": [ - "org.mockito:mockito-core:2.28.2" - ] - } -} \ No newline at end of file diff --git a/src/test/resources/improveextensions/j9modules/mixins.minestomcore.json b/src/test/resources/improveextensions/j9modules/mixins.minestomcore.json deleted file mode 100644 index 7c8c03fe2..000000000 --- a/src/test/resources/improveextensions/j9modules/mixins.minestomcore.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "improveextensions.mixins", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_11", - "mixins": [ - "InstanceContainerMixin" - ] -} \ No newline at end of file diff --git a/src/test/resources/improveextensions/missingmodifiers/extension.json b/src/test/resources/improveextensions/missingmodifiers/extension.json deleted file mode 100644 index d5db684db..000000000 --- a/src/test/resources/improveextensions/missingmodifiers/extension.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "entrypoint": "improveextensions.missingmodifiers.MissingCodeModifiersExtension", - "name": "MissingCodeModifiersExtension", - "codeModifiers": [ - "InvalidCodeModifierClass" - ], - "mixinConfig": "mixins.$invalid$.json" -} \ No newline at end of file diff --git a/src/test/resources/improveextensions/mixins.minestomcore.json b/src/test/resources/improveextensions/mixins.minestomcore.json deleted file mode 100644 index 7c8c03fe2..000000000 --- a/src/test/resources/improveextensions/mixins.minestomcore.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "improveextensions.mixins", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_11", - "mixins": [ - "InstanceContainerMixin" - ] -} \ No newline at end of file diff --git a/src/test/resources/mixins.testextension.json b/src/test/resources/mixins.testextension.json deleted file mode 100644 index 6fd90870c..000000000 --- a/src/test/resources/mixins.testextension.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "testextension.mixins", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_11", - "mixins": [ - "InstanceContainerMixin", - "DynamicChunkMixin" - ] -} \ No newline at end of file