diff --git a/src/main/java/net/minestom/server/extras/selfmodification/MinestomRootClassLoader.java b/src/main/java/net/minestom/server/extras/selfmodification/MinestomRootClassLoader.java index a2427f810..5813ea20a 100644 --- a/src/main/java/net/minestom/server/extras/selfmodification/MinestomRootClassLoader.java +++ b/src/main/java/net/minestom/server/extras/selfmodification/MinestomRootClassLoader.java @@ -316,7 +316,7 @@ public class MinestomRootClassLoader extends HierarchyClassLoader { * 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 extension code. + * 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. * diff --git a/src/test/java/improveextensions/unloadcallbacks/UnloadCallbacksExtension.java b/src/test/java/improveextensions/unloadcallbacks/UnloadCallbacksExtension.java index 767994736..2c44089a8 100644 --- a/src/test/java/improveextensions/unloadcallbacks/UnloadCallbacksExtension.java +++ b/src/test/java/improveextensions/unloadcallbacks/UnloadCallbacksExtension.java @@ -3,7 +3,6 @@ package improveextensions.unloadcallbacks; import net.minestom.server.MinecraftServer; import net.minestom.server.event.EventCallback; import net.minestom.server.event.GlobalEventHandler; -import net.minestom.server.event.handler.EventHandler; import net.minestom.server.event.instance.InstanceTickEvent; import net.minestom.server.extensions.Extension; import net.minestom.server.extras.selfmodification.MinestomRootClassLoader; @@ -11,6 +10,8 @@ import net.minestom.server.utils.time.TimeUnit; import org.junit.jupiter.api.Assertions; import org.opentest4j.AssertionFailedError; +import java.util.concurrent.atomic.AtomicBoolean; + public class UnloadCallbacksExtension extends Extension { private boolean ticked1 = false; @@ -62,18 +63,29 @@ public class UnloadCallbacksExtension extends Extension { tickedScheduledNonTransient = false; tickedScheduledTransient = false; - // TODO: set to transient task to avoid losing the task on termination + AtomicBoolean executedDelayTaskAfterTerminate = new AtomicBoolean(false); + // because terminate is called just before unscheduling and removing event callbacks, + // the following task will never be executed, because it is not transient MinecraftServer.getSchedulerManager().buildTask(() -> { - // Make sure callback is disabled + executedDelayTaskAfterTerminate.set(true); + }).delay(100L, TimeUnit.MILLISECOND).schedule(); + + // this shutdown tasks will not be executed because it is not transient + MinecraftServer.getSchedulerManager().buildShutdownTask(() -> Assertions.fail("This shutdown task should be unloaded when the extension is")).schedule(); + + MinecraftServer.getSchedulerManager().buildTask(() -> { + // Make sure callbacks are disabled try { Assertions.assertFalse(ticked1, "ticked1 should be false because the callback has been unloaded"); Assertions.assertFalse(ticked2, "ticked2 should be false because the callback has been unloaded"); Assertions.assertFalse(tickedScheduledNonTransient, "tickedScheduledNonTransient should be false because the callback has been unloaded"); Assertions.assertTrue(tickedScheduledTransient, "tickedScheduledNonTransient should be true because the callback has NOT been unloaded"); + Assertions.assertFalse(executedDelayTaskAfterTerminate.get(), "executedDelayTaskAfterTerminate should be false because the callback has been unloaded before executing"); + System.out.println("All tests passed."); } catch (AssertionFailedError e) { e.printStackTrace(); } - MinecraftServer.stopCleanly(); + MinecraftServer.stopCleanly(); // TODO: fix deadlock which happens because stopCleanly waits on completion of scheduler tasks }).delay(1L, TimeUnit.SECOND).makeTransient().schedule(); } }