This release is a major overhaul of the core features in Fabric Loader, including everything that deals with finding and choosing mods. Users should benefit from greatly improved error messages and quite a few options to customize their install. Mods have several new tools to achieve their goals more easily.

Fabric Loader 0.12 is not yet available through the normal means, see below for how to get it.

Changelog

  • added support for the bundler based server distribution introduced by the MC snapshot 21w39a (Player)
  • added support for global access wideners (shartte)
  • added ObjectShare mechanism for mods to interact indirectly (Player)
  • changed package structure for clear api/implementation split, may break some mods that use internals beyond what is now provided by legacy support API (Player)
  • changed project structure to isolate MC specific code, runtime test dependencies and legacy API (modmuss50)
  • fixed mod dependency inspection API and made it more useful (Player)
  • updated Mixin (modmuss50, Player)
  • added Mixin backwards compatibility mechanism, Mixin behavior will depend on the minimum fabricloader version requested by the mod’s dependency definition (Player)
  • changed mod discovery for better reliability, speed and memory efficiency (Player)
  • added fabric.addMods system property and argument to configure additional mod sources: individual jar files, directories containing jars, directories representing an extracted mod or @-prefixed files listing the previous one line at a time (Player)
  • changed mod resolution to gracefully handle multiple instances of the same mod, produce better errors, give mod dependency issue guidance, handle nested jars properly and allow for more customization (Player)
  • changed mod load order to be random in-dev (see fabric.debug.disableModShuffle system property) and explicitly sorted by mod id in production (not a specification, may change without notice) (Player)
  • added system property fabric.debug.loadLate to work around mod load order bugs (Player)
  • added fabric.debug.throwDirectly system property to let errorneous entrypoints fail immediately, helps debugging them through isolation (Player)
  • changed exposing the game and its libraries to be as late as possible to prevent accidental too-early accesses (Player)
  • dropped most library dependencies to avoid conflicts with the game (modmuss50, Player)
  • added exception display to the error screen and made it show for crashes too early for MC to normally display by itself (Chocohead)
  • added error screen support for MacOS (Player)
  • fixed various MacOS error screen issues including the dock icon, title, dark mode, stuck on close (modmuss50)
  • fixed normalization of special MC versions like combat test, april fools or experimental releases (Chocohead)
  • various smaller changes and fixes

How to test

Due to the size of the changes we are releasing this version in stages, once we are happy everything is working we will release it to everyone. If you do find an issue please make sure to report it on our Github Repository.

Initially the installer won’t offer Loader 0.12 by itself, it has to be installed as follows:

  1. Go to https://fabricmc.net/use/.
  2. Click “Show other versions” and select 0.8.0, download the installer
  3. Download Fabric Loader 0.12.0 from here: fabric-loader-0.12.0.jar
  4. Run the installer and go to the Client or Server tab as desired
  5. Select the desired Minecraft version as usual
  6. Select (select custom) at the very bottom of the Loader Version list
  7. Configure anything else as desired and start the install as usual by using the Install button
  8. The installer will now ask for the Fabric Loader JAR, provide it with the one downloaded in step 3

A Fabric Installer version older than 0.8.0 will not support this procedure.

Mod Developers

  1. Ensure you are using Loom 0.7 or higher. Loom 0.10 is required to use transitive access wideners and develop on 1.18 snapshots.
  2. Change your loader version in gradle.properties to be 0.12.0 and reload your gradle project.

Mod resolution changes

Fabric Loader 0.12.0 will no longer refuse multiple versions of the same mod, some but not all of these may even have unmet dependencies. It will select the latest compatible version if more than one option is present.

If mod resolution fails due to unmet dependencies Loader will now try to compute a possible solution in addition to only stating what the issue was. It also tries to come up with a much better error message than before, unhelpful “empty clause” errors should be gone.

fabric.debug.loadLate

Sometimes mods make false assumptions about the load order of mods, which limits their compatibility unintentionally. Mod load order is not specified and depends on implementation details that may change with a Fabric Loader release. Version 0.12 is one of these and it is impractical to emulate the old behavior.

We have added a workaround for load order bugs in the form of the fabric.debug.loadLate system property, which will delay the specified mods to load later than all other mods. For example, if someMod required a block from another mod that’s being created in the same startup phase, adding -Dfabric.debug.loadLate=someMod moves someMod behind all other mods, including the one supplying the block it needs.

fabric.addMods

Fabric Loader normally loads mods from the mods directory, the fabric.addMods system property or game argument allows specifying more. It takes a list of paths separated by the operation system specific path separator (; on Windows, : elsewhere).

Supported options for the paths are:

  • mod jar location
  • directory location containing mod jars (searched recursively)
  • directory location containing an unpacked mod (for development purposes, detected by the presence of fabric.mod.json)
  • mod list file location prefixed by @, e.g. -Dfabric.addMods=@/path/to/extraMods.txt

A mod list file contains any of the above supported paths except another mod list file, one per line.

Paths can be absolute or relative to the working directory.

Mixin compatibility

Mixin has been changing its implementation in such a way that mixins that are correct and working on one version may no longer work correctly or at all in a newer version. This was necessary to fix bugs in its local variable detection logic.

Fabric adds a mechanism to emulate the Mixin behavior bundled with the least Loader version a mod depends upon. If the mod requires an old Loader version (or none at all), its Mixins will be processed in line with the old Mixin behavior. If it however depends on Loader 0.12.0, which comes with Fabric Mixin 0.10.2+mixin.0.8.4, it’ll use the native behavior that comes with that release and currently represents the latest&greatest.

Mods are highly encouraged to declare the minimum Fabric Loader dependency to reflect the minimum version they were tested against. If they need the latest Mixin behavior and fixes, they also need to depend on the latest fabricloader version explicitly.

For Fabric Loader 0.12.0 this can be done as follows:

  1. In the fabric.mod.json add the following dependency
"depends": {
   "fabricloader": ">=0.12.0"
}

The lack of suitable dependency declaration will always force-enable legacy behavior for the respective mod! This is undesirable for newly developed mods, but keeps older mods working.

ObjectShare

The object share is very similar to a String-indexed Java Map with arbitrary values. It offers the usual get/put/putIfAbsent/remove operations and additionally whenAvailable to listen for additions in cases without clear ordering.

Its primary purpose is inter-mod communication. One mod can put some data into it, another mod can pull it back out. Active interactions are possible by publishing and using objects with interfaces like Function or Consumer.

Contrary to any regular API the object share allows mod interaction without even a compile time dependency, removing friction for simple purposes. This case requires commonly available types/interfaces like the ones provided by Java, Minecraft or Fabric API (String, Integer, List, Map, Identifier, NbtCompound, Event, …). Custom types are of course still possible, but don’t carry these benefits.