88import net .minecraftforge .mcmaven .impl .data .GradleModule ;
99import net .minecraftforge .mcmaven .impl .mappings .Mappings ;
1010import net .minecraftforge .mcmaven .impl .repo .Repo ;
11+ import net .minecraftforge .mcmaven .impl .repo .Repo .PendingArtifact ;
1112import net .minecraftforge .mcmaven .impl .repo .forge .FGVersion ;
1213import net .minecraftforge .mcmaven .impl .repo .forge .ForgeRepo ;
14+ import net .minecraftforge .mcmaven .impl .repo .mcpconfig .MCP ;
1315import net .minecraftforge .mcmaven .impl .repo .mcpconfig .MCPConfigRepo ;
16+ import net .minecraftforge .mcmaven .impl .repo .mcpconfig .MinecraftTasks ;
1417import net .minecraftforge .mcmaven .impl .util .Artifact ;
1518import net .minecraftforge .mcmaven .impl .util .ComparableVersion ;
1619import net .minecraftforge .mcmaven .impl .util .Constants ;
1720import net .minecraftforge .mcmaven .impl .util .POMBuilder ;
18- import net .minecraftforge .mcmaven .impl .util .Util ;
21+ import net .minecraftforge .mcmaven .impl .util .ProcessUtils ;
22+ import net .minecraftforge .srgutils .MinecraftVersion ;
1923import net .minecraftforge .util .data .json .JsonData ;
2024import net .minecraftforge .util .file .FileUtils ;
2125import net .minecraftforge .util .hash .HashStore ;
3034import java .nio .charset .StandardCharsets ;
3135import java .util .ArrayList ;
3236import java .util .Arrays ;
37+ import java .util .Collections ;
3338import java .util .HashMap ;
3439import java .util .HashSet ;
3540import java .util .List ;
3641import java .util .Map ;
42+ import java .util .Set ;
3743
3844import javax .xml .parsers .DocumentBuilderFactory ;
3945import javax .xml .parsers .ParserConfigurationException ;
@@ -57,13 +63,17 @@ public record MinecraftMaven(
5763 Mappings mappings ,
5864 Map <String , String > foreignRepositories ,
5965 boolean globalAuxiliaryVariants ,
60- boolean disableGradle
66+ boolean disableGradle ,
67+ boolean stubJars ,
68+ Set <String > mcpConfigVersions
6169) {
62- private static final ComparableVersion MIN_SUPPORTED_FORGE = new ComparableVersion ("1.14.4" ); // Only 1.14.4+ has official mappings, we can support more when we add more mappings
70+ // Only 1.14.4+ has official mappings, we can support more when we add more mappings
71+ private static final MinecraftVersion MIN_OFFICIAL_MAPPINGS = MinecraftVersion .from ("1.14.4" );
72+ private static final ComparableVersion MIN_SUPPORTED_FORGE = new ComparableVersion ("1.14.4" );
6373
6474 public MinecraftMaven (File output , boolean dependenciesOnly , File cacheRoot , File jdkCacheRoot , Mappings mappings ,
65- Map <String , String > foreignRepositories , boolean globalAuxiliaryVariants , boolean disableGradle ) {
66- this (output , dependenciesOnly , new Cache (cacheRoot , jdkCacheRoot , foreignRepositories ), mappings , foreignRepositories , globalAuxiliaryVariants , disableGradle );
75+ Map <String , String > foreignRepositories , boolean globalAuxiliaryVariants , boolean disableGradle , boolean stubJars ) {
76+ this (output , dependenciesOnly , new Cache (cacheRoot , jdkCacheRoot , foreignRepositories ), mappings , foreignRepositories , globalAuxiliaryVariants , disableGradle , stubJars , new HashSet <>() );
6777 }
6878
6979 public MinecraftMaven {
@@ -78,6 +88,7 @@ public MinecraftMaven(File output, boolean dependenciesOnly, File cacheRoot, Fil
7888 LOGGER .info (" Foreign Repos: [" + String .join (", " , foreignRepositories .values ()) + ']' );
7989 LOGGER .info (" GradleVariantHack: " + globalAuxiliaryVariants );
8090 LOGGER .info (" Disable Gradle: " + disableGradle );
91+ LOGGER .info (" Stub Jars: " + stubJars );
8192 LOGGER .info ();
8293 }
8394
@@ -86,49 +97,118 @@ public void run(Artifact artifact) {
8697 var version = artifact .getVersion ();
8798 LOGGER .info ("Processing Minecraft dependency: %s:%s" .formatted (module , version ));
8899 var mcprepo = new MCPConfigRepo (this .cache , dependenciesOnly );
89-
90100 if (Constants .FORGE_GROUP .equals (artifact .getGroup ()) && Constants .FORGE_NAME .equals (artifact .getName ())) {
91- if (dependenciesOnly )
92- throw new IllegalArgumentException ("ForgeRepo doesn't currently support dependenciesOnly" );
93-
94101 var repo = new ForgeRepo (this .cache , mcprepo );
95- if (artifact .getVersion () == null )
96- throw new IllegalArgumentException ("No version specified for Forge" );
97-
98- if ("all" .equals (version )) {
99- var versions = this .cache .maven ().getVersions (artifact );
100- var mappingCache = new HashMap <String , Mappings >();
101- for (var ver : versions .reversed ()) {
102- var cver = new ComparableVersion (ver );
103- if (cver .compareTo (MIN_SUPPORTED_FORGE ) < 0 )
104- continue ;
102+ createForge (artifact , mcprepo , repo );
103+ } else if (Constants .MC_GROUP .equals (artifact .getGroup ())) {
104+ createMinecraft (artifact , mcprepo );
105+ } else {
106+ throw new IllegalArgumentException ("Artifact '%s' is currently Unsupported. Will add later" .formatted (module ));
107+ }
108+ }
109+
110+ protected void createForge (Artifact artifact , MCPConfigRepo mcprepo , ForgeRepo repo ) {
111+ if (dependenciesOnly )
112+ throw new IllegalArgumentException ("ForgeRepo doesn't currently support dependenciesOnly" );
113+
114+ var version = artifact .getVersion ();
115+ if (version == null )
116+ throw new IllegalArgumentException ("No version specified for Forge" );
117+
118+ if ("all" .equals (version )) {
119+ var versions = this .cache .maven ().getVersions (artifact );
120+ var mappingCache = new HashMap <String , Mappings >();
121+ for (var ver : versions .reversed ()) {
122+ var cver = new ComparableVersion (ver );
123+ if (cver .compareTo (MIN_SUPPORTED_FORGE ) < 0 )
124+ continue ;
125+
126+ var fg = FGVersion .fromForge (ver );
127+ if (fg == null || fg .ordinal () < FGVersion .v3 .ordinal ()) // Unsupported
128+ continue ;
129+
130+ var mappings = mappingCache .computeIfAbsent (forgeToMcVersion (ver ), this .mappings ::withMCVersion );
131+ var art = artifact .withVersion (ver );
132+ var artifacts = repo .process (art , mappings );
133+ finalize (art , mappings , artifacts );
134+ }
135+ } else {
136+ var mappings = this .mappings .withMCVersion (forgeToMcVersion (version ));
137+ var artifacts = repo .process (artifact , mappings );
138+ finalize (artifact , mappings , artifacts );
139+ }
140+ }
105141
106- var fg = FGVersion .fromForge (ver );
107- if (fg == null || fg .ordinal () < FGVersion .v3 .ordinal ()) // Unsupported
142+ protected void createMinecraft (Artifact artifact , MCPConfigRepo mcprepo ) {
143+ if (artifact .getVersion () == null )
144+ throw new IllegalArgumentException ("No version specified for MCPConfig" );
145+
146+ var version = artifact .getVersion ();
147+ if (version == null )
148+ throw new IllegalArgumentException ("No version specified for Forge" );
149+
150+ if ("all" .equals (version )) {
151+ var manifestFile = mcprepo .getLauncherManifestTask ().execute ();
152+ var manifest = JsonData .launcherManifest (manifestFile );
153+ for (var ver : manifest .versions ) {
154+
155+ try {
156+ var cver = MinecraftVersion .from (ver .id );
157+ if (cver .compareTo (MIN_OFFICIAL_MAPPINGS ) < 0 )
108158 continue ;
159+ } catch (IllegalArgumentException e ) {
160+ // Invalid/unknown version, so skip.
161+ continue ;
162+ }
109163
110- var mappings = mappingCache .computeIfAbsent (forgeToMcVersion (ver ), this .mappings ()::withMCVersion );
111- var art = artifact .withVersion (ver );
112- var artifacts = repo .process (art , mappings );
113- finalize (art , mappings , artifacts );
164+ var versioned = artifact .withVersion (ver .id );
165+ // If there is no MCPConfig, then we just produce a official named jar
166+ List <PendingArtifact > artifacts = null ;
167+ if (hasMcp (mcprepo , ver .id ))
168+ artifacts = mcprepo .process (versioned , mappings .withMCVersion (ver .id ));
169+ else if (mappings .channel ().equals ("official" ) && hasOfficialMappings (mcprepo , ver .id ))
170+ artifacts = mcprepo .processWithoutMcp (versioned , mappings .withMCVersion (ver .id ));
171+ else {
172+ LOGGER .info ("Skipping " + versioned + " no mcp config" );
173+ continue ;
114174 }
115- } else {
116- var mappings = this .mappings ().withMCVersion (forgeToMcVersion (version ));
117- var artifacts = repo .process (artifact , mappings );
118175 finalize (artifact , mappings , artifacts );
119176 }
120- } else if (Constants .MC_GROUP .equals (artifact .getGroup ())) {
121- if (artifact .getVersion () == null )
122- throw new IllegalArgumentException ("No version specified for MCPConfig" );
177+ } else {
178+ var mcVersion = mcpToMcVersion (version );
179+ var mappings = this .mappings .withMCVersion (mcVersion );
180+
181+ List <PendingArtifact > artifacts = null ;
182+ if (hasMcp (mcprepo , version ))
183+ artifacts = mcprepo .process (artifact , mappings );
184+ else if (mappings .channel ().equals ("official" ) && hasOfficialMappings (mcprepo , mcVersion ))
185+ artifacts = mcprepo .processWithoutMcp (artifact , mappings );
186+ else
187+ throw new IllegalStateException ("Can not process " + artifact + " as it does not have a MCPConfig ror official mappings" );
123188
124- var mappings = this .mappings ().withMCVersion (mcpToMcVersion (version ));
125- var artifacts = mcprepo .process (artifact , mappings );
126189 finalize (artifact , mappings , artifacts );
127- } else {
128- throw new IllegalArgumentException ("Artifact '%s' is currently Unsupported. Will add later" .formatted (module ));
129190 }
130191 }
131192
193+ // This is ugly, but there really isn't a good way to check if a file exists. DownlodUtils could probably use a 'exists' that HEAD's and returns false non 404
194+ private boolean hasMcp (MCPConfigRepo repo , String version ) {
195+ if (this .mcpConfigVersions .isEmpty ()) {
196+ var versions = repo .getCache ().maven ().getVersions (MCP .artifact ("1.21.11" ));
197+ this .mcpConfigVersions .addAll (versions );
198+ }
199+ return this .mcpConfigVersions .contains (version );
200+ }
201+
202+ // No official mappings, we can't do anything
203+ private static boolean hasOfficialMappings (MCPConfigRepo repo , String version ) {
204+ var tasks = repo .getMCTasks (version );
205+ var versionF = tasks .versionJson .execute ();
206+ var json = JsonData .minecraftVersion (versionF );
207+
208+ return json .getDownload (MinecraftTasks .Files .CLIENT_MAPPINGS .key ) != null ||
209+ json .getDownload (MinecraftTasks .Files .SERVER_MAPPINGS .key ) != null ;
210+ }
211+
132212 private static String forgeToMcVersion (String version ) {
133213 // Save for a few april-fools versions, Minecraft doesn't use _ in their version names.
134214 // So when Forge needs to reference a version of Minecraft that uses - in the name, it replaces
@@ -151,7 +231,7 @@ public static String mcpToMcVersion(String version) {
151231 return version .substring (0 , idx );
152232 }
153233
154- private void finalize (Artifact module , Mappings mappings , List <Repo .PendingArtifact > artifacts ) {
234+ protected void finalize (Artifact module , Mappings mappings , List <Repo .PendingArtifact > artifacts ) {
155235 var variants = new HashSet <Artifact >();
156236 for (var pending : artifacts ) {
157237 if (pending == null )
@@ -161,6 +241,13 @@ private void finalize(Artifact module, Mappings mappings, List<Repo.PendingArtif
161241 // Simplest case would be different mapping channels.
162242 // I haven't added an opt-in for making artifacts that use mappings, so just assume any artifact with variants
163243 var artifact = pending .artifact ();
244+
245+ if (stubJars && "jar" .equals (artifact .getExtension ())) {
246+ // No sources allowed in stub repos
247+ if ("sources" .equals (artifact .getClassifier ()))
248+ continue ;
249+ }
250+
164251 String suffix = null ;
165252 if (!disableGradle && pending .variants () != null && !mappings .isPrimary ()) {
166253 // If we are not the primary mapping, but we haven't generated the primary mapping yet, do so.
@@ -214,6 +301,11 @@ private void finalize(Artifact module, Mappings mappings, List<Repo.PendingArtif
214301 }
215302
216303 private void updateFile (File target , File source , Artifact artifact ) {
304+ if (stubJars && "jar" .equals (artifact .getExtension ())) {
305+ writeStub (target , source , artifact );
306+ return ;
307+ }
308+
217309 var cache = HashStore .fromFile (target )
218310 .add ("source" , source );
219311
@@ -228,7 +320,6 @@ private void updateFile(File target, File source, Artifact artifact) {
228320 }
229321
230322 if (write ) {
231- // TODO: [MCMavenizer] Add --api argument to turn class artifacts to api-only targets for a public repo
232323 try {
233324 if (disableGradle && isPom ) {
234325 makeNonGradlePom (source , target );
@@ -243,6 +334,37 @@ private void updateFile(File target, File source, Artifact artifact) {
243334 }
244335 }
245336
337+ private void writeStub (File target , File source , Artifact artifact ) {
338+ var tool = this .cache .maven ().download (Constants .STUBIFY );
339+ var cache = HashStore .fromFile (target )
340+ .add ("tool" , tool )
341+ .add ("source" , source );
342+
343+ if (target .exists () && cache .isSame ())
344+ return ;
345+
346+ File jdk ;
347+ try {
348+ jdk = this .cache .jdks ().get (Constants .STUBIFY_JAVA_VERSION );
349+ } catch (Exception e ) {
350+ throw new IllegalStateException ("Failed to find JDK for version " + Constants .STUBIFY_JAVA_VERSION , e );
351+ }
352+
353+ var log = new File (source .getAbsolutePath () + ".stubify.log" );
354+ var ret = ProcessUtils .runJar (jdk , source .getParentFile (), log , tool , Collections .emptyList (),
355+ List .of ("--input" , source .getAbsolutePath (), "--output" , target .getAbsolutePath ())
356+ );
357+ if (ret .exitCode != 0 )
358+ throw new IllegalStateException ("Failed to stubify jar file (exit code " + ret .exitCode + "), See log: " + log .getAbsolutePath ());
359+
360+ try {
361+ cache .save ();
362+ HashUtils .updateHash (target );
363+ } catch (Throwable t ) {
364+ throw new RuntimeException ("Failed to generate artifact: %s" .formatted (artifact ), t );
365+ }
366+ }
367+
246368 private void updateVariants (Artifact artifact ) {
247369 var root = new File (this .output , artifact .getFolder ());
248370 var inputs = new ArrayList <File >();
0 commit comments