Remove Bootstrap, MinestomRootClassLoader. Cleanup

This commit is contained in:
Matt Worzala 2021-11-13 14:14:03 -05:00 committed by TheMode
parent b558125bee
commit 0c6e4c0129
30 changed files with 75 additions and 826 deletions

View File

@ -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();
}
}
}

View File

@ -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<DiscoveredExtension> 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));

View File

@ -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) {

View File

@ -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;

View File

@ -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 <code>null</code> 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;
}
}

View File

@ -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;
}
}

View File

@ -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<String> protectedClasses = new HashSet<>() {
{
add("net.minestom.server.extras.selfmodification.CodeModifier");
add("net.minestom.server.extras.selfmodification.MinestomOverwriteClassLoader");
}
};
public final Set<String> 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<String> 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 <code>null</code> 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;
}
}

View File

@ -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]);
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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);
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -1,12 +0,0 @@
package improveextensions.mixins;
//@Mixin(InstanceContainer.class)
public class InstanceContainerMixin {
// @Inject(method = "<init>", at = @At("RETURN"), require = 1)
// private void constructorHead(CallbackInfo ci) {
// System.out.println("Mixin into InstanceContainerMixin");
// MixinIntoMinestomCore.success = true;
// }
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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<MethodNode> methods) {
// return methods.stream().filter(m -> m.name.equals("<init>")).findFirst().orElseThrow();
// }
//
// @Override
// public String getNamespace() {
// return "net.minestom.server";
// }
}

View File

@ -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;
// }
}

View File

@ -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 = "<init>", at = @At("RETURN"))
// private void onRunHead(CallbackInfo ci) {
// System.out.println("Hello from Mixin!!!");
// }
}

View File

@ -1,8 +1,4 @@
{
"entrypoint": "testextension.TestExtension",
"name": "Test_extension",
"codeModifiers": [
"testextension.TestModifier"
],
"mixinConfig": "mixins.testextension.json"
"name": "Test_extension"
}

View File

@ -1,6 +0,0 @@
{
"entrypoint": "improveextensions.DisableEarlyLoad",
"name": "DisableEarlyLoad",
"codeModifiers": [],
"mixinConfig": "mixins.minestomcore.json"
}

View File

@ -1,10 +0,0 @@
{
"required": true,
"minVersion": "0.8",
"package": "improveextensions.mixins",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_11",
"mixins": [
"InstanceContainerMixin"
]
}

View File

@ -1,6 +0,0 @@
{
"entrypoint": "improveextensions.MixinIntoMinestomCore",
"name": "MixinIntoMinestomCore",
"codeModifiers": [],
"mixinConfig": "mixins.minestomcore.json"
}

View File

@ -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"
]
}
}

View File

@ -1,10 +0,0 @@
{
"required": true,
"minVersion": "0.8",
"package": "improveextensions.mixins",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_11",
"mixins": [
"InstanceContainerMixin"
]
}

View File

@ -1,8 +0,0 @@
{
"entrypoint": "improveextensions.missingmodifiers.MissingCodeModifiersExtension",
"name": "MissingCodeModifiersExtension",
"codeModifiers": [
"InvalidCodeModifierClass"
],
"mixinConfig": "mixins.$invalid$.json"
}

View File

@ -1,10 +0,0 @@
{
"required": true,
"minVersion": "0.8",
"package": "improveextensions.mixins",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_11",
"mixins": [
"InstanceContainerMixin"
]
}

View File

@ -1,11 +0,0 @@
{
"required": true,
"minVersion": "0.8",
"package": "testextension.mixins",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_11",
"mixins": [
"InstanceContainerMixin",
"DynamicChunkMixin"
]
}