Quote from the Discord for context:
I think by this point it should be evident that we can't forever evade making breaking changes to Grimoire itself, unless we want to just leave it as-is until the end of time or see how it slowly turns into abomination that has 90% of its code in place solely to maintain all the backwards compatibility. My whole idea is to just make such changes once in a way that would minimize need to make them in a future. Not as simple as it sounds, but I believe we could figure something out with some thinking, careful planning and clever design.
As such, I envision glorious new Grimoire as Mixin-provider framework that will offer vast possibilities for configuration control and management, as well as some interaction between implementers of this framework. We shall sacrifice backwards compatibility once, in order to create an interface where internal workings behind that interface will be better adapted to future alteration and extension, while everything exposed to external implementers will remain stable and wont require any changes on their side when updating, unless they want to use new features that may be added. Through the power of our incredibly very custom ForgeGradle fork we should also be able to further extend support for in-dev environments and simplify workspace setup required to use Grimoire, since as it stands such setup requires a couple shenanigans in buildscript to make it all work.
So, let's go in order:
Better Naming
"GrimPatch" doesn't quite seem to perfectly reflect the awesomeness and power that implementers of our new framework shall possess, since Mixins aren't always about patching broken things, but also about expanding the opportunities of mod development and achieving things previously impossible. So let's name them something different. I suggest "Grimmix" for the time being.
The Great Divide
Probably the most breaking of all breaking changes. I suggest to split Grimoire in two parts, where one will be the Mixin framework itself, while another one will implement its features, embedding Grimoire-Mixins and from then on bearing responsibility for loading them. Let's call that part GrimPatcher for now. I furthermore suggest to make it so that GrimPatcher will by default ship all Grimoire-Mixins all within itself and provide a config file that will allow users to configure what patches they wish to be loaded without having to mess around with a ton of jars themselves. It's probably better to have all patches turned off by default, leaving user to choose themselves what they absolutely want.
Grimmix Loading Plugin
So, something similar to IFMLLoadingPlugin
. In our case it will be the controller providing to Grimoire information like grimmix name and priority it should have compared to other grimmixes, and also be capable of receiving crucial lifecycle events from Grimoire itself, like from the the stage of loading core mixins and another one from the stage of loading mod mixins. Furthermore, the burden of loading actual configurations will be relayed to the implementers, while Grimoire will just dispatch events where such loading should happen and provide methods necessary to execute it, or ones that will just be helpful in doing so (for instance - something like #iDontWannaTypeInConfigurationNamesJustScanMyJarAndLoadWhateverYouFind()
).
Specialized Grimoire Event Bus
A bit about that inter-grimmix interaction I've been mentioning above. Be pretty cool if we provided a number of Grimoire-associated events, not just dispatched to controllers mentioned above, but in general to any subscribers of aprropriate EventBus
. Thus far I envision following list:
- Special validation event, dispatched for every individual controller after all controllers are found and constructed. If cancelled, grimmix associated with this event instance will be dropped from the list of loaded ones and Grimoire will make no further attempts interact with it through its lifecycle methods;
- Pre and Post for core mixin loading, and also individual one from before dispatching call to every individual controller. First and third will be cancellable;
- Pre and Post for mod mixin loading, and also individual one from before dispatching call to every individual controller. Again, first and third - cancellable;
- Pre-Event for every individual attempt to load specific mixin configuration. Cancellable. Relies on the fact all implementers will use Grimoire's own methods for loading configuration and not call Mixin directly, but let's just consider this a new convention;
Since force-loading MinecraftForge.EVENT_BUS
at the time of these events would be rude, and besides, that bus is really a crowded place nowadays, I suggest to make our own incredibly very custom EventBus
for events listed above, and potentially for any Grimoire-associated events we might have in the future.
EventHelper Integration Module
Just a library module that will present optional integration with EventHelper, since this is what a lot of patching in Grimoire-Mixins seems to be about. Instead of using EventHelper as hard dependency, it will allow to call its methods if it is loaded among other mods, otherwise relaying calls to some dummy implementation to not break things in case it's not there.
Should be a great thing to use in that GrimPatcher thing I've been talking about above.
ForgeGradle Goodness
As mentioned above, having a proper workspace setup with Grimoire does require an amount of shenanigans in buildscript currently. I believe it should be possible to implement these on the side of ForgeGradle and simply expose some boolean property like enableGrimoireShenanigans
to allow FG initialize them for you by setting that property to true in buildscript.
Extra Gimmicks
There is an amount of potential events it would be absolutely cool to have in Forge, but for some reason Forge itself never introduced them, or only did so on the new MC versions. Some instances would be:
- Final version of entity-receiving-damage event. While
LivingAttackEvent
is dispatched before any damage processing is done at all, and LivingHurtEvent
is dispatched after it is certain that attack will be considered "sucessfull", armor, enchantment and potion damage reduction calculations are all aplied after both of these events, and there is no way to intercept damage after they were applied. Would be cool to have some sort of LivingDamageEvent
, where we intercept and pass damage after all damage reduction calculations, but before the result was subtracted from entity's health;
LootingLevelEvent
and FortuneLevelEvent
. As it stands, there is no direct way to alter what level of Looting and Fortune player is considered to have when slaying mobs/breaking blocks. LootingLevelEvent
was actually added on new MC/Forge versions, but one for Fortune level never was.
We could go ahead and introduce those as part of Grimoire itself, to reduce amount of Mixin action going around particular use-cases that require something like them. These would really be just gimmicks, since they are not crucial as framework functionality, but if we're feeling fancy - might as well go for it.
The Great Merging
Although I believe it has to be possible, I'm not really sure how some of the ideas above will align with this whole codebase merging thing. I also don't really have any experience whatsoever in interaction with 1.12 toolchain, so my helpfulness in this initiative might turn out to be rather limited, though I will most certanly do what I can if we're aiming for this.