fabricmc / fabric-loader Goto Github PK
View Code? Open in Web Editor NEWFabric's mostly-version-independent mod loader.
License: Apache License 2.0
Fabric's mostly-version-independent mod loader.
License: Apache License 2.0
The current way of mod loading uses a list of initializer classes in the .JSON which can provide various interfaces. Specially annotated interfaces are, then, indexed in an accessible manner for queries - Fabric queries them for instances of "ModInitializer". This has a few issues, however.
Client/Server environment specific code
(As of 18w49a, there is only really client environment specific code worth worrying about, but for the sake of argument...)
Many classes exist solely on the client and accessing them on the dedicated server is... a bad idea, to say the least. My proposal here would be to add a "ClientModInitializer/ServerModInitializer" interface - with the caveat that those classes only get loaded on the specific environment. Another option would be marking classes as client/server-side-specific in the JSON file. Of course, we could also replace ModInitializer with something else entirely.
Using the JSON interface list for mod add-on resolution
Is this a good idea? Say, if JEI were to add plugins, it would just add a JeiPlugin interface which can be implemented by classes added to the JSON initializer list. For this, we could extend the former to also not load classes if the interfaces on them are not present in the classpath after all mods are added to said classpath.
META-INF/services vs JSON
Someone once said we should use the former versus a custom list format for classes. Just bringing it up, although honestly I'm not a huge fan.
Advantages:
Disadvantages:
Things to discuss:
Mod sorting is currently a stub in fabric. It can be done with a topological sort.
Examples of topological sort I wrote is at https://github.com/KyoriPowered/lunar/tree/master/src/main/java/net/kyori/lunar/graph and https://github.com/MinecraftForge/MinecraftForge/blob/e164b2f5d54798716a5f4914d781dacbbf4a0e47/src/fmllauncher/java/net/minecraftforge/fml/loading/toposort/TopologicalSort.java#L87-L123. Out of the two, the forge one should be concise enough.
It also incorporates a cycle reporting functionality based on tarjan's strongly connected components algorithm, but that part takes a few more lines. If you think the cycle reporting is too verbose, we can simply throw a regular IllegalArgumentException
instead.
For example, lever makes "Leash knot tied" sound, instead of it's normal sound.
Chicken makes "Chest open" sound, etc.
When other player walks on stone I hear button clicks instead of stone steps, other player hears stone step.
It works fine when fabric-loader is not installed.
This issue is intended for discussion related to the Java module system that was implemented in Java 9 as part of project Jigsaw.
If implemented in a way that would allow this functionality in Java 9 or greater while maintaining backwards compatibility with Java 8 should be fairly easy, but it will create issues if a backwards compatibility system of sorts is not put in place. If a developer creates a mod and only tests against Java 8 and does not specify any module metadata for Java 9+ it would have to be put into the "Unamed module".
For what I would consider a proper "backwards compatibility" needs the following:
module-info.java
) in modsopens
keyword)Then the actual module loader implementation would require the following:
If this is implemented properly it would allow more flexibility with libraries and prevent reflection hacking
from occurring. This prevents many issues with code accessing things that they should not, and can entirely hide internals of libraries if the need arises. It also makes it so all public fields, methods and types have to be explicitly exported. Makes it a little harder to leak info from implementations.
Method <T> Collection<T> getInitializers(Class<T> type)
is missing in the API class.
I wanted to see if a local client would work, and was confused when it did not:
Put both .JARs in the same directory. From the command line, run:
java -Xmx[RAM amount, for example 2G] -jar fabric-loader-[version].jar [minecraft server JAR] [arguments…]
This should let you run the server.
If you don't want to (or can't) provide the Minecraft server .JAR as an argument, it's optional - however, the JAR must then be named “server.jar".
I changed fabric-loader to fabric-installer. I also tried a variety of ways to provide the Minecraft server .JAR. The responses were:
Loading Fabric Installer: 0.3.0.17
No handler found for server.jar see help
I could not find the help, here or on fabricmc.net. I know forge installations can require extra options or clicks; I may be missing an installation step.
From what I can tell, fabric loader crashes if a dependency is missing.
I believe it would be more helpful for users if it displayed some sort of GUI explaining what mod dependencies are missing.
Implementing a permission system would increase the security of Minecraft, making it harder for a rouge mod to leave the sandbox of the JVM and damage the host system.
My current idea for the permissions module are as follows:
For implementation details, I am not sure. Would probably be best to use some sort of JSON configuration file.
Or maybe just expose the json objects. Whatever works.
I want to grab additional values fields for Mod Menu if they're present
Apparently the Realms JAR does actually rely on obfuscated Minecraft code (which is bad news).
This means I can't get away with just not breaking its deobfuscated mappings, but will have to remap it alongside the Minecraft JAR. This will be done in Loader 0.4.3.
Can reproduce with this repo/branch: https://github.com/grondag/smart_chest/tree/override_bug
Canvas will fail on launch.
To see the affected @Override
use cases, refer to these commits:
In 1.13+, vanilla adds net.minecraft.data.Main
entry point for both clients and servers to allow easy data generation. This generation appears useful to modders as it can create jsons with little code and is almost always up-to-date.
Can fabric loader add a hook for the data generation, so that mods can register their stuff and then generate content for data packs correctly?
Ever since loader 0.4.0, I've been getting a ConcurrentModificationException about 60-70% of the time when I try to run the game in a dev environment. It happens both with the intellij run configuration and with the runClient gradle task. Here's a sample stack trace:
**Connected to the target VM, address: '127.0.0.1:36833', transport: 'socket'
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
[23:04:14] [ForkJoinPool-1-worker-5/WARN]: Mod ID fabric uses outdated schema version: 0 < 1
Exception in thread "main" java.lang.RuntimeException: Mod resolution failed!
at net.fabricmc.loader.discovery.ModResolver.resolve(ModResolver.java:470)
at net.fabricmc.loader.FabricLoader.load(FabricLoader.java:144)
at net.fabricmc.loader.launch.knot.Knot.init(Knot.java:120)
at net.fabricmc.loader.launch.knot.KnotClient.main(KnotClient.java:26)
Caused by: java.util.ConcurrentModificationException: java.util.ConcurrentModificationException
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:600)
at java.base/java.util.concurrent.ForkJoinTask.getException(ForkJoinTask.java:933)
at net.fabricmc.loader.discovery.ModResolver.resolve(ModResolver.java:453)
... 3 more
Caused by: java.util.ConcurrentModificationException
at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1134)
at net.fabricmc.loader.discovery.ModResolver$UrlProcessAction.compute(ModResolver.java:379)
at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:189)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Disconnected from the target VM, address: '127.0.0.1:36833', transport: 'socket'
Process finished with exit code 1**
Motivation
As we need very few generic hooks, in this way, we could boot fabric-loader on arbitrary environments, mappings, Minecraft version, etc. blindly. Currently, we rely on the Intermediary names matching. Meddle's DynamicMappings, as well as some experiments we did in 2016, can be considered prior art.
To be done
I believe https://github.com/FabricMC/fabric-loader/blob/master/src/main/java/net/fabricmc/loader/launch/knot/KnotClassDelegate.java#L86 doesn't yield the correct code source, at least for non-jars.
The correct code source should be:
It should never point to a class file directly.
https://github.com/FabricMC/fabric-loader/blob/master/src/main/java/net/fabricmc/loader/util/UrlUtil.java#L40 appears to yield the class file instead of the base dir.
Additionally KnotClassDelegate.getMetadata could obtain the Manifest from the JarURLConnection directly and reliably.
Do we use 4 spaces or tabs? I think 4 spaces may be better.
People are going to do it out of habit, so we might as well avoid any weird cyclic dependencies caused by "" allegedly being a thing.
Alternatively, if we want to break the habit of that, spew an error if someone tries to use "" as an empty list instead of {}, and tell them to use {} if there is genuinely nothing to depend on.
Of course, there are very few things which will actually have no dependency.
My advice, use "fabric_internal_nodep_pretrap1" < "fabric_internal_nodep_pretrap2" and make everything within fabric-base depend on "fabric_internal_nodep_pretrap2". That way we can catch things out as early as possible.
And of course, at the same time, spew an informative error every time someone does "" out of habit.
It's much easier than trying to decipher where the cycle is in the hookchain, but we'll have to do that anyway.
https://github.com/FabricMC/fabric-loader/blob/master/src/main/java/net/fabricmc/loader/ModInfo.java#L136-L138
Should support an array of Mixin configuration file names.
When using a MultiMC client with fabric that has a path that contains spaces, it does not allow mods to load.
The Sided annotation is misleading:
A more appropriate name is Environment/Env/EnvOnly, with an entry for each distribution.
I'd love to be able to organize my mods however I like within the "mods/" folder, so for example I could maintain a structure like this:
minecraft/
| mods/
| lib/
| fabric.jar
| fabric-language-kotlin.jar
| cloth.jar
| crochet.jar
| core/
| roughly-enough-items.jar
| modmenu.jar
| content/
| level-up-hp.jar
| some-really-cool-mod.jar
| utility/
| lead-villagers.jar
| some-tweaks-here.jar
Deprecation in FabricLoader.INSTANCE
tells me to report stuff I'm missing, so: there's no getConfigDirectory
in api.FabricLoader
. Unless there's some other way to get the config directory now?
Knot is the recommended launcher now, but fabric-loader is supposed to be compatible with LaunchWrapper.
Trying to launch the server in a fabric-loader environment with LaunchWrapper results in this error:
java.lang.NullPointerException: null
at java.io.File.<init>(File.java:277) ~[?:1.8.0_162]
at net.fabricmc.loader.launch.FabricTweaker.injectIntoClassLoader(FabricTweaker.java:84) ~[fabric-loader_main/:?]
at net.minecraft.launchwrapper.Launch.launch(Launch.java:115) [launchwrapper-1.12.jar:?]
at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.12.jar:?]
This is the run configuration:
It seems during the addition of Knot the launcher mechanism started deleting the --runDir
option too early.
When using a built version of my mod, the client crashes with the following message:
java.lang.LinkageError: loader constraint violation:
Full log: https://gist.github.com/Blayyke/8830bee84b9ab84b83ce2aef029158c6
(this was run with other mods present but i have tested just with mine and it happens)
java -version output:
openjdk version "1.8.0_202"
OpenJDK Runtime Environment (build 1.8.0_202-b26)
OpenJDK 64-Bit Server VM (build 25.202-b26, mixed mode)
Edit:
This only seems to happen when I'm shading in org.spongepowered:configurate-hocon:3.6
.
I would like to use a separate non-mod library with a mod. It seems currently the only viable option is shading. It's not the end of the world, but I think it should be possible for the user to install non-mod jars, either in the mods directory or somewhere else. Jar-in-jar could also be an option but that's a bit further away.
Many modders have raised the issues of covering things Mixin doesn't do adequately. One of them is covering the domain of "access transformers", or ways to achieve the following:
There are two disadvantages of access transformation in general worth bringing up:
There are many approaches we could take. Of course, they should not be evaluated as competitors - some of them only cover part of the problem domain.
Approach 1: Do nothing.
Advantages:
Disadvantages:
Approach 2: Just add access transformers.
Advantages:
Disadvantages:
Approach 3: "OverridePrivate" annotation
Advantages:
Disadvantages:
Approach 4: Accessor.field(MyClass.class, "field"), Accessor.invoke(MyClass.class, "myMethod", a, b)
Advantages:
Disadvantages:
fabric-loader should rely solely on launchwrapper and the mixin library as to be includeable in Weave and versioned outside of Minecraft itself; fabric-base should depend on it and provide "essential" Minecraft-related functionality (kicking players on fatal mod list mismatches, for example).
All map
methods in FabricMappingResolver
require class names in dot format, but nothing is actually done to convert dot format to internal anywhere. As such, no mapping can ever get resolved.
This is the current exception stacktrace which is not at all helpful:
java.lang.RuntimeException: net.fabricmc.loader.language.LanguageAdapterException: I/O error!
at net.fabricmc.loader.InstanceStorage.instantiate(InstanceStorage.java:45)
at net.fabricmc.loader.FabricLoader.initializeMods(FabricLoader.java:458)
at net.fabricmc.loader.FabricLoader.onModsPopulated(FabricLoader.java:283)
at net.fabricmc.loader.FabricLoader.load(FabricLoader.java:264)
at net.fabricmc.loader.FabricLoader.load(FabricLoader.java:158)
at net.minecraft.client.MinecraftClient.handler$init$zzb000(MinecraftClient.java:2238)
at net.minecraft.client.MinecraftClient.init(MinecraftClient.java)
at net.minecraft.client.MinecraftClient.start(MinecraftClient.java:360)
at net.minecraft.client.main.Main.main(Main.java:126)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at net.fabricmc.loader.launch.knot.Knot.init(Knot.java:320)
at net.fabricmc.loader.launch.knot.KnotClient.main(KnotClient.java:26)
Caused by: net.fabricmc.loader.language.LanguageAdapterException: I/O error!
at net.fabricmc.loader.language.LanguageAdapter.createInstance(LanguageAdapter.java:36)
at net.fabricmc.loader.InstanceStorage.instantiate(InstanceStorage.java:40)
... 14 more
Caused by: java.io.IOException: Class not found
at org.objectweb.asm.ClassReader.readStream(ClassReader.java:300)
at org.objectweb.asm.ClassReader.<init>(ClassReader.java:273)
at net.fabricmc.loader.language.JavaLanguageAdapter.getClass(JavaLanguageAdapter.java:59)
at net.fabricmc.loader.language.LanguageAdapter.createInstance(LanguageAdapter.java:29)
... 15 more
To reproduce, use this repro/branch: https://github.com/grondag/smart_chest/tree/shadow_bug
Canvas will fail on world load at start of rendering. (Minecraft launch is successful.)
To see the affected @Shadow
usage see this commit: vram-guild/canvas@ed1782a
https://gist.github.com/modmuss50/9fcef9e6885fa185dfd822e6f1ffc487
0.3.0.77 works fine, so it must have been a recent change.
I don't believe the current implementation from #26 is as effective as it could be.
Currently, mod initializers are declared using the "initializer" string field or the "initializers" string array field in the fabric.mod.json
file. The strings are fully qualified names of classes that fabric-loader will create singleton instances of. An initializer class can implement any number of interfaces to expose itself. The same instance is used for each interface the initializer implements. ModInitializer, ClientModInitializer and DedicatedServerModInitializer are used by fabric-loader. It is also possible to use additional initializer interfaces and get them via FabricLoader#getInitializers(Class)
for add-on resolution.
Implementing ClientModInitializer/DedicatedServerModInitializer may have unexpected effects if implemented in a class that also implements another initializer interface. To avoid class loading issues in client/dedicated server environments, fabric-loader may avoid loading an initializer. Currently, depending on the environment, fabric will refuse to load initializers if they implement ClientModInitializer or DedicatedServerModInitializer respectively. When an initializer is not loaded, it will not be exposed for any of its interfaces. This means a class implementing both ClientModInitializer and ModInitializer cannot be exposed as a ModInitializer. Analyzing classes with ASM to avoid loading issues is something I think we should avoid.
One bug is that the test for implementation of ClientModInitializer/DedicatedServerModInitializer does not match the exposure, meaning there are ways to implement ClientModInitializer/DedicatedServerModInitializer and having it loaded when it should not be. Fixing this bug would make things even more dependent on ASM analysis.
There is also currently no way to declare dependently loaded interfaces for add-on resolution. I imagine initializers used by a mod like JEI might contain environment specific parts.
I propose that we declare common, client and dedicated server initializers separately instead of declaring them all together. We can implement the dependent loading mechanism at that level instead of inspecting initializer classes. This would also make ClientModInitializer and DedicatedServerModInitializer obsolete, as mods can declare a client-only secondary initializer implementing ModInitializer.
The @Environment
annotation is used in a development environment to indicate that something exists only in the dedicated server or client environment. It currently has no effect but it could be used for static verification.
The problem is that a runtime server/client environment is not truly simulated in a development environment. You can easily do something that works in a development environment but not in a production environment.
Examples are Block#addInformation
and Item#buildTooltip
(yarn:18w50a.59). TooltipOptions is an @Environment(EnvType.CLIENT)
class used as a parameter type in both methods. Trying to reflect on the Block/Item class will load the TooltipOptions class. Works in a development environment but explodes in a dedicated server environment.
The class verifier may also trip on implicit casts. As an example, you could have a field/variable/parameter with type MinecraftServer. If you attempt to assign this something like new IntegratedServer
, the class verifier will attempt to verify that IntegratedServer is a MinecraftServer, even if the expression is guarded using something like if (environmentHandler.getEnvironmentType() == EnvType.CLIENT)
. The IntegratedServer class will be loaded. Works in a development environment but explodes in a dedicated server environment.
We should strip methods, fields and classes in the class loader depending on the @Environment
annotation. Both net.minecraft
and mod classes could use this.
in the dev environment all jars in build/libs
are loaded as mods
when those include old builds of the project it leads to this kind of crash
java.lang.RuntimeException: Duplicate mod ID: fabric-example-mod-kotlin! (kotlin-example-1.0.0.jar, kotlin-example-1.0.1.jar)
at net.fabricmc.loader.FabricLoader.addMod(FabricLoader.java:305)
at net.fabricmc.loader.FabricLoader.load(FabricLoader.java:209)
at net.fabricmc.loader.FabricLoader.load(FabricLoader.java:143)
at net.minecraft.client.MinecraftClient.handler$init$zzb000(MinecraftClient.java:2169)
at net.minecraft.client.MinecraftClient.init(MinecraftClient.java)
at net.minecraft.client.MinecraftClient.start(MinecraftClient.java:358)
at net.minecraft.client.main.Main.main(Main.java:126)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
I think build/libs
should not load mods, and instead there should be utility to populate mods/
with any dependencies (as part of modCompile
?)
Running a fabric server with Cotton-Energy (jar in a zip
attached below) will cause the server to crash with this output: https://gist.github.com/Blayyke/3f50792b1f4a905956c3832abe2db6c0.
Running the server without cotton-energy in the mods folder does not crash, and using some other combination of mods also does not crash. However, I think cotton-energy is the only mod that uses nested jars, so this may be a loader 0.4.0 issue. This crash does not occur on a prod client, dev environment client, or dev environment server.
When loading a Fabric mod I noticed that all classes have no package information.
To reproduce just print out the package in "onInitialize":
LOG.info("Package: " + this.getClass().getPackage());
[Server thread/INFO]: Package: null
In my case this crashes snakeyaml because there one class tries to create a logger with the package as name.
Fabric-loader should probably distribute a library for one, at least.
There are many options which were brought up: YAML, HOCON, IC2-style .ini files, something entirely custom, etc.; and many libraries which implement them. What would you, as a modder, want to use?
i think this might be mostly loader related
https://gist.github.com/NikkyAI/792753436bf874bfa0ca539ef2a00735
constructing the Language adapter for kotlin fails and the resulting crashlog creates
some files that should not be there: file:/$PROJECT_DIR$/run
https://i.imgur.com/Jps6WmL.png
Since the latest release (0.4.1) the following mixin into a private inner class doesn't work anymore:
@Mixin(targets = "net/minecraft/recipe/RecipeFinder$MatchableRecipe")
It fails with the following message:
Error loading class: Lnet/minecraft/recipe/RecipeFinder$MatchableRecipe; (java.lang.ClassNotFoundException: Lnet/minecraft/recipe/RecipeFinder$MatchableRecipe;)
It works fine with Loader 0.4.0.
I don't know whether this is related to changes of the loader or changes of the mixin library. So feel free to close this here and open it there ;)
encountered on keys: depends
, mixins
tested via ./gradlew runClient
incorrect json or the like seems to make loader drop the mod without logging errors (it might log in debug but thats hidden by default in gradle and i did not check)
This issue is for discussion of the structure and layout of configuration files. If you are looking for the issue on the configuration file format (JSON, HOCON, YAML), see issue #30.
The issue I'd like to discuss here is that there is not one type of mod configuration, but three:
Set A will include breaking changes that, if modified, will require a restart of the client or server. Thus, it is logical to place these in a "cfg" folder, and additionally have a separate Mod Configuration menu in the Main Menu that users can use to modify configuration values.
However, for those options in Set B, including these options in the Mod Configuration menu makes it hard for users to determine what is safe for them to change. Additionally, if the Mod Configuration menu is accessible in-game, that can cause problems as options that are not meant to be changed mid-game are changed, whereas if the Mod Config menu is only available from the main menu, that excludes options that should be allowed to be changed mid-match.
I would like to see mod configuration split into two logical categories.
Config properties (Set A) would be breaking changes, and require the user to access them either through modification of a config file in the mod folder or through some GUI accessible only when the user is not logged into the world.
Options (Set B) would be treated semantically differently. They should hook into the vanilla options menu, being added to either a special "mod options menu" (which would not be preferred since users might confuse them with immutable config properties) or, preferably, the appropriate submenu in the options menu. Integrating the options fully would make them feel "natural" and make them more user friendly.
For those options in Set C, the Server (upon the client connecting) would send a packet containing the server-operator-defined range of allowable values for the client, with a chosen default value for those clients which are not in compliance. The client would receive these, and temporarily adjust those options to the provided defaults if they are not in range.
Note that including comments and labels in the config itself as an object, this is not extendable, especially to multiple languages. Names and descriptions (for both config properties and options) should be read from lang files using translation keys:
config.<modname>.<configkey>.<configsubkey>.title
and config.<modname>.<configkey>.<configsubkey>.desc
Additionally, it may also be appropriate to place config properties in the data folder, allowing replacement of them with data packs.
The classpath apparently supports wildcards as described here: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html#A1100762
The loading code seems to assume the entries cannot have wildcards. I don't know whether or not this is needed in practice.
I tried to make a simple mod using fabric-language-kotlin, and noticed my mod's initializer wan't being called. Initially I thought it was the fault of fabric-language-kotlin, so I tried again in Java. The problem persisted.
I did some debugging, and found that the initializers stored in InstanceStorage
weren't being mapped from classes properly. Specifically, Fabric API's initializer and my initializer are being mapped from two different "instances" of the ModInitializer
interface class. Here's a screenshot to show what I mean:
You can see there are two ModInitializer keys, one Class@6421
, and one Class@6419
, each with only one mod initializer in its set of values. So, when the loader tries to get all mods' ModInitializer
, it only gets it from Fabric API, not my mod, and misses running my initialize.
Did some more digging to find how this MultiMap
get populated, and found that you call getInterfaces
on my initializer class.
This is where the two different Class<ModInitializer>
instances are coming from; see Class@6430
and Class@6428
. I recommend you use the class's canonical name String
as the key of the MultiMap
inside the InstanceStorage
, not the class itself since it seems two different Class<Foo>
are not guaranteed to always be equal.
My versions are as follows:
minecraft_version=19w13a
yarn_mappings=19w13a.2
loader_version=0.3.7.109
fabric_version=0.2.6.116
Currently, to conditionally do something, you have virtually 2 choices.
1.
if (disabledFeature) return;
I think the mixin JSON could be extended to allow a condition to be passed next to the applicable mixin.
I'm going to write up a rough concept I had for discussion:
The goal of a good versioning system would be to make things easy for modpack developers, users and modders. That's important.
Let's take some notes from SemVer: MAJOR.MINOR.PATCH-BUILD, to put it in a very, very shortened version. But let's change things up a bit.
Another approach would be to have separate versioning for API (SemVer), user-facing mod (whatever parseable) and network protocol (integer). However, I have concerns about proper maintaining of the network protocol version by modders in particular - if we had a higher-level networking system in FabricAPI we could perhaps check some kind of immutable schema, but eh...
As you might've noticed, in 0.1.x-0.3.x the fabric.mod.json format is effectively "defined" by the Java class - this doesn't really make for good documentation or specification.
This is an issue opened to discuss things which should be covered by a fabric.mod.json standard ("schemaVersion": 1) which I hope to add in 0.4.0 - with the prior JSON files being implied as "schemaVersion": 0.
These are the existing fields in the mod.json format as of 0.3.6:
// Required
private String id;
private String version;
// Optional (environment)
private DependencyMap requires = new DependencyMap();
private DependencyMap conflicts = new DependencyMap();
private String languageAdapter = "net.fabricmc.loader.language.JavaLanguageAdapter";
private Mixins mixins = Mixins.EMPTY;
private Side side = Side.UNIVERSAL;
private boolean lazilyLoaded = false;
private String initializer;
private String[] initializers;
// Optional (metadata)
private String name;
private String description = "";
private Links links = Links.EMPTY;
private DependencyMap recommends = new DependencyMap();
private Person[] authors = new Person[0];
private Person[] contributors = new Person[0];
private String license = "";
Some prior art:
I'd also like to call in @peterix as he might have lots of prior art from his work on MultiMC.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.