FabricMC / fabric-loader

Fabric's mostly-version-independent mod loader.
Apache License 2.0
617 stars 262 forks source link

Bootstrapping fabric-loader #292

Open ramidzkh opened 4 years ago

ramidzkh commented 4 years ago

An API to wrap a set of URLs or a ClassLoader with fabric-loader so that Mixins and access wideners and whatever are all run.

API would look something like

    /**
     * Creates a ClassLoader which fabric-loader is able to transform (e.g. with Mixin)
     *
     * @param parent       The parent {@link ClassLoader} to use
     * @param urls         The {@link URL URLs} which fabric-loader is able to transform
     * @param runDirectory The directory where the mods, config and related folders are located
     */
    public static ClassLoader wrap(ClassLoader parent, URL[] urls, File runDirectory) {
        // Bootstrap loader
        // Get the classloader from the preferred system (Knot/LegacyLauncher, whatever is decided)
        // Return it
    }

This is not useful at all for Minecraft, but in other cases where Java applications are bootstrapped (e.g. amidst), currently very heavy reflection on internal code is used

burgerindividual commented 4 years ago

An alternative to this is to just make more classes and methods public instead of package protected or private. This allows us to do things in between stages of the bootstrap much easier.

Chocohead commented 4 years ago

I wouldn't have said that Loader is really in a state to be using it for non-Minecraft related things whilst still expecting it to work readily without changes. Given it won't even start if the Minecraft game provider doesn't find the game jar with no option for adding other providers is a prime example of this. There needs to be some more general consideration of what is likely to apply to most uses compared to what is generally designed around Minecraft's case (ie to split them apart more clearly to what is designed to be implemented vs an implementation detail of Loader itself) before tacking on extra extensions IMO.

sfPlayer1 commented 4 years ago

I don't quite understand how this is supposed to work, normally fabric loader or launchwrapper controls the program entry point. The proposed method implies it runs somewhere in between, but only returns a class loader? How is that supposed to work? Why does it take a parent class loader? Why does it return one?

Splitting MC specifics into a separate project is my next big TODO item for loader.

ramidzkh commented 4 years ago

An alternative to this is to just make more classes and methods public instead of package protected or private. This allows us to do things in between stages of the bootstrap much easier.

Most package private classes have good reason to be package private. Knot is really an implementation detail

Given it won't even start if the Minecraft game provider doesn't find the game jar with no option for adding other providers is a prime example of this.

Hmm, I guess also add an option for the preferred GameProvider?

I don't quite understand how this is supposed to work, normally fabric loader or launchwrapper controls the program entry point. The proposed method implies it runs somewhere in between, but only returns a class loader? How is that supposed to work? Why does it take a parent class loader? Why does it return one?

The parent ClassLoader is the loader which has the JRE and other untransformable dependencies. The urls argument is an array of URLs which loader should be able to transform. The returned ClassLoader is a loader which will is able to transform classes. For example:

File remappedMinecraftJar = // Create a file with the remapped Minecraft jar
ClassLoader loader = wrap(ClassLoader.getSystemClassLoader(), new URL[] { remappedMinecraftJar.toURI().toURL() }, new File("."));
Thread.currentThread().setContextClassLoader(loader);
Class.forName("net.minecraft.server.MinecraftServer", true, loader)
    .getMethod("main", String[].class)
    .invoke(null, args);