#FML Clean-up
1 messages ยท Page 2 of 1
Correct
what change? NDOC'ing fml?
I mean
Making sure that there are no hardcast is a good idea
Even in the current setup
Concepts of caching, or other locating mechanics do not matter
They would require a massive refactor anyway
Well to remove the hardcasts, we now have to promote things to API that previously were not, however
Yeah which is fine for now
The amount of API refactoring that will happen is so large
I am just hesitant since it might increase the workload to clean it up later
given the use-cases currently do work
The larger workload of the cleanup comes from the fact Maty wants a lazy compile
Worst case scenario we can presumably get it working with cursed filesystem based fuckery instead, honestly
@glad cobalt have you ever considered getting Jij to work at the ML level to allow ML plugins to be JIJ?
Thinking ahead and of neoforge as a mod jar, we likely would want to have FML Jij in it
I thought about it
It is doable
But it would not be pretty!
If we do FML iterative discovery, then we should discover that on ML level too
And then it might be doable
Hmmm yeah. I am prototyping some stuff. I.e. I have a working prototype of FML that generates the client jar on-demand using installer-data embedded in a neoforge.jar (which is just in the mods folder)
That works, but if we pursued that, we'd still have to add FML itself to the launcher profile. The only way around that is to have JiJ on the ML-level ๐ค
I am trying out having a unified client.jar come out of that, but I still need to verify that the neoforge data+assets correctly override vanilla since y'all said that's why client-extra exists
Do FML and ML really need to be separate nowadays?
If we have neoforge-as-mod-jar, having a version-independent launcher that does the bare minimum to get us to load is nice
since then the installation would just consist of getting the mod-launcher into the launcher profile, and dropping neoforge in the mods folder
ML itself has very few dependencies besides asm... so a few libraries, a different main method and you'd be good to go
updating neoforge/fml would then just consist of replacing the neoforge.jar in mods/, no rerunning installer needed
I see
Yes
There are many users of ML outside of FML
Hell most of them are even outside of modding
The question if we have to cater to them as a project remains, but ML itself isn't too much of a problem, really
I'd personally hide the entire securejar stuff as an impl detail from downstream, though. But that's largely indepenent of the split
Yes we do
The same way Mixin is used downstream outside of Modding
As a project we certainly don't have to ๐
Yes and No
I'd say at the very least with Sponge it's a give and take, given Mixin
We use Mixin, they use ML. Tit for tat, so to speak ๐
Again, ML is not really an issue
There are some things to simplify, but most of the meat is in FML
One thought I had was to use dist-specific entrypoints in ML to make detecting the dist more trivial than it is right now
IDK why mixin for example has to reach into FML to detect the dist
We should have that in ML
All of that would only be possible once ML is modularJPMS-ready though
as I understand it, the scope of ML should be the same as LaunchWrapper, right?
pretty much
No
Not 100%
The combination of BSL and ML is LaunchWrapper
Up to a certain degree
BSL is a hack, don't forget that
it would not need to exist if ML was actually JPMS capable
Hm, that is a half-truth. it's less ML and more the consumers of ML that needs to be JPMS-compatible ๐
Correct
I am 100% for it
If we enforce JPMS downstream
But we need to design "encapsulation" breaking mechanics
what does enforce JPMS mean? everything is a module?
Okay the primary reason you cannot put ML itself on the JVM module-path right now is the use of Implementation/Specification version to check for compatibility in downstream projects
Since the concept of Implementation & Specification version do not exist for "normal" JPMS modules
But they do exist for modules created by SJH
Yes
well everything is already a module, but we use too much custom plumbing
Including mods?
mods already are modules
oh yeah
but my focus is more on the layers above game... in game you circumvent any encapsulation with AT/Mixin/Coremods anyway
but since those don't affect FML/ML/Libraries, there's potential for encapsulation through modules there
Why would the tools above game need to do any special hacks (except maybe SJH)
they don't
and they don't need SJH either
It's just a property of ML right now that it enforces SecureJar
My next prototype after module-less is probably modules, but vanilla JRE classloaders ๐
thoughts on removing ICoreModFile and ICoreModProvider from SPI and directly using CoreMods instead?
(this would also fix the current spi -> coremods -> fml dependency that we have)
Hm? I don't see a spi->coremods dependency?
Hm but I think I can see what you mean. There is no extension point there, the SPI is actually the API that coremods implements, but there can only be a single provider
A mod could conceivably call FMLLoader.getCoreModProvider().addCoreMod() at any time, without guarantee that it would do anything.
But the API seems to be available. How do we handle that? Just replace ICoreModProvider with the concrete CoreModProvider class?
yeah that's what I would do
I'd be okay with that, the API doesn't really get us anything. The coremod lib is exposed as a transitive dependency to mods already (sadly)
I anticipate some changes in CoreMods once we get java coremods working, so we could also keep the current thing for now
leave it, but if we can hide the actual impl l ibrary from dev that would be nice. not that I have a good idea on how to do that ๐
the goal is that we don't need the library anymore once we have java coremods
which in my mind would be loaded from PLUGIN layer jars
Hm
I don't know that I'd really do it that way ๐
what kind of classes do coremods need to reach? I'd have said, java.base, coremod api, asm and otherwise fully isolated from anything else?
why do we need to isolate them so much? ๐
well it's true that they don't really differ too much from ITransformer implementations, I suppose
the idea is that they would more or less be ITransformer implementations
Please dear god don't isolate them any more than is actually necessary. All sorts of useful bytecode transforming libraries people might want to bring in
Besides which, there's really no argument for isolating then beyond just keeping them above all the game or mod level stuff
Because they should not touch or fuck with anything else
And I will be vetoing any PR that lifts that restriction
The point is that they are 100% not allowed to request or load any classes from anywhere
Other then the ones they provide themselves, or are basically ASM and its dependencies
It is part of the architecture
And there 0 reason to change that
They are supposed to be stateless
Adapters of code
They are not supposed to touch anything other then themselves
And the fed in bytecode
What is your reasoning for that architecture?
They are less powerful than launch plugins which do NOT have that restriction
You always make this sound like it's a political issue by immediately putting your foot down ๐
yeah there's no "vetoing" this is just shitty intimidation
No there is
This architecutre was specifically chosen
Because we did not have it in the past
And that caused so many fucking untraceable issues
Maty let's just explore what is going on, I'd like to know
With people loading classes early
What does early mean?
We have a layered class-loader structure now, they can only load up...
It might be possible to loosen
But what would you loosen to?
They are in a completely isolated layer
Same principle as launch plugins
On purpose
which are in a plugin layer
I mean that seems reasonable
essentially we are exporting ITransformer instances
But why?
The point of coremods is that they are stateless self contained systems
Else make a transformer
You can't add a transformer from a game content jar right now, I believe
Well I mean even as a JIJ plugin
You have restrictions applied to you
no no, JIJ doesn't though
Basically core mods are loaded from a mod jar if I remember properly, like mixin and others
Whatever we do for java coremods, the boundary has to be along JAR-files, as in, coremod has to be a separate jar JIJ'd into the game content jar
Seems reasonable yes
which then gets loaded above the game layer (and before the game layer even exists)
I mean for Java coremods it makes somewhat sense to allow them to access dependencies
oh i'm just annoyed by how
A team is a group of people with similar goals, and equal weighting in most decision making
is only used when it's beneficial and ignored when it's not lol
Stop the strawman argument, cause taht statement also means that we need consensus to make desicision which we do not have on this topic!
So please discuss this on the content.
This architecture has been put in place in the past because people fucked it up fiercly and violently. It is there because it is a safeguard for us all not because it is usefull or nice to have. It makes our systems a lot easier but also a lot safer
Again in a java coremod environment, I think there might be an argument to loosen it a bit
But to what
There are not many other libraries that makes sense
I mean
Maybe GSON
Or something
no, you can stop with "And I will be vetoing *" cause that's not the attitude this project is meant to have. if you start your sentences with that it's by the book intimidation
you can discuss without threaths
threats is how most FML discussions started and resulted in
Sure, let me state it like this, without reasons to loosen the restrictions, I won't agree with this change, and will request changes to it's justification
i thought we agreed we'd get rid of that?
great thanks
It is a statement of fact
now you can continue the discussion
You know that it means exactly the same thing right?
no, one is absolute "no discussion" and the other is "i'm not a dictator so i'm open to discussion"
A veto is not a "no discussion"
And I specifically stated that i would veto a PR
Not the discussion
I thought that was clear
Back to topic
not sure where people are supposed to get "you can discuss" from that
Sharte the core concept of coremods is that they are isolated from the environment
The fact that I kept writing and arguing
There is still no reason to change it
In my opinion even in java land
They should touch java.base, asm and that it is
They are supposed to be isolated mutators of the code
Not touch random shit
Or load config files
Or mutate the state
As such architecturally there is no reason to lift the isolation
then why do people get "fml should be deleted" from my messages that state that i find fml a mess when i still discuss incremental changes to it that don't necessarily mean throwing it out and rewrite it
As said I could have stated that differently, but can we now get back to topic, and stop discussing my wrong way of writing and hammering this on me
@haughty copper Is there some design or implementation within java coremods that you think is not achieveable with isolation in place?
As in the same isolation that JS Core mods right now have
Besides the fact that they are also isolated through their execution environment
?
@Orion the real problem in the old (1.12) design is that there was no classloader isolation AT ALL between transformable code and transforming code
I know
But there is also no argument to undo it
Unless there is something that can not be done with their current architecture in mind
So a transformer could directly load game code in the wrong CL and prevent others from transforming it (in 1.12)
I mean, we have the module setup exactly to prevent this sort of issue
A coremod in the PLUGIN layer has no chance whatsoever of loading game classes in the wrong CL
By construction of the modules
Again large part of that restriction comes from the runtime environment JSCoremods are in
I consider Java coremods to be more similar to Transformers so existing in the PLUGIN layer as said above
And with that kind of isolation in mind
Not at all, the module system is a fundamental component of the jvm that prevents this sort of CL issue
JS coremods made sense in the 1.16 context where modules were not available, imo
Yeah I know that....... What I am saying is that coremods right now can not have dependencies loaded because of the nashorn runtime it runs in
And indeed the fact that it was designed like way before modules
And I am asking
What I have in mind for Java coremods is just loading them via SPI from PLUGIN libraries
With us putting them on PLUGIN, as in using that module layers isolation, is there anythign that a modder could not do, which we would deam reasonable?
Yes I understand that, and that isolation is fine
It is basically JSCoremods minus nashorn
Ah but then we're all on the same page
The coremods will be able to access any lib then, since libs are also plugin layer
I assume that is fine
(except for GAMELIBRARY jars which will not be accessible)
I see no obvious reason why that would not be fine....
But I also see no reason to lift the restrictions further
I mean that's already a massive lifting compared to js coremods ๐
I just got the impression that you wanted more isolation than plugin layer
You are right that the isolation for coremods originated as protection, and that today that protections is given by modules, so the runtime isolation is not needed anymore.
But I am also against lifting restrictions for liftings sake
I would welcome it, if in someway we could really isolate all transformers from each other, to be able to reload and discard them if need be (failing broken transformer scenario)
But I also understand that that is fundamentally more difficult
So I consider that at best a stretch goal
On mobile right now so limited ability to follow...
I mean that's not really transformer specific
Is there a usecase for accessing loadingmodlist to conditionally.enable compatibility transforms?
In a stretch world we could recreate all layers, reset FML, and only load forge+mc
I'm only just skimming the chat since I'm in a meeting right now, but wouldn't it be a lot simpler to initially have no isolation, and add it on at a later point?
No
From experience that is going to get people mad
If we do isolation
We need to set it up right
And do it from the get go
Gotcha
It is like adding a firewall on whitelist mode after people have deployed 20 apps
That now all break because they try to access something that they previously could
Yeah, that makes sense; I was just thinking that nobody currently has actually "used" the isolation, so to speak, so they might not even notice that it's missing
Every JSCoremod basically does, because it runs in nashorn
But yeah
No ITransformer ever had any
Maybe, but there might be a discussion topic here if it should not be there
Or at least maybe have a distinction between "priviledged transformers" like for forge, or fml. And "mod transformers"
Don't use SJH and use real modular.classloaders instead 
That would be trivial to do after the fact once we have module reconstruction working
Is that even possible from the vanilla launcher?
If you were to load in safe mode you wouldn't even look at mod jars except forge's
So their transformers wouldn't get loaded at all
Of course
Neat
Isn't the core concept just that they can modify bytecode using ASM? ๐
Sorry, I am just getting to the chat history now
He means the JS coremods literally
(the CoreMods repo)
Not the overall ASM concept
oooh ok
Question: why is the default layer for JiJ libraries with nothing else specified GAMELIBRARY, not LIBRARY?
The average library that's JiJed doesn't touch vanilla classes. If it does, the developer is aware of FML to some degree and can add that to the manifest
There is no GAMELIBRARY Layer
Erm, whatever the default JiJ one is. It's not LIBRARY
There's only BOOT -> [SERVICE|PLUGIN] -> GAME
But without checking, GAMELIBRARY likely goes to GAME while LIBRARY goes to PLUGIN
Yes that's my question: why are otherwise unspecified libraries that are JiJed sent to GAME not PLUGIN?
that's what the FMLModType is called
(given that you can JiJ LIBRARY stuff, that you can use LIBRARY stuff from the game but not the other way around, and that most libraries that need to be on GAME will be aware of FML enough to specify GAMELIBRARY themselves but the reverse is not necessarily true)
Because jij is supposed to be used by mods
Anything in the plugin layer can not be touched by the game layer
And by design the game layer is the default layer for ml
So it goes there if nothing is specified
Which is what allows mods and their dependencies to work together
..huh? you mean the other way around?
access works fine top to bottom
default is GAMELIBRARY yeah
for jar in jar
for other locators you get an exception if you don't specify anything
I guess I don't see how treating JiJed stuff as LIBRARY by default would change this. Mods can use LIBRARY layer stuff just fine by default; however, if some mod JiJes a newer version of library X in its normal form, and some plugin layer tool JiJes it but transforms it to load on LIBRARY... the plugin layer thing won't be able to access it if it JiJes an out of date version!
Basically, what is the actual scenario where JiJing stuff as LIBRARY by default causes issues?
The only scenario I can think of is stuff that has to talk to mods or the game, not just be called by it - in which case it is aware of mods and FML and would either have a mods.toml (if it's a mod) or should specify the layer in its manifest
And yeah this is confusing for me too - plugin layer stuff can be touched by game layer stuff - or at least LIBRARY jars at any rate certainly can be!
isn't it also the case that by the time the mod/JiJ search is being done, the SERVICE/PLUGIN layer is already completely built and immutable?
at least i vaguely remember that being the case from when I was working on things, which is why I had to split my mod into a bunch of projects to ensure I could appropriately deal with the different module layers
Language providers can JiJ LIBRARY stuff just fine, and access the JiJed stuff, so I wouldn't think so
Because correct me if I'm wrong but it'd need to be on the plugin layer for a language provider to access it
(as in, GML itself is written in groovy)
I think I vaguely remember that language providers are loaded on the PLUGIN layer anyway
And we transform the groovy jar to turn the mod type to LIBRARY at present
Yeah that would make sense, but JiJ resolution only happens once, right?
So it's happening while that path can still be changed
Unless I've drastically misunderstood the system here which is definitely possible
i believe that JiJ resolution is done in the SERVICE layer
specifically, in MCML's TransformationServicesHandler::discoverServices, which loads the discovery services and adds them to the SERVICE layer
and it's then done again in the GAME layer
you mean PLUGIN?
So does JiJ discovery happen twice then? That seems like it'd lead to even more issues
I assumed it happened once before language providers and whatnot were loaded
Possibly, yeah
For reference, this issue isn't entirely theoretical. It means that language providers or any other thing at that layer have to be extremely careful what stuff they depend on, because anything they depend on is just waiting to explode if a mod also depends on it
here's the relevant code:
final var scanResults = this.transformationServicesHandler.initializeTransformationServices(this.argumentHandler, this.environment)
.stream().collect(Collectors.groupingBy(ITransformationService.Resource::target));
scanResults.getOrDefault(IModuleLayerManager.Layer.PLUGIN, List.of())
.stream()
.<SecureJar>mapMulti((resource, action) -> resource.resources().forEach(action))
.forEach(np->this.moduleLayerHandler.addToLayer(IModuleLayerManager.Layer.PLUGIN, np));
this.moduleLayerHandler.buildLayer(IModuleLayerManager.Layer.PLUGIN);
final var gameResults = this.transformationServicesHandler.triggerScanCompletion(this.moduleLayerHandler)
.stream().collect(Collectors.groupingBy(ITransformationService.Resource::target));
final var gameContents = Stream.of(scanResults, gameResults)
.flatMap(m -> m.getOrDefault(IModuleLayerManager.Layer.GAME, List.of()).stream())
.<SecureJar>mapMulti((resource, action) -> resource.resources().forEach(action))
.toList();
gameContents.forEach(j->this.moduleLayerHandler.addToLayer(IModuleLayerManager.Layer.GAME, j));
(Heck, I explicitly set the LIBRARY mod type in the artifacts of one of my projects, that isn't really MC specific, for this exact reason)
so scanResults is a Map<Layer, List<SecureJar>> which contains both PLUGIN and GAME entries
and this is done directly after the SERVICE layer is built
so anything that locates/builds SecureJar objects to be added to the PLUGIN or GAME layers is loaded in the SERVICE layer
Right, that makes sense to me
or optionally the BOOT layer if it's provided in the classpath/module path
The JiJ discovery let's both PLUGIN and GAME stuff be discovered then, as I thought (and as what I see in practice reflects)
which would suggest to me JarInJarDependencyLocator is in the SERVICE layer
Which means what I've said is still relevant - there's no reason that the default for JiJed stuff couldn't be LIBRARY
Uh while hacking away at NF coremods, this surely can't be needed anymore?
given that function name...
Okay, I figured it out; JiJ can discover PLUGIN layer jarfiles if the jar is already loaded in the BOOT/SERVICE layer
but mod jars are loaded after the scan has completed
which means that the PLUGIN layer has already been built
though uh, in ModValidator's ctor:
this.candidatePlugins = lst(modFiles.get(IModFile.Type.LANGPROVIDER));
this.candidatePlugins.addAll(lst(modFiles.get(IModFile.Type.LIBRARY)));
(candidatePlugins is the List<ModFile> that gets returned and turned into the scanResults map I mentioned earlier)
so from what I can tell, there should be nothing in the code that actually prevents LIBRARY type jars from being loaded by mod files
and those SHOULD be loaded as PLUGIN by ModLauncher
As for this, it's purely JarInJarDependencyLocator::getDefaultJarModType being set to GAMELIBRARY, since that's likely the best default for most users
given that most mods don't currently specify a FMLModType of MOD, they actually get defaulted to GAMELIBRARY
Right this works just fine now, that's not the issue. My complaint is that jars without anything are treated as GAMELIBRARY when it's saner to treat them as LIBRARY
I'm reasonably certain it special cases that in for stuff with a mods.toml and sets it to MOD
Because the normal discovery errors out on stuff without a mods.toml or FMLModType
Can we make JiJed libraries be LIBRARY instead of GAMELIBRARY by default in a future MC version? Us groovy folks now have an issue where we JiJ a library we use in our language provider as a LIBRARY, by adding an otherwise-absent FMLModType, but someone else JiJes it just normally and theirs is getting loaded instead of ours, and causing an incompatibility with a nasty looking module error. The only things that need to be GAMELIBRARY instead of LIBRARY will be things that reference MC or mod classes, and so already know that Minecraft exists and can define an FMLModType themselves. This would be a breaking change, so we'd have to make it in the next MC version. I can open a PR if folks agree that this is okay to do - this is no longer some theoretical issue though, we actively have an incompatibility with a mod due to it
No
This was discussed a million times now
There are way more users which use JiJ for GAMELIBRARY then LIBRARY
And we want to support that layer by default
However
I think we should support the injection of libraries into a specific layer
But that requires some modifications to the relevant systems to support
Can you give me an example of something that would be JiJed on GAMELIBRARY where the author wouldn't be aware enough of MC to give it a FMLModType?
Most libraries people use can be JiJed just fine on LIBRARY, and can still be used from game-level code
So for the majority of uses of JiJ this will have no effect
Those don't really exist, but we have as principal to keep the LIBRARY layer as small as possible, so if it is not needed then it should not be in there, is and will be the default way we implement this.
From that follows that the JIJ default layer will always be GAMELAYER, but I agree that it should be easy and trivial tell JiJ to load it in a different layer
Can you justify this principal, given that it's actively causing issues?
Seems kinda arbitrary
Speed
How would adding to LIBRARY slow stuff down more than adding to GAMELIBRARY
It is simply faster to lookup classes with as few layers as possible
In such a case, JiJ should also determine the layer to load a library in based on the "bottom-most" layer approach IMO
If two mods want to JiJ the same thing one in LIBRARY and one in GAMELIBRARY, LIBRARY should win
Yes
I agree that that should be the behaviour
But unless otherwise specified it should always be GAMELAYER
This is how FML has always done it
That runs into the issue of services
To allow for the most flexibilty and the lowest hops needed
Could you elaborate on that actually?
the services got fixed
Mod A and lang provider B JiJes library C, which loads service X. Mod B also JiJes library D which provides that service
If library C is moved to service because B wants it there, it won't find service X from D
Which mod A expects it to because with just mod A they're both on GAMELIBRARY
That's the issue
We always had the rules to not allow mixing of the layers
You can't do what silk proposed without running into this issue
Yeah and that is perfectly fine
Where mod A breaks when B is present
The design has this issue build in
If you load a library that is not FML Aware
That is always something you need to worry about
The same is for example with shadowing
It's trivially solved by moving it to LIBRARY by default
Isn't that reversed?
But we do not want to do that
Library layer is untransformed
But the point is there's nothing mod A can do about this
It's much faster to load it from *PLUGIN/SERVICE rather than GAME
Mod A will just randomly break
And again, by design we have untill now accepted this limitation
uhm i wouldn't use that as an argument given that gamelibrary classes get transformed
True
This wasn't a limitation at all before now - this only pops up with the proposed "use the lowest requested layer"
I see the point that if the .jar file doesn't declare anything at all and is no mod, why load it in GAME?
Whereas moving to LIBRARY doesn't have this issue at all, and I've yet to see a solid argument against it besides speed which is looking iffy
This is basically all I'm saying, yeah - it's far less risky to load it as a LIBRARY, and if it declares nothing at all that's likely where it should go
I get that you've accepted this limitation in the past. I'm saying you no longer should as there's now evidence of it causing unsolvable incompatibilities in production
Yet the problem is that such changes can have a lot of very unforeseen concequences
Just because it fixes your problem
Does not mean that it does not open pandoras box
FML is very hard to test
And it is simply safest option to use GAMELIBRARY
But I am reworking parts of FML anyway right now
We've shown that that's not the safest
It's just what's currently done
how does making something more restrictive open a pandora's box
It's inherently unsafe
this is completely backwards
Furthermore, the alternative proposed solution of loading stuff on the most restrictive requested layer has more potential issues than moving them to LIBRARY
The whole service thing
Which would cause breakages that would be even harder to diagnose than this one
Okey, but you also remove the ability to transform those libraries
Which people might have been doing
You also modified the way the existing libraries are loaded and processed
Because they are in a different layer by nature
Simply stating that you fix A and as such need solution B, does not mean that said solution B does not cause issue C which currently does not exist
I mean it is unlikely that issue C exist in this particular case
but it still needs to be put through testing
And I already agreed to do said testing
Far more unlikely than issue A which we know exists
And you've yet to propose an alternative solution that doesn't open up far more potential issues that are way more painful to figure out
I would have allowed you to specify the layer, and failed to load it if two mods want to load it in different layers
Same way you can have two different requested version ranges right now
And get a load failure that way
Because as far as I can telรถl
Even if I load library A with service spec B in the LIBRARY layer, that will still blow up if their is a mod that provides implementation C
So mods would have to actively declare which layer they want things on if the things use a service of any form
Because the library consumer of A which loads services B in the LIBRARY layer will never see the implementation C
That's not the issue
But it is.....
The issue is a library with an implementation in another library
It's all perfectly safe so long as both libraries are on the same level!
Obviously your example is unresolvable
But this one is! But not via declaring a correct layer for stuff...
Cause they don't need to be on that layer. They just have to be on the same layer as one another
So your argument is that if I have two libraries which are FML unaware, and one of them holds the service spec, and one of the impl, they should always be loade din the same layer correct?
Yes
That's what you'd want them to do
And you'd want that while mods might need one or the other as a LIBRARY
Because that's the current issue
And you can't rely on libraries declaring services they use, cause not every library is module aware beyond an automatic module name
Realistically does this happen?
Libraries using a service provided in another library? Yes
Hell, I actively maintain one such library. I declare an FMLModType in it even though it's not MC aware to avoid issues of this type by just locking in where it can show up to begin with
But services as a way to communicate between libraries is kinda the point of services
Currently it doesn't cause an issue because both load on GAMELIBRARY
If you allow one to get dragged higher because someone requests it on LIBRARY, you have an issue, as it wouldn't drag the other with it
As I said I will test it
This doesn't require testing to tell you it's an issue
Hell, you want an example of such a library? Jackson databind. Which. Yeah, Jackson libraries are the ones actively involved here so this would break in our specific case
Jackson databind, and other Jackson libraries, provide services used in Jackson core
GML JiJes some but not all Jackson libraries
Valkyrien Skies JiJes a different set of Jackson libraries
Boom, issues arise - currently, cause they get loaded as GAMELIBRARY when we need them as LIBRARY. With your proposed solution, you'd still have issues as core would be pulled up to LIBRARY but not things that provide services for it
Test what exactly? I've pointed out that this is an issue. We know it's an issue, either at present or with your proposed solution. That doesn't need tested. That's just how services work
Test your solution
Sorry if I seem impatient about this; I'm just rather annoyed that it took till this actually caused us one of those incompatibilities-that-arent-necessary-but-that-we-cant-fix that we were worried about for this to get taken seriously, which I suppose could be partially just the perception of the situation on my end
It really is
Because you are simply the first to bring it up
And in general I am not oposed to your ideas and solutions
I brought it up many times before this point and generally got ignored or brushed aside though
I am simply not as quick to accept them on facevalue
And want to get the time and should get the time to do my own investigation and test your ideas
That's fine. Can you not be dismissive of my ideas right off the bat then?
Well it is the actual first time I have an object case to work with. So it is the first time it got actually stuck on my radar
I first defend the current stance, which might seem dismissive, but you did not provide your examples from the get go
You asked for a change without providing the real reason or examples of what does not work
The fact that your first response to me bringing this up was literally "No" (#1187879036815417456 message) is telling
And I am not going to do work for free
So my first response to the question "Can you do X?" is always a blanked "No"
Cause you can easily make the PR yourself
And have me review it
I provided the example from the get go of what the current stance broken
It is a single line change after all
If your response is "no" when I bring it up here, I'm not making the PR. I've never expected you to do all the work here
Anyways, I'll drop this; probably not productive
That is correct. It does disable AT and Mixin into those libraries. Debatable whether that should be encouraged or not, but it's a real consequence.
With neo on it's own what's loaded as GAMELIBRARY? Do DFU and company go there? Cause as far as I'm aware you can't mixin/AT DFU
And if not, the name GAMELIBRARY is a bit misleading
it is a library that gets loaded into the GAME module layer
in that sense, GAMELIBRARY is quite sensible
and no, nothing is in GAMELIBRARY in the latest releases
Huh, alright, good to know
...wait hmm, does that mean LIBRARY stuff, or whatever that layer that gets that stuff is called, can reference and use DFU? I'm gonna have to abuse that
at the moment yes
(cause I am not 100% sure)
thing is, anything in GAMELIBRARY can use DFU as well ๐
I will be abusing this heavily. Get ready for BytecodeOps
...well, I'm still waiting on some sort of nicer transformer API I suppose before I go there
As a follow up to the FMLModType discussion, https://github.com/neoforged/FancyModLoader/pull/96
Are there cleanup tasks in FML that could use contributors? I would very much like to see #22 become a thing, and am wondering what the major blockers on this are at present
oh there's a billion blockers
Might be worth putting together some sort of roadmap (maybe a github project?) for FML, given the number of different things it has going on
Regardless - in terms of mod module support specifically, are we looking at major architechtural limitaitons or "this system has been around for 5 years, nobody knows what it does, and making this change requires changing it" limitations?
I think that an accurate view would be "this system has been around for 5 years, it needs to be cleaned up, and we don't want new extensions with unpredictable impact that might hinder the clean up"
That's fair. Is there work that needs to be done to clean those up that you could use help with?
One of the first steps is the removal of BootstrapLauncher. In theory we could just put everything on the module path
This requires a mixin update however - maybe it could be done now that we're using fabric's fork
Hmm. What's the issue with mixin at present? Something something service discovery?
It relies on a package version check that would fail is normal modular environments
I forgot the details
These package version checks need to be eradicated
Yes, implementation and specification version do not exist in JPMS
That they're still there is an enhancement made by SJH but that breaks as soon as you try to load things on the JVMs normal module path
We really need to port the changes over to fabric mixin that I made ๐ค (Well and fix the uses we have ourselves)
The version could be pulled from the module, in theory
Yes, that was one possible fix, but that does cause issues in dev of these projects
The far easier fix is probably the "old" way of including a version class in API to query it
I would once again like to request that EventBusSubscriber be moved into an outer class because I don't like how there are three levels of classes in one file and that Mod and EventBusSubscriber don't seem to be functionally similar, other than the fact that Mod also automatically subscribes to events. If people are not opposed to the idea I can open an issue.
EBS is part of FML Java specification
And not part of any other language spec
That.. doesn't change that it's nested under @Mod ?
Well it kind of does
Because @Mod is the FMLJava annotation
It ties them together
I know it is not really a "thick" connection
Or a good reason
But that is the reason why it is there right now
I don't see why the FMLJava spec must be contained within one class
Both classes should be moved to the javafmlmod package then because right now they are in common, which by your explanations doesn't make sense either
I agree and this already not the case from what I can tell as Mod ctors are allowed to accept an FMLModContainer, meaning that class is part of the spec (though why that behavior is allowed is also questionable as FMLModContainer has no additional functionality over ModContainer)
Could also just check both and delegate - like, if the module has a version use that, otherwise try and query the other one. But yeah a general version class in the API is probably the better bet
And yeah this is the proper solution - this is java. We can use packages for grouping, no need to shove it all in big mega-classes for no reason
Should I open an issue then?
so.. i tried something for locators https://github.com/Matyrobbrt/FancyModLoader/commit/2580401af01351fe00989a99937720af76afbc69
it will still benefit from an int-based priority system, and some logging but it's a start 
cc @glacial crag 
If we are already making such breaking changes
Then why not inject the mod file factory via the constructor?
Also I would extract the manifest parsing logic to somewhere else
That locating and manifest management are two different things
it's in a provider..? 
unless you mean moving manifestParser in which case w/e, another class seems pointless
Why did you make it public then?
it needs to be package, it's used in the jij locator and that class both of which are in the same pacjage
Either it is used in multiple locations
And something like a ManifestParser would make more sense
Then move it
maybe running the tests?
that or gradle
Lambda soup is tasty, especially with custom methods that are more descriptive than using function etc everywhere
๐ซ
ah, the case of the logs folder strikes again
If you call that lambda soup, you haven't seem my code, let me tell you
mmm checked exceptions
my favorite garbage feature
yeah not really "soup" there, mosr like a little snack
I can't share the entire class, but
No well, it's my code, I can
Now that is a lambda soup
not sure what to call this, ... lambda lasagna?
You still aren't nesting lambdas into lambdas
Look at ExpectationPredicate there lol
true, it's not so much stacked on top of each other as next to each other
Fun fact, this actually worked first try
I was thinking of a peice of code I wrote a bunch of years ago
that was written enterely using continuation-passing style
the code was horrible to debug
because "what comes next" was decided at runtime
Giga, are you on PC?
yes I am sitting in front of a windows PC and typing on my keyboard, why?
Can you give me a link to the file I sent? Discord on mobile doesn't want me to
Oof
I wouldn't like that at all...
It's a state machine, but worse
Thanks
that's what clicking on the donwload button gave me :P
Yeah, I can't do that on mobile
did discord change this? I still see it like this on my phone
I think the betas are running on a different branch from the mainline releases
and have different feature sets
(I use beta, not canary, not release)
Yes, but pressing the download button downloads
It doesn't open a page for it
So I cannot get the URL
OH
right, it opens in my Edge browser, with a download prompt, but I can't click on the url, and if I cancel it closes the download tab
I really like checked exceptions
installs Manifold solely for unchecked exceptions 
I get why checked exceptions exist, but they make the code far too annoying to write
They also cause a problem when you enter the world of functional programming because Javaโs functional APIs have practically no support for them
Ah, yet another reason I continually wish Java supported higher kinded types.
okay the logs/ files come from running the SPI tests with the log4j2.xml file
what is this
why is there a lambda that takes two lambdas and returns a third lambda
that's what I mean by "lambda soup"
from what I can tell the main goal of this refactor is to separate which JARs are found, and how to interpret JARs as mods
i am not a functional programming expert, but maybe that's the style?
It is
the style of what?
It is functional programming
composition
it's unreadable soup
Yep
Not really
Just to you
I have grown up with functional apis and it was basically after java the first thing they thought us in uni
So I am used to seeing this
And have apis structured like this
that doesn't make it any good
It actually does
functional programming has its uses, don't get me wrong
we learned composition patterns in school
the goal is readability, FP is just one technique to achieve that
Composition is a proven track record to be the most flexible of api designs
I don't care about a "flexible" API if it's an unmaintanable mess because of the lambda soups
(see FML)
IMO the main issue with FP in java is the lambda allocations (i think other languages handle it better)
but that's not FP's problem
This is just my opinion: if you do fp in java. You should use your own types
Not function<x,y>
it probably depends
It gets you better documentation options for one
And gets you better composition results
is there a performance benefit from avoiding the generic bouncer method or is that optimized away already
it was a general question
There is no performance benefit here
It is a purely architectural benefit
Composition has been proven to be the better oop architecture
But you can't really do composite oop in java, cause there is no real pplymorphism
But you can with lambdas
Because the concept of functional composition is defined differently but has the same outwards facing traits
Meanwhile Oracle's pushing DOP for modern Java 
well the problem here is that there's too many layers of indirection
Agreed, that pretty much sums up my personal opinion of modlauncher and fml in general
indeed
the thing is... sometimes you only locate JARs which you know how to interpret
(e.g. classpath locator)
maybe we should run all of the classpath jars through the mod providers then
and have a way to distinguish between "required" jars (i.e. a mod provider must process them) and "optional" jars (i.e. if nothing processes them then they just get skipped)
(naming is terrible of course)
that should be replaced by a securejar->iconfigurable function
no jar should be skipped
it should display a warning at least if no provider handles ign
we probably want #maintenance-talk message before the mod locator changes
(so go review my CoreMods PR
)
well except for classpath I'd say
That method up there is not good for various reasons. One being that using a generic Function interface makes it impossible to find implementors of it
So good luck trying to navigate that codebase for someone who isn't already familiar with it
I agree
I remember seeing a lot of streams and even though I prefer to never use them, they are not inherently unreadable
[Reference to](#modder-1โค20โค1-support message) #modder-1โค20โค1-support [โค ](#modder-1โค20โค1-support message)FML should probably throw in dev if it finds an invalid loader version decl though
ok so maty is still looking into the mod locators, and I have cleaned up mod loading stages
what's next 
saying WTF
because that's what the broken files code is making me scream
it's in current FML
doesn't seem useful, no
ew this is so fucked
that should also report fabric/forge mods as warnings
now @glacial crag you can fix the branch cause i don't want to deal with the spotless conflicts
sigh OK
I think you'll have to open a PR if you want me to push to your repo
there
Ok I'll give it a shot soonโข๏ธ
(I mean maty's mod locator rewrite here)
that's good
which PR?
The document
That's certainly "a name": JarModsDotTomlModProvider
@glacial crag Why are we even returning a Stream from scanCandidates?
Especially given that we call toList() on the return value at the only call-site... locator.scanCandidates().toList()
returning a stream is more convinent for locators
since they'd usually iterate a dir
Well in that case, we need to actually close those streams
I don't think terminal operations close streams automatically, so toList will leave the directory stream dangling
Also, only 1 out of 6 locators actually does a directory stream ๐
BTW; some of these locators. I think we discussed this in the past, have we seen actual usage of the MavenDirectory one?
any terminal operation should close them
ExplodedDirectoryLocator can be removed, it's superseded by MOD_CLASSES
the maven directory one is also suspicious
tbh I'd move the mod classes logic to explodeddir
instead of unintuitively being in mclocator
yeah but they need to be in mclocator for neoforgedev
JarContents.of would be nice for the simple case (new JarContentsBuilder().paths(p).build())
BTW while I am looking at it, the attributes for the generated minecraft mods toml are no longer correct:
mods.set("logoFile", "mcplogo.png");
mods.set("credits", "Mojang, deobfuscated by MCP");
mods.set("authors", "MCP: Searge,ProfMobius,IngisKahn,Fesh0r,ZeuX,R4wk,LexManos,Bspkrs");
mods.set("description", "Minecraft, decompiled and deobfuscated with MCP technology");
yeah, maty also requested that
we can do it
yeah that's super outdated...
The varargs method doesn't work as a method-reference for List.of(...).map(JarContents::of)
And it allows it to be called with zero args, which leads to a runtime error ๐
that's pretty sad
That's good, it'd hide an array alloc ๐
๐คท
and that's why we (Path path, Path... otherPaths)
What was fml.gameLayerLibraries used for again? when eventbus was still required to be ASM transformed, we had that in there, right?
Yes correct
yeet
pluginLayerLibraries can be removed too
Yes, yeeting

I am trying to also get rid of the locators inspecting legacyClassPath directly
I'll have to test my approach, though
Yeet MavenDirectoryLocator too?
yess
Okay, by what? We might wanna put that in a comment on that class
I can't find the option being used anywhere on github, period
lol
Wait that's wrong, there's a few old ones
...all commented out in the code for various launchers, it seems
So if it's used by anything I'm not finding it
@glacial crag no idea if it's worth it trying to clean up the use of initArguments / arguments in this cycle
I am half-way through replacing that with a LocatorContext and moving to type-safe keys (think TypeSafeMap) rather than a Map<String, ?>
The arguments are not used much, are they?
It's a weird system because of course it can only use arguments that FML defines already
It's used more as a way to transport info from the launch handlers and the core to locators
And they contain more info than you'd think
I don't know when you'd use arguments and when the FML Environment
But check here for example:
https://github.com/neoforged/FancyModLoader/blob/main/loader/src/main/java/net/neoforged/fml/loading/VersionInfo.java#L12
https://github.com/neoforged/FancyModLoader/blob/main/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ExplodedDirectoryLocator.java#L73
https://github.com/neoforged/FancyModLoader/blob/main/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/MavenDirectoryLocator.java#L37
Some are set here:
https://github.com/neoforged/FancyModLoader/blob/6a5abe8478f86eabcbd1b3acaafbac7ae6feb004/loader/src/main/java/net/neoforged/fml/loading/FMLServiceProvider.java#L70
Others here:
https://github.com/neoforged/FancyModLoader/blob/main/loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java#L105
maven and exploded dir locators can be yeet
Why are we meeting shit?
Meeting*
Yeeting*
Do these things hurt us?
No
Is there a use for them
Yes
Do we use it ourselves probably no
But up untill now i have seen no justification for yeeting locators!
Reduced maintenance burden?
Everyone who has to look at this code has to figure out first: "what does this do"
And if it's not used by anyone what exactly is the fucking point of spending that time?
Then document it
because no one used them
Are you sure?
Hence I asked you: what's the use case so I can document it
But we haven't actually found one ๐
between yes and yes: yes
That's not a guaranteed "no" maty ๐
They can and should be used by launchers that provide a central cache of mods. Using a single argument they can then launch the game with the mods selected without having to copy them
We provide a central implementation for a cache that is structured like a maven
mod filenames do not necessarily adhere to maven GAV format
Because that is we where asked for in the past
It is what was asked....
So we included it
Because it was trivial for us to do. It was a standardized format etc
So the locator was added
And just because you can not find shit on github does not mean it is not used. There are a ton of launchers which are not on github.....
We always communicated to launchers: Listen if you want to create a cache centrally were mods are found, and you have a specific format, come to us. We will find a good way to add it
Do we know if any launcher actually went ahead with a centralized mod repo?
Yeah it was used very much in the 1.12 to 1.14 days
We don't really communicate anything about FML anywhere though, there isn't even a readme for it
Even before that I think
Because all of that happened in the past via Discord / IRC even
The launcher people and lex/cpw came together, and hashed out what was needed
And then it was implemented / provided for them
In such a way that it was easy for us to maintain
And easy for them to use (aka one launch arg, or a launch file)
I am pretty sure there is/was also one that could read from a json file
And load files listed in it
not that I have seen
that would indeed be more useful than the list of GAVs though
Keeping the maven one or not barely matters, really. But keeping essentially dead code since we don't communicate what our external API is, sucks.
So, I'd then actually start writing a README that documents these options we consider public
including this maven one and how it's even used
This one is definitely dead though: ExplodedDirectoryLocator
It reads its list of exploded directories from an argument that no one sets
Yeah i think so
it think that was an old way of including stuff
Instead of from the CP
I actually kinda like the idea, honestly. But it's definitely defunct at the moment
NG could use it instead of MOD_CLASSES ๐
For the Mven/JsonLocator there is an actual obvious use
and pass CLI args instead of an env var
With difficulty.....
Since the data model is absolutly identical
Maybe
But in the future we likely don't need either
ModulePatcher supports directories natively
public record ExplodedMod(String modid, List<Path> paths) {}
So you can just yeet a set of directorise into a module
Look at this record. It models 1:1 what we put into MOD_CLASSES ๐
I have to read up on module patcher
Currently I am trying to untangle another mess: we read legacyClasspath too much to try and avoid double-loading jars
I'll see if I can replace that with a lookup that just checks if a path is already on one of the layers or their parents
I think we can yeet LCP in the future as well
I just hope patch-module is not as useless as the other JVM options
For us, it kind of is.
Because Patch-Module only works on the system / boot layer
Not on our custom layer
Yup that's what I thought
I mean ultimately we currently try to solve the problem of grouping a set of seemingly unrelated directories by "mod" they belong to
If we could solve that without additional info just based on the directories, we wouldn't need to pass MOD_CLASSES
The point is
We can extend the patch module system trivially
Because the underlying patcher now has an API
So we can read the patching information for our layer
From anywhere we want
Feed it to the patcher
And done
You still need to externally pass the info which directories belong together
Yeah but in the past the patcher was hardcoded to a single property
And not adaptable
It sucks that we have to compile that info a priori
that's the entire misery around modSources
There is no really connection, especially in the IDE, between the actual running instance, and gradle
And with the new patcher you don't need to compile it apriori at all
You just need to pass it a map
Well
Yeah
It's likely you could heuristically determine that a classes/resources directory belong together
That is an apriori
That's literally the same ๐
But you could implement the map interface
Just different format
You cannot compute it on the fly since the information just isn't there unless you apply heuristics
Yes
if you have two directories that the IDE puts on the classpath
But that is the problem which you will always have
i.e. myproject\build\classes and myproject\build\resources
Maybe
But as soon as you start having
project\mod\build\classes
project\mod\build\resources
project\common\build\classes
project\common\build\resources
But in reality it does not matter
we cannot really know that the user wants these four directories to go into a single module
Yeah
Gradle doesn't know either, to be frank
The user is likely configuring some shadowJar stuff to get a single jar out at the end
Yeah
So in reality an apriori compute is the best UX
It is a bit stupid for us to maintain
But the UX for the user is probably the best
worst case they can always request that we add it back
- remove thing that seems unused and is undocumented
- someone requests it
- we add it back with good documentation and a clear explanation of the use case
if nobody uses it we stay with 1. -> profit
if someone complains we end up with better code -> profit
Eh I don't care enough about the maven one. It's not terrible
Which is fucking tripple the work for us
no it's not - it's just copy/pasting code that we already had and adding documentation
I would generalise it over relative directory paths though
- it's not you that will do the work it's me ๐
all the dead code in FML makes it harder to understand what is really going on
Or at noen
can you link a launcher that uses it then at least?
You are literally yeeting stuff that is at the end of an entire code tree........
You are not reducing complexity with that
Just removing functionality
Let's not get hung up on that thing. Let's just document it and that we don't know any users and move on
And again there is 0 proof that it is dead
Well Orion it's passing cli arga through several layers.heh
Yeah that is bad, I agree, but right now that is the best infra we have
With unchecked casts and string keys
Because ModLauncher nor the Locators themselves have better infra for it
That stuff is all in FML actually
does (F)ML not have decent joptsimple infra to parse args with strong typing?
It does but passes it through the FML arguments map
we're cleaning things up - that's why we're having the discussion
I already have a lightweight typedmap style alternative...
To at least make this typesafe... Pr later ๐
wouldn't it make more sense to pass a context object that contains all the possible args?
ah yes good
that's more or less what I had in mind - the impl can easily be record-backed too
But it's still a map with typesafe keys underneath
Since you kinda need that to pass options to custom locators
btw I think that Lex removed MavenDirectoryLocator in MCF
Other question... What are your thoughts on getting rid of it entirely in favour of using FMLEnvironment
If he did I think we can too
https://github.com/MinecraftForge/MinecraftForge/commit/6f9f0f0cfacc74d62be39359d773d5dda220ad73#diff-459b28878dcf6d12fbf72d2987be9bdbbb0e2da780ce56d83358d63d1f1f41f7 removes it completely as far as I can tell
FMLEnvironment is a good idea
I think that laready has a type safe map
Okey then yeet it
right now you can get the dist from FMLEnvironment, from FMLLoader and probably a bunch of other places
we should consolidate all the context
you can also get it from ML's Environment using the neoforgespi Environment.Keys.DIST
Downside of FMLEnvironment is it's global nature
Why does ML have an Environment, that is what the fuck I am thinking about
But that is also an upside hehehe
Yeah the ML Environment and FMLs are easy to mix up
There is also an IEnvironment somewhere
But didn't we have one in spi too?
Environment is from SPI and can be deleted now that it only contains the dist
it's just a holder class
just keep FMLEnvironment, that's what we all use in our code :V
in MI I use FMLEnvironment apparently
FMLEnvironment.dist.isClient() / FMLEnvironment.dist == Dist.CLIENT is what we tell everyone to use for physical side stuff :P
so I would agree with that statement
FMLEnvironment.isClient() helper when? ๐
It's just a design question if we want to use this global to pass along cli args too hehehe.
Although they would not be exposed since these keys could be kept internal
For testing it would certainly be nicer to not use a global.
I guess you mean the cleaned args right?
Because I really would not like my access token to be exposed to a random mod.....
Allthough...
Unsure
I think you can already access it today if you really really really tried
you know that that's not how it works ๐
hmmm?
I thought this was limited to FML's arguments
There are various ways of getting the access token if you wanted to within the process
Yeah
But yes the args I was taking about are the parsed and cleaned args
I have some wild ideas for prototyping things for 1.21, but we should put a pin in what we want to finish for 1.20.5 first
My suggestion:
- Remove all deprecations from ML/SJH/FML/etc.
- Enable Java Core Mods (but keep the current system in parallel, maybe deprecate it?)
- Finish the locators but potentially just stop here
sounds good
deprecations in FML don't really matter - we already cleaned up many of them
Yes, as I said this would just be what we aim for for 1.20.5
Since we're already at pre1, we likely don't have much time for more
@glad cobalt Do you still think we should keep the maven locator if MCF removed it?
I am kinda neutral on the whole thing at this point, I might add
Maybe not. But the concept is right. we should talk to them to figure out how we can help them make such a central cache solution a reality
Yeah I can see value in the idea at the very least
I.e. other modding ecosystems like the Bethesda games struggle with similar issues and have developed virtual file systems to work around it (the nexus launcher does something along these lines, I think)
"them"?
Launchers
The..' what???
How large are their mods?
oh come on, we all know that's not going to happen :P
Jeez
these discussions turn into years long discussion and then more years before they're actually implemented if those discussions actually get somewhere
Looking at the hierarchy:
I removed the intermediate abstract class for jar handlers since it was already empty
BuiltinGameLibraryLocator is currently unused (fml.gameLayerLibraries is always empty)
I struggle to find a future use for this
There is not one anymore
Yeeting this too: mappingsOption = argumentBuilder.apply("mcpMappings", "MCP Mappings Channel and Version").withRequiredArg().ofType(String.class);
@chrome mortar Hm, given the current locator design, if there's an invalid zip-file in mods/ it just crashes completely?
Not that I tried, but I'd assume it does
I don't like it, but I also don't really see a way around it
public sealed interface IModFileCandidateLocatorResult {
record Success(JarContents contents) implements IModFileCandidateLocatorResult {
}
record Error(EarlyLoadingException.ExceptionData error) implements IModFileCandidateLocatorResult {
}
static IModFileCandidateLocatorResult of(JarContents contents) {
return new Success(contents);
}
}
the of should really take a path and try/catch it...
Yeah that is exactly what I also found out 5 minutes later ๐
static IModFileCandidateLocatorResult result(Path path) {
try {
return result(JarContents.of(path));
} catch (Exception e) {
}
}
static IModFileCandidateLocatorResult result(List<Path> paths) {
try {
return result(JarContents.of(paths));
} catch (Exception e) {
}
}
static IModFileCandidateLocatorResult result(JarContents contents) {
return new IModFileCandidateLocatorResult.Success(contents);
}
The question is what to catch I suppose
I have yet to decide
I'll write a few JUnit tests, testing this seems a nightmare
libsPath = Path.of(System.getProperty("libraryDirectory", "crazysnowmannonsense/cheezwhizz")); ๐ค
it me, cheesewhiz
FMLOnly artifacts currently don't exist as far as I know.
So this is never gonna work, right?
var fmlonly = LibraryFinder.findPathForMaven("net.neoforged.fml", "fmlonly", "", "universal", versionInfo.mcAndFmlVersion());
Note: our installer should already add the mods.toml for the minecraft jar directly into the jar
Probably not for 1.20.5

