4444import java .nio .file .Files ;
4545import java .nio .file .Path ;
4646import java .util .ArrayList ;
47+ import java .util .Collection ;
4748import java .util .Collections ;
49+ import java .util .HashMap ;
4850import java .util .List ;
51+ import java .util .Map ;
4952import java .util .Objects ;
50- import java .util .stream .Collectors ;
5153
5254/**
5355 * <p>A task transforming MultiMC Modpack Scheme to Official Launcher Scheme.
5456 * The transforming process contains 7 stage:
55- * General Setup, Load Components, Resolve Json-Patch, Build Artifact,
56- * Copy Embedded Files, Assemble Game, Download Game and Apply JAR mods.
57+ * <ul>
58+ * <li>General Setup</li>
59+ * <li>Load Components</li>
60+ * <li>Resolve Json-Patch</li>
61+ * <li>Build Artifact</li>
62+ * <li>Copy Embedded Files</li>
63+ * <li>Assemble Game</li>
64+ * <li>Download Game</li>
65+ * <li>Apply JAR mods</li>
66+ * </ul>
5767 * See codes below for detailed implementation.
5868 * </p>
5969 */
@@ -64,7 +74,6 @@ public final class MultiMCModpackInstallTask extends Task<MultiMCInstancePatch.R
6474 private final MultiMCInstanceConfiguration manifest ;
6575 private final String name ;
6676 private final DefaultGameRepository repository ;
67- private final List <Task <MultiMCInstancePatch >> patches = new ArrayList <>();
6877 private final List <Task <?>> dependents = new ArrayList <>();
6978 private final List <Task <?>> dependencies = new ArrayList <>();
7079 private final DefaultDependencyManager dependencyManager ;
@@ -125,29 +134,74 @@ public void preExecute() throws Exception {
125134 try (FileSystem fs = openModpack ()) {
126135 Path root = getRootPath (fs );
127136
137+ List <Task <MultiMCInstancePatch >> patches = new ArrayList <>();
128138 for (MultiMCManifest .MultiMCManifestComponent component : Objects .requireNonNull (
129139 Objects .requireNonNull (manifest .getMmcPack (), "mmc-pack.json" ).getComponents (), "components"
130140 )) {
131141 String componentID = Objects .requireNonNull (component .getUid (), "Component ID" );
132142 Path patchPath = root .resolve (String .format ("patches/%s.json" , componentID ));
133143
134- Task <String > task ;
135144 if (Files .exists (patchPath )) {
136145 if (!Files .isRegularFile (patchPath )) {
137146 throw new IllegalArgumentException ("Json-Patch isn't a file: " + componentID );
138147 }
139148
140- // TODO: Task.completed has unclear compatibility issue.
141- String text = FileUtils .readText (patchPath , StandardCharsets .UTF_8 );
142- task = Task .supplyAsync (() -> text );
149+ MultiMCInstancePatch patch = MultiMCInstancePatch .read (componentID , FileUtils .readText (patchPath , StandardCharsets .UTF_8 ));
150+ patches .add (Task .supplyAsync (() -> patch )); // TODO: Task.completed has unclear compatibility issue.
143151 } else {
144- task = new GetTask (MultiMCComponents .getMetaURL (componentID , component .getVersion ()));
152+ patches .add (
153+ new GetTask (MultiMCComponents .getMetaURL (componentID , component .getVersion ()))
154+ .thenApplyAsync (s -> MultiMCInstancePatch .read (componentID , s ))
155+ );
145156 }
157+ }
158+ dependents .add (new MMCInstancePatchesAssembleTask (patches ));
159+ }
160+ }
161+
162+ private static final class MMCInstancePatchesAssembleTask extends Task <List <MultiMCInstancePatch >> {
163+ private final List <Task <MultiMCInstancePatch >> patches ;
164+
165+ public MMCInstancePatchesAssembleTask (List <Task <MultiMCInstancePatch >> patches ) {
166+ this .patches = patches ;
167+ }
168+
169+ @ Override
170+ public Collection <? extends Task <?>> getDependents () {
171+ return patches ;
172+ }
173+
174+ @ Override
175+ public void execute () throws Exception {
176+ Map <String , MultiMCInstancePatch > existed = new HashMap <>();
177+ for (Task <MultiMCInstancePatch > patch : patches ) {
178+ MultiMCInstancePatch result = patch .getResult ();
146179
147- Task <MultiMCInstancePatch > task2 = task .thenApplyAsync (s -> MultiMCInstancePatch .read (componentID , s ));
148- patches .add (task2 );
149- dependents .add (task2 );
180+ existed .put (result .getID (), result );
150181 }
182+
183+ checking :
184+ while (true ) {
185+ for (MultiMCInstancePatch patch : existed .values ()) {
186+ for (MultiMCManifest .MultiMCManifestCachedRequires require : patch .getRequires ()) {
187+ String componentID = require .getID ();
188+ if (!existed .containsKey (componentID )) {
189+ Task <MultiMCInstancePatch > task = new GetTask (MultiMCComponents .getMetaURL (
190+ componentID , Lang .requireNonNullElse (require .getEqualsVersion (), require .getSuggests ())
191+ )).thenApplyAsync (s -> MultiMCInstancePatch .read (componentID , s ));
192+ task .run ();
193+
194+ MultiMCInstancePatch result = Objects .requireNonNull (task .getResult ());
195+ existed .put (result .getID (), result );
196+ continue checking ;
197+ }
198+ }
199+ }
200+
201+ break ;
202+ }
203+
204+ setResult (new ArrayList <>(existed .values ()));
151205 }
152206 }
153207
@@ -160,10 +214,15 @@ public List<Task<?>> getDependents() {
160214 @ Override
161215 public void execute () throws Exception {
162216 // Stage #3: Build Json-Patch artifact.
163- MultiMCInstancePatch .ResolvedInstance artifact = MultiMCInstancePatch .resolveArtifact (patches .stream ()
164- .map (value -> Objects .requireNonNull (value .getResult (), "MultiMCInstancePatch" ))
165- .collect (Collectors .toList ()), name
166- );
217+ MultiMCInstancePatch .ResolvedInstance artifact = null ;
218+ for (int i = dependents .size () - 1 ; i >= 0 ; i --) {
219+ Task <?> task = dependents .get (i );
220+ if (task instanceof MMCInstancePatchesAssembleTask ) {
221+ artifact = MultiMCInstancePatch .resolveArtifact (((MMCInstancePatchesAssembleTask ) task ).getResult (), name );
222+ break ;
223+ }
224+ }
225+ Objects .requireNonNull (artifact , "artifact" );
167226
168227 // Stage #4: Copy embedded files.
169228 try (FileSystem fs = openModpack ()) {
0 commit comments