diff --git a/loader/src/main/java/net/neoforged/fml/classloading/transformation/ClassProcessorSet.java b/loader/src/main/java/net/neoforged/fml/classloading/transformation/ClassProcessorSet.java index b31aa0240..6e1c15588 100644 --- a/loader/src/main/java/net/neoforged/fml/classloading/transformation/ClassProcessorSet.java +++ b/loader/src/main/java/net/neoforged/fml/classloading/transformation/ClassProcessorSet.java @@ -113,14 +113,14 @@ public List transformersFor(Type classDesc, boolean isEmpty, Pro return out; } - public void link(Function bytecodeProviderLookup) { + public void link(Function bytecodeProviderLookup, ClassLoader parentClassLoader) { if (linked) { throw new IllegalStateException("This set of class processors is already linked."); } linked = true; for (var processor : sortedProcessors) { - var context = new ClassProcessor.LinkContext(processors, bytecodeProviderLookup.apply(processor.name())); + var context = new ClassProcessor.LinkContext(processors, bytecodeProviderLookup.apply(processor.name()), parentClassLoader); processor.link(context); } } diff --git a/loader/src/main/java/net/neoforged/fml/classloading/transformation/TransformingClassLoader.java b/loader/src/main/java/net/neoforged/fml/classloading/transformation/TransformingClassLoader.java index 1d6eb8b88..7ed0a0487 100644 --- a/loader/src/main/java/net/neoforged/fml/classloading/transformation/TransformingClassLoader.java +++ b/loader/src/main/java/net/neoforged/fml/classloading/transformation/TransformingClassLoader.java @@ -38,7 +38,7 @@ public TransformingClassLoader(ClassProcessorSet classProcessorSet, ClassProcess super("TRANSFORMER", configuration, parentLayers, parentClassLoader); this.classTransformer = new ClassTransformer(classProcessorSet, auditTrail); // The state of this class has to be set up fully before the processors are linked - classProcessorSet.link(processorName -> className -> buildTransformedClassNodeFor(className, processorName)); + classProcessorSet.link(processorName -> className -> buildTransformedClassNodeFor(className, processorName), parentClassLoader); } @Override diff --git a/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLClassProvider.java b/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLClassProvider.java index 32754df15..d0082da25 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLClassProvider.java +++ b/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLClassProvider.java @@ -7,13 +7,21 @@ import java.net.URL; import net.neoforged.fml.loading.FMLLoader; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.spongepowered.asm.service.IClassProvider; /** * Class provider for use under ModLauncher */ class FMLClassProvider implements IClassProvider { - FMLClassProvider() {} + private static final Logger LOGGER = LogManager.getLogger(); + + private final ClassLoader pluginClassLoader; + + FMLClassProvider(ClassLoader pluginClassLoader) { + this.pluginClassLoader = pluginClassLoader; + } @Override @Deprecated @@ -23,12 +31,26 @@ public URL[] getClassPath() { @Override public Class findClass(String name) throws ClassNotFoundException { - return Class.forName(name, true, FMLLoader.getCurrent().getCurrentClassLoader()); + try { + return Class.forName(name, true, pluginClassLoader); + } catch (ClassNotFoundException e) { + warnOnDeprecatedTclPluginLoad(name); + return Class.forName(name, true, FMLLoader.getCurrent().getCurrentClassLoader()); + } } @Override public Class findClass(String name, boolean initialize) throws ClassNotFoundException { - return Class.forName(name, initialize, FMLLoader.getCurrent().getCurrentClassLoader()); + try { + return Class.forName(name, initialize, pluginClassLoader); + } catch (ClassNotFoundException e) { + warnOnDeprecatedTclPluginLoad(name); + return Class.forName(name, initialize, FMLLoader.getCurrent().getCurrentClassLoader()); + } + } + + private static void warnOnDeprecatedTclPluginLoad(String name) { + LOGGER.error("Mixin attempted to load class {} from the transforming classloader. This behavior is deprecated and may not continue to work; mixin config plugins should be provided from FMLModType=LIBRARY jars instead.", name); } @Override diff --git a/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLMixinClassProcessor.java b/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLMixinClassProcessor.java index 691c764fd..9840fa192 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLMixinClassProcessor.java +++ b/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLMixinClassProcessor.java @@ -34,6 +34,7 @@ public FMLMixinClassProcessor(FMLMixinService service) { @Override public void link(LinkContext context) { this.service.setBytecodeProvider(new FMLClassBytecodeProvider(context.bytecodeProvider(), this)); + this.service.setClassProvider(new FMLClassProvider(context.pluginClassLoader())); } @Override diff --git a/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLMixinService.java b/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLMixinService.java index 113582db5..83afe7ce4 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLMixinService.java +++ b/loader/src/main/java/net/neoforged/fml/loading/mixin/FMLMixinService.java @@ -101,6 +101,10 @@ public void setBytecodeProvider(@Nullable IClassBytecodeProvider bytecodeProvide this.bytecodeProvider = bytecodeProvider; } + public void setClassProvider(@Nullable IClassProvider classProvider) { + this.classProvider = classProvider; + } + @Override public void offer(IMixinInternal internal) { if (internal instanceof IMixinTransformerFactory mixinTransformerFactory) { @@ -136,7 +140,7 @@ public boolean isValid() { @Override public IClassProvider getClassProvider() { if (this.classProvider == null) { - this.classProvider = new FMLClassProvider(); + throw new IllegalStateException("Service initialisation incomplete, FMLMixinClassProcessor has not yet been linked"); } return this.classProvider; } @@ -144,7 +148,7 @@ public IClassProvider getClassProvider() { @Override public IClassBytecodeProvider getBytecodeProvider() { if (this.bytecodeProvider == null) { - throw new IllegalStateException("Service initialisation incomplete, launch plugin was not created"); + throw new IllegalStateException("Service initialisation incomplete, FMLMixinClassProcessor has not yet been linked"); } return this.bytecodeProvider; } diff --git a/loader/src/main/java/net/neoforged/neoforgespi/transformation/ClassProcessor.java b/loader/src/main/java/net/neoforged/neoforgespi/transformation/ClassProcessor.java index 63a4f23e8..3c05f3325 100644 --- a/loader/src/main/java/net/neoforged/neoforgespi/transformation/ClassProcessor.java +++ b/loader/src/main/java/net/neoforged/neoforgespi/transformation/ClassProcessor.java @@ -221,12 +221,14 @@ record AfterProcessingContext(Type type) { * The context provided to {@linkplain ClassProcessor class processors} * when they are linked with a bytecode source. * - * @param processors an immutable map of the processors that are being linked. The maps iteration order is the order in which the processors will be applied - * @param bytecodeProvider a provider to access class bytecode for other classes than the class that is being transformed + * @param processors an immutable map of the processors that are being linked. The maps iteration order is the order in which the processors will be applied + * @param bytecodeProvider a provider to access class bytecode for other classes than the class that is being transformed + * @param pluginClassLoader provides access to the classloader before the transforming classloader, for use in safely loading classes */ record LinkContext( @Unmodifiable SequencedMap processors, - BytecodeProvider bytecodeProvider) { + BytecodeProvider bytecodeProvider, + ClassLoader pluginClassLoader) { @ApiStatus.Internal public LinkContext {} }