diff --git a/README.md b/README.md index b6f541e5..199b5051 100644 --- a/README.md +++ b/README.md @@ -117,10 +117,12 @@ Download a file ### install-curseforge ``` -Usage: mc-image-helper install-curseforge [-h] [--file-id=] - [--filename-matcher=STR] [--modpack-page-url=URL] - [--output-directory=DIR] [--results-file=FILE] [--slug=] - [--exclude-mods=PROJECT_ID[Whitespace or commasPROJECT_ID...]]... +Usage: mc-image-helper install-curseforge [-h] [--force-synchronize] + [--file-id=] [--filename-matcher=STR] [--modpack-page-url=URL] + [--output-directory=DIR] [--parallel-downloads=] + [--results-file=FILE] [--slug=] [--exclude-mods=PROJECT_ID + [Whitespace or commasPROJECT_ID...]]... [--force-include-mods=PROJECT_ID + [Whitespace or commasPROJECT_ID...]]... --exclude-mods=PROJECT_ID[Whitespace or commasPROJECT_ID...] For mods that need to be excluded from server deployments, such as those that don't label as @@ -128,6 +130,10 @@ Usage: mc-image-helper install-curseforge [-h] [--file-id=] --file-id= --filename-matcher=STR Substring to select specific modpack filename + --force-include-mods=PROJECT_ID[Whitespace or commasPROJECT_ID...] + Some mods incorrectly declare client-only support, + but still need to be included in a server deploy + --force-synchronize -h, --help --modpack-page-url=URL URL of a modpack page such as https://www. @@ -138,6 +144,8 @@ Usage: mc-image-helper install-curseforge [-h] [--file-id=] 0 --output-directory=DIR + --parallel-downloads= + Default: 4 --results-file=FILE A key=value file suitable for scripted environment variables. Currently includes SERVER: the entry point jar or script diff --git a/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java b/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java index cef41302..5ba712e7 100644 --- a/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java +++ b/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java @@ -59,7 +59,15 @@ public class CurseForgeInstaller { @Setter private boolean forceSynchronize; - public void install(String slug, String fileMatcher, Integer fileId, Set excludedModIds) throws IOException { + @Getter + @Setter + private Set forceIncludeMods = Collections.emptySet(); + + @Getter + @Setter + private Set excludedModIds = Collections.emptySet(); + + public void install(String slug, String fileMatcher, Integer fileId) throws IOException { requireNonNull(outputDir, "outputDir is required"); requireNonNull(slug, "slug is required"); @@ -79,16 +87,13 @@ else if (searchResponse.getData().size() > 1) { throw new GenericException("More than one mod found with slug={}" + slug); } else { - processMod(preparedFetch, uriBuilder, searchResponse.getData().get(0), fileId, fileMatcher, - excludedModIds != null ? excludedModIds : Collections.emptySet() - ); + processMod(preparedFetch, uriBuilder, searchResponse.getData().get(0), fileId, fileMatcher); } } } private void processMod(SharedFetch preparedFetch, UriBuilder uriBuilder, CurseForgeMod mod, Integer fileId, - String fileMatcher, - Set excludedModIds + String fileMatcher ) throws IOException { @@ -123,8 +128,7 @@ else if (Manifests.allFilesPresent(outputDir, manifest)) { log.info("Processing modpack {} @ {}:{}", modFile.getDisplayName(), modFile.getModId(), modFile.getId()); final List installedFiles = processModpackFile(preparedFetch, uriBuilder, - normalizeDownloadUrl(modFile.getDownloadUrl()), - excludedModIds + normalizeDownloadUrl(modFile.getDownloadUrl()) ); final CurseForgeManifest newManifest = CurseForgeManifest.builder() @@ -176,8 +180,7 @@ private static URI normalizeDownloadUrl(String downloadUrl) { ); } - private List processModpackFile(SharedFetch preparedFetch, UriBuilder uriBuilder, URI downloadUrl, - Set excludedModIds + private List processModpackFile(SharedFetch preparedFetch, UriBuilder uriBuilder, URI downloadUrl ) throws IOException { final Path downloaded = Files.createTempFile("curseforge-modpack", "zip"); @@ -257,7 +260,7 @@ private Mono downloadModFile(SharedFetch preparedFetch, UriBuilder uriBuil file.getFileName(), projectID, fileID ); - if (!isServerMod(file)) { + if (!forceIncludeMods.contains(projectID) && !isServerMod(file)) { log.debug("Skipping {} since it is a client mod", file.getFileName()); return Mono.empty(); } diff --git a/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java b/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java index cebed67c..d8145cc2 100644 --- a/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java +++ b/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java @@ -1,6 +1,7 @@ package me.itzg.helpers.curseforge; import java.nio.file.Path; +import java.util.Collections; import java.util.Set; import java.util.concurrent.Callable; import java.util.regex.Matcher; @@ -39,6 +40,12 @@ public class InstallCurseForgeCommand implements Callable { ) Set excludedModIds; + @Option(names = "--force-include-mods", paramLabel = "PROJECT_ID", + split = "\\s+|,", splitSynopsisLabel = "Whitespace or commas", + description = "Some mods incorrectly declare client-only support, but still need to be included in a server deploy" + ) + Set forceIncludeMods; + @Option(names = "--filename-matcher", paramLabel = "STR", description = "Substring to select specific modpack filename") String filenameMatcher; @@ -80,10 +87,16 @@ public Integer call() throws Exception { } final CurseForgeInstaller installer = new CurseForgeInstaller(outputDirectory, resultsFile) + .setExcludedModIds(nonNullSet(excludedModIds)) + .setForceIncludeMods(nonNullSet(forceIncludeMods)) .setForceSynchronize(forceSynchronize) .setParallelism(parallelDownloads); - installer.install(slug, filenameMatcher, fileId, excludedModIds); + installer.install(slug, filenameMatcher, fileId); return ExitCode.OK; } + + private static Set nonNullSet(Set in) { + return in != null ? in : Collections.emptySet(); + } } diff --git a/src/test/java/me/itzg/helpers/curseforge/CurseForgeInstallerTest.java b/src/test/java/me/itzg/helpers/curseforge/CurseForgeInstallerTest.java index c9ee9d67..fb67407a 100644 --- a/src/test/java/me/itzg/helpers/curseforge/CurseForgeInstallerTest.java +++ b/src/test/java/me/itzg/helpers/curseforge/CurseForgeInstallerTest.java @@ -50,7 +50,7 @@ void testManual() throws IOException { final Path resultsFile = tempDir.resolve(".results.env"); final CurseForgeInstaller installer = new CurseForgeInstaller(tempDir, resultsFile); - installer.install("all-the-mods-8", "1.0.4", null, null); + installer.install("all-the-mods-8", "1.0.4", null); assertThat(tempDir) .isNotEmptyDirectory();