-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] Convert Forge's CoreMods to Mixins, deprecate JS CoreMods #10177
base: 1.21.x
Are you sure you want to change the base?
[RFC] Convert Forge's CoreMods to Mixins, deprecate JS CoreMods #10177
Conversation
- Minecraft Forge can now ship its own Mixins. - `ForgeMixinPlugin` is used as both the connector and plugin. - The plugin can be very useful if we need to do manual ASM for any unhinged reason. - `minecraftforge.mixins.json` acts as the Mixin counterpart to `coremods.json`, giving all the necessary info for Forge's mixins.
@Redirect( | ||
method = { | ||
"<init>(Lnet/minecraft/world/effect/MobEffectInstance;)V", | ||
"getParticleOptions()Lnet/minecraft/core/particles/ParticleOptions;", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way that these strings can be encoded better to provide better error when things change?
@MethodRef("<init>", args = { MobEffectInstance.class }, ret = Void.class)
or something?
Perhaps a build script task that verifies that we have all the expected targets?
We already have the code to generated the json that feeds the existing coremod, can something be expanded to mixins?
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
As discussed on Discord, I will be taking a different approach to these larger-scale Mixins that require several classes in order to have the same functionality that the original CoreMods did. This will likely mean writing a tool that generates Mixin classes on Gradle build. Smaller-scale mixins, like for patches we make already through bin patch, are more suited to the way Mixins are currently written. |
Issue with this proposal:Mixins are incredibly non-dynamic. If you need to target an arbitrary number of classes - for example, trying to allow pack devs to add blocks as Thaumcraft "Infusion Stabilizers", meaning you have to monkey-patch an interface onto them because they for some reason don't use capabilities - you physically cannot do this with Mixin. Believe me, I've tried. If you need to do any sort of dynamic targeting, you have to either use a class transformer or a janked-out Mixin plugin. Obviously, I'd much rather use a class transformer to reduce the amount of jank present rather than increase it. Mixin is an amazing framework for ASM, but access to the raw ASM is required for anything that isn't known at compile-time. I would strongly suggest that you keep some way of accessing the raw ASM layer in Forge, even if it's just "put the names of your old-fashioned |
Yes, we've had this discussion in the Discord server already. I forgot to give updates here, so my bad. However, ModLauncher transformers effectively do what CoreMods already does (it itself is a ModLauncher transformer service) without the difficulties that come with maintaining CoreMods in JS (see #10157 for an example). Although it is probably true that a simpler solution could be created that uses ModLauncher transformation service without being to cumbersome. Right now, ModLauncher transformers are expected to add their own plugins as well, and it's kind of an esoteric process. (Disclaimer: I have never actually written any ModLauncher transformer services myself, but this is how I've seen it done in the wild.) In fact, Mixin has already turned out to be a pretty bad solution for Forge's existing CoreMods. I plan on rewriting them in raw ASM transformers instead, probably through a ModLauncher plugin. |
I'll be honest, a hybrid approach might be best. Instead of requiring people to write in JS to avoid classloading loops, just use the old coremod system but require all coremod classes to be in META-INF instead of the main jar. That way you can load the mods' classes as late as you want while still having access to their coremods. All you need from there is a way to export the data from the coremod phase to the mod phase, like a global data cache that persists between phases that mods can retrieve from when they launch. A singleton hashmap that mods request data from by name. Adding that second part would pretty much fix all of the issues with the old coremod system. Hell, I'd even be able to actually use a segmented jar if that were a thing. |
That might be the play, although I'm not entirely sure how I would be able to access compiled classes from META-INF (I have never done that before!!!), let alone make a way for modders to write CoreMods so that they can end up in there. But yeah, repurposing the current CoreMods framework is a decent solution since it already complies with the ModLauncher transformation implementation.
I don't know why you'd need to export data from the coremod phase, when the only thing that should be done during the coremod phase (or even what the CoreMods should be doing at all) is running transformers on ASM trees. However, since these CoreMods would be running in Java and can access ModLauncher, you can easily write a key to ModLauncher's blackbord (here is a write example in MinecraftForge and a read example in CoreMods). |
Well, besides the fact that visitors are a nice option for a lot of one-time transformations, the biggest thing is that anything sufficiently high-level requires some amount of knowledge of what's on the classpath and what transformations were or weren't applied. Considering it's just "let a map exist during the ASM phase", I hope it's not too much to ask. The thing I ended up needing it for was checking if TickProfiler was installed, and disabling my Mixin and adding warning tooltips to a block if it was. For some reason, TP caused There's one more thing: as someone who tried his darnedest to work with the 1.12-era coremod system, the place where the split jar failed was trying to load Mixins in the Init phase. Since Mixins are compiled classes, they have to reference things that exist on the classpath. The problem is, when those things are APIs that only exist during the Mod phase, you can only compile them in your mod jar. But then you can only apply the Mixins early enough during the coremod phase... and it all comes apart. You can see this happen in real time between this commit and this commit. I can't think of how to fix this, but I figured you should know about it before continuing down that path. |
It's time to kill CoreMods.
Background
Since the FML rewrite in 1.13, JS CoreMods have existed as a replacement to the previous Java-based CoreMods transformers that has existed in versions 1.12.2 and older. This was done to keep transformers within a sandbox where they couldn't cause unhinged early classloading issues and other nonsense. However, since 1.16 (and eventually 1.15), Forge has been shipping SpongePowered's Mixin as an alternative solution to transforming classes at runtime. It has since become the defacto "coremodding tool" and effectively supersedes CoreMods. Besides, if people really wanted to write ASM transformers in Java, they already can with ModLauncher services.
All that said, I have made this preliminary PR for a handful of reasons:
Migration to Mixins
With regards to migrating to Mixins, there are a few key points that need to be addressed.
Forge's Mixins
As of the creation of this PR, I have converted the existing CoreMods into Mixins.
Mixin Libraries
@WrapOperation
than@Redirect
since MixinExtras can chain injectors of the former properly).Note
MixinExtras can already be, and is already commonly, shadowed in with mods by using the JarJar system. It is not imperative that this is added to ForgeDev or UserDev, but would add to the convenience of modders.
Deprecation of CoreMods
As mentioned above, an additional purpose of moving Forge's CoreMods to Mixins is to incentivize the deprecation, and eventual removal, of the CoreMods framework. CoreMods's only purpose was to provide a method of creating ASM transformers within a sandbox, and it has ultimately failed at that goal considering the status of Mixin and the availability of ModLauncher transformer services.
So, we need to decide the following:
Note
Raw ASM transformers can still be created, with Mixin, by using a Mixin config plugin and overriding
postApply()
.Merge Process
Before this PR can be merged, the following must happen:
Disclaimers
Please note that, as of writing, this PR is still a work-in-progress and things about it may change, including the information in this PR description and the discussion surrounding it. Major testing still needs to done and discussions need to happen in order for this to go anywhere. There is no time limit, but I hope that this RFC PR is enough to start preparing for this change.
None of the changes in this PR will be backported to any versions before the merged version unless there are specific changes that can be which don't break compatibility, binary or otherwise.
Important
If you are a modder, you should not be using CoreMods or Mixins before attempting to use existing Forge APIs. You are more than welcome to write PRs that add your desired functionality to the mod loader.