LLibrary and best practices for core modding
JamiesWhiteShirt opened this issue ยท 14 comments
I am opening this issue so that it can be discussed if and how LLibrary and its users should follow the core mod best practices as officially stated by Minecraft Forge.
-
Coremod must be the coremod only, and no extra library/features/apis/etc.
-
Coremod binaries must be signed.
-
Coremods should be visible source.
Let's try not to discuss why these practices are the way they are and instead focus on how LLibrary and its users can adapt.
-
This one is the most challenging. I will outline possible solutions below.
-
@gegy1000 should continue building and publishing LLibrary, with the addition of signing all jars.
-
Obviously nothing has to be done.
In order to conform to 1. the core part of LLibrary, let's call it LLibraryCore, has to be isolated in its own self contained jar. Most importantly LLibrary can depend on LLibraryCore, but LLibraryCore cannot depend on LLibrary (this can supposedly cause issues with class loaders).
Note that we do not have to split the project distribution for this. Forge provides a (incomplete) jar-in-jar extraction mechanism that would allow bundling LLibraryCore inside LLibrary.
The options I know in the top of my head right now:
-
Split the project into two; separate repositories, separate projects and separate publishing for LLibrary and LLibraryCore. This is probably the simplest solution. We could still bundle LLibraryCore inside LLibrary with this approach.
-
Use gradle sub-projects. This would allow us to statically verify the required isolation. This requires some setup, but I believe it can be done.
-
Modify gradle build tasks to separate LLibrary and LLibraryCore. We lose the static isolation verification with this approach, but it should be plain and simple.
There is also an opportunity for another split. LLibraryCore has 2 components. The ASM utilities (let's call it LLibraryCoreUtils) and LLibraryCore. If we split this too, I would be able to depend on LLibraryCoreUtils only. That is the only part of LLibrary that Literal Ascension uses.
I will be experimenting a bit on this to see what is feasible to do.
To me it seems the most convenient way of separation would be to configure a gradle sub-project. I've setup up sub-projects before, so it's something I'm fairly familiar with.
It would probably make sense to go the extra step of splitting LLibraryCoreUtils from LLibraryCore, because there's no reason to depend on the features LLibraryCore is enabling when using LLibrary's ASM utils.
That makes sense with the current structure, although a big benefit we get from splitting the jars is the ability to depend on only what you need from LLibrary. This structure would mean you'd always be effectively depending on all 3.
I don't think the dependency structure I mentioned earlier is ideal either, though. You wouldn't want to depend on LLibrary if all you needed were the ASM utils.
We may want to remove LLibrary completely from the dependency chain, and have it independent.
I did not initially understand your proposed dependency structure, but I think I do now. You are proposing a distribution separation of (LLibrary) / (Core + ASM Utils).
LLibrary -> Core -> ASM Utils is the way I always saw it, however it seems LLibrary does not really depend on Core.
The distribution separation I had in mind is (LLibrary + Core) / (ASM Utils). This is what aligns most with my interests as I would like to depend on ASM Utils only. It would allow you to depend on the entire package or ASM Utils only.
On something that may assist us in terms of structure: would the features (events, remote language) provided by Core be packaged with the Core jar, or would they be in the main LLibrary jar, and Core would call it?
If it were in the main jar and LLibrary did not depend on Core, how would we ensure users know the feature they are using requires Core to function?
Also, I'd imagine the ASM utils would have it's own coremod, separate from Core's which handles the LDC type replacement and discovery of patchers.
... LLibrary can depend on LLibraryCore, but LLibraryCore cannot depend on LLibrary (this can supposedly cause issues with class loaders).
Core should package its events and only depend on ASM utils. The question becomes whether or not LLibrary should depend on Core. It looks like this separation will be somewhat tricky because LLibrary depends on PlayerModelEvent. This stuff would either have to be moved to Core (which would be rather ugly) or removed.
Yes, ASM utils should have its own coremod.
LLibrary's dependency on PlayerModelEvent
has been removed in 1.12, although this change has not been committed yet.
I have begun the process of separating LLibrary into sub-projects, and so far it's been successful, just need to figure out some things.
Also, do we want to be releasing the Core and ASMUtils jar in a different CurseForge project? I assume this would make it most simple for mods adding dependencies.
I think the core part that only LLibrary itself uses should only be distributed through the LLibrary CurseForge project as a jar-in-jar, but the ASM utilities definitely belong in a separate CurseForge project.
You should be able to embed the ASM utilities jar in the LLibrary jar to avoid the dependency hassle. However you have to verify that an environment where the ASM utilities jar is installed both independently and embedded in LLibrary works. If this is not the case, LLibrary should probably not embed the ASM utilities.
By the way, forge's jar-in-jar system does not work with core mods yet. This PR has to be completed and pulled first.
Wouldn't LLibrary Core depend on the ASM utils? I was initially assuming the dependencies would be set up something like: Core -> ASM Utils -> LLibrary
As far as I can tell, LLibrary depends on LLibrary Core and LLibrary Core depends on ASM Utils.
Looking into this more, and the separation of LLibrary and Core looks harder than just handling PlayerModelEvent
. Functions supplied by Core such as TickRateHandler
depend on LLibrary's proxy to set Timer#tickLength
. Implementing a proxy to core without an FML mod would be messy, and not ideal.
I only saw the link to my PR now and wanted to put my 2 cents in: dependency extraction might not work with the coremod being extracted at the moment, but it works just fine for the "normal mod" part. I've even put up an example that demonstrates a possible route. Note that the coremod does not need to be runnable without the other stuff and vice-versa, so they can be compiled together but shipped separately.