From 61f92b771db5cacd3eed49a3bc6583d09ba5001a Mon Sep 17 00:00:00 2001 From: FlowArg Date: Wed, 1 Sep 2021 17:05:12 +0200 Subject: [PATCH] Fixes, refactor and optimizations Removed all plugin dependencies Merged plugins in the base flowupdater project Plugins renamed to integrations Modpack's mods fetch now asynchronous Improved asset download by using cached thread pool executor Removed plugin exceptions Added FlowUpdaterException --- CurseForgePlugin/build.gradle | 64 ------ .../CurseForgePluginException.java | 21 -- OptifinePlugin/build.gradle | 63 ------ .../optifineplugin/OptiFinePlugin.java | 186 ---------------- .../OptiFinePluginException.java | 21 -- build.gradle | 5 - settings.gradle | 3 +- .../fr/flowarg/flowupdater/FlowUpdater.java | 36 ++-- .../flowupdater/download/DownloadList.java | 18 +- .../download/ICurseFeaturesUser.java | 3 +- .../download/VanillaDownloader.java | 54 +++-- .../download/json/CurseFileInfo.java | 17 ++ .../flowupdater/download/json/MCP.java | 4 +- .../CurseForgeIntegration.java | 198 ++++++------------ .../curseforgeplugin/CurseMod.java | 2 +- .../curseforgeplugin/CurseModPack.java | 2 +- .../optifineplugin/OptiFine.java | 5 +- .../optifineplugin/OptiFineIntegration.java | 151 +++++++++++++ .../utils/FallbackPluginManager.java | 36 ---- .../utils/FlowUpdaterException.java | 25 +++ .../flowupdater/utils/IntegrationManager.java | 124 +++++++++++ .../flowupdater/utils/ModFileDeleter.java | 47 ++--- .../flowupdater/utils/PluginManager.java | 172 --------------- .../flowupdater/utils/UpdaterOptions.java | 65 +----- .../utils/builderapi/BuilderArgument.java | 2 +- .../versions/AbstractForgeVersion.java | 57 +++-- .../flowupdater/versions/FabricVersion.java | 20 +- .../versions/IModLoaderVersion.java | 14 +- 28 files changed, 500 insertions(+), 915 deletions(-) delete mode 100644 CurseForgePlugin/build.gradle delete mode 100644 CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseForgePluginException.java delete mode 100644 OptifinePlugin/build.gradle delete mode 100644 OptifinePlugin/src/main/java/fr/antoineok/flowupdater/optifineplugin/OptiFinePlugin.java delete mode 100644 OptifinePlugin/src/main/java/fr/antoineok/flowupdater/optifineplugin/OptiFinePluginException.java rename CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseForgePlugin.java => src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseForgeIntegration.java (61%) rename {CurseForgePlugin/src/main/java/fr/flowarg/flowupdater => src/main/java/fr/flowarg/flowupdater/integrations}/curseforgeplugin/CurseMod.java (91%) rename {CurseForgePlugin/src/main/java/fr/flowarg/flowupdater => src/main/java/fr/flowarg/flowupdater/integrations}/curseforgeplugin/CurseModPack.java (95%) rename {OptifinePlugin/src/main/java/fr/antoineok/flowupdater => src/main/java/fr/flowarg/flowupdater/integrations}/optifineplugin/OptiFine.java (71%) create mode 100644 src/main/java/fr/flowarg/flowupdater/integrations/optifineplugin/OptiFineIntegration.java delete mode 100644 src/main/java/fr/flowarg/flowupdater/utils/FallbackPluginManager.java create mode 100644 src/main/java/fr/flowarg/flowupdater/utils/FlowUpdaterException.java create mode 100644 src/main/java/fr/flowarg/flowupdater/utils/IntegrationManager.java delete mode 100644 src/main/java/fr/flowarg/flowupdater/utils/PluginManager.java diff --git a/CurseForgePlugin/build.gradle b/CurseForgePlugin/build.gradle deleted file mode 100644 index a93f915c..00000000 --- a/CurseForgePlugin/build.gradle +++ /dev/null @@ -1,64 +0,0 @@ -archivesBaseName = "flowupdater-curseforgeplugin" -version '2.1.0' - -dependencies { - implementation 'com.github.TheRandomLabs:CurseAPI:master-SNAPSHOT' - implementation 'org.slf4j:slf4j-simple:2.0.0-alpha1' -} - -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact tasks.sourcesJar - artifact tasks.javadocJar - - pom { - groupId = project.group - version = project.version - artifactId = 'flowupdater-curseforgeplugin' - name = project.name - description = 'Add-on for FlowUpdater to download some files from CurseForge.' - url = 'https://github.com/FlowArg/FlowUpdater' - - scm { - connection = 'scm:git:git://github.com/FlowArg/FlowUpdater.git' - developerConnection = 'scm:git:ssh://github.com:FlowArg/FlowUpdater.git' - url = 'https://github.com/FlowArg/FlowUpdater/tree/master' - } - - licenses { - license { - name = 'GNU General Public License v3.0' - url = 'https://www.gnu.org/licenses/gpl-3.0.txt' - } - } - - developers { - developer { - id = 'flowarg' - name = 'Flow Arg' - email = 'coutureflorence3@gmail.com' - } - } - } - } - } - - repositories { - maven { - credentials { - username = System.getenv("OSSRH_USERNAME") - password = System.getenv("OSSRH_PASSWORD") - } - url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - } - } -} - -signing { - def signingKey = System.getenv("GPG_PRIVATE_KEY") - def signingPassword = System.getenv("GPG_PASSPHRASE") - useInMemoryPgpKeys(signingKey, signingPassword) - sign publishing.publications.mavenJava -} diff --git a/CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseForgePluginException.java b/CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseForgePluginException.java deleted file mode 100644 index dc28400f..00000000 --- a/CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseForgePluginException.java +++ /dev/null @@ -1,21 +0,0 @@ -package fr.flowarg.flowupdater.curseforgeplugin; - -public class CurseForgePluginException extends RuntimeException -{ - public CurseForgePluginException() {} - - public CurseForgePluginException(String message) - { - super(message); - } - - public CurseForgePluginException(String message, Throwable cause) - { - super(message, cause); - } - - public CurseForgePluginException(Throwable cause) - { - super(cause); - } -} diff --git a/OptifinePlugin/build.gradle b/OptifinePlugin/build.gradle deleted file mode 100644 index 7a8ff9e1..00000000 --- a/OptifinePlugin/build.gradle +++ /dev/null @@ -1,63 +0,0 @@ -archivesBaseName = "flowupdater-optifineplugin" -version '2.1.0' - -dependencies { - implementation 'com.squareup.okhttp3:okhttp:3.14.9' -} - -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact tasks.sourcesJar - artifact tasks.javadocJar - - pom { - groupId = project.group - version = project.version - artifactId = 'flowupdater-optifineplugin' - name = project.name - description = 'Add-on for FlowUpdater to download OptiFine from the official website.' - url = 'https://github.com/FlowArg/FlowUpdater' - - scm { - connection = 'scm:git:git://github.com/FlowArg/FlowUpdater.git' - developerConnection = 'scm:git:ssh://github.com:FlowArg/FlowUpdater.git' - url = 'https://github.com/FlowArg/FlowUpdater/tree/master' - } - - licenses { - license { - name = 'GNU General Public License v3.0' - url = 'https://www.gnu.org/licenses/gpl-3.0.txt' - } - } - - developers { - developer { - id = 'flowarg' - name = 'Flow Arg' - email = 'coutureflorence3@gmail.com' - } - } - } - } - } - - repositories { - maven { - credentials { - username = System.getenv("OSSRH_USERNAME") - password = System.getenv("OSSRH_PASSWORD") - } - url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - } - } -} - -signing { - def signingKey = System.getenv("GPG_PRIVATE_KEY") - def signingPassword = System.getenv("GPG_PASSPHRASE") - useInMemoryPgpKeys(signingKey, signingPassword) - sign publishing.publications.mavenJava -} diff --git a/OptifinePlugin/src/main/java/fr/antoineok/flowupdater/optifineplugin/OptiFinePlugin.java b/OptifinePlugin/src/main/java/fr/antoineok/flowupdater/optifineplugin/OptiFinePlugin.java deleted file mode 100644 index b03076ed..00000000 --- a/OptifinePlugin/src/main/java/fr/antoineok/flowupdater/optifineplugin/OptiFinePlugin.java +++ /dev/null @@ -1,186 +0,0 @@ -package fr.antoineok.flowupdater.optifineplugin; - -import fr.flowarg.flowio.FileUtils; -import fr.flowarg.flowlogger.ILogger; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.jetbrains.annotations.NotNull; - -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.Objects; - -public class OptiFinePlugin -{ - public static final OptiFinePlugin INSTANCE = new OptiFinePlugin(); - - private final OkHttpClient client = new OkHttpClient(); - - private ILogger logger; - private Path folder; - - /** - * Get an OptiFine object from the official website. - * @param optiFineVersion the version of OptiFine - * @param preview if the OptiFine version is a preview. - * @return the object that defines the plugin - */ - public OptiFine getOptiFine(String optiFineVersion, boolean preview) - { - try - { - final String name = preview ? (optiFineVersion.contains("preview_") && optiFineVersion.contains("OptiFine_") ? optiFineVersion + ".jar" : "preview_OptiFine_" + optiFineVersion + ".jar") : "OptiFine_" + optiFineVersion + ".jar"; - final String newUrl = this.getNewURL(name, preview, optiFineVersion); - final Request request = new Request.Builder() - .url(newUrl) - .build(); - - final Response response = this.client.newCall(request).execute(); - final int length = Integer.parseInt(Objects.requireNonNull(response.header("Content-Length"))); - - assert response.body() != null; - this.checkForUpdates(name, response.body().byteStream(), length, newUrl); - - response.body().close(); - - if(length <= 40) - throw new OptiFinePluginException("Given version of OptiFine not found."); - - return new OptiFine(name, length); - } - catch (Exception e) - { - throw new OptiFinePluginException(e); - } - } - - private @NotNull String getNewURL(String name, boolean preview, String optiFineVersion) - { - final HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse("https://optifine.net/downloadx")).newBuilder(); - urlBuilder.addQueryParameter("f", name); - urlBuilder.addQueryParameter("x", preview ? this.getJsonPreview(optiFineVersion) : this.getJson(optiFineVersion)); - - return urlBuilder.build().toString(); - } - - private void checkForUpdates(String name, InputStream byteStream, int length, String newUrl) throws Exception - { - final Path outputPath = this.getFolder().resolve(name); - if(Files.notExists(outputPath) || FileUtils.getFileSizeBytes(outputPath) != length) - { - this.getLogger().info(String.format("Downloading %s from %s...", outputPath.getFileName().toString(), newUrl)); - Files.copy(byteStream, outputPath, StandardCopyOption.REPLACE_EXISTING); - } - byteStream.close(); - } - - public void shutdownOKHTTP() - { - this.client.dispatcher().executorService().shutdown(); - this.client.connectionPool().evictAll(); - if(this.client.cache() != null) - { - try - { - Objects.requireNonNull(this.client.cache()).close(); - } catch (Exception ignored) {} - } - } - - /** - * @param optiFineVersion the version of OptiFine - * @return the download key - */ - private @NotNull String getJson(String optiFineVersion) - { - final Request request = new Request.Builder() - .url("https://optifine.net/adloadx?f=OptiFine_" + optiFineVersion) - .build(); - try - { - final String[] respLine = this.responseLines(request); - String keyLine = ""; - for(String line : respLine) - { - if(line.contains("downloadx?f=OptiFine")) - { - keyLine = line; - break; - } - } - - return keyLine.replace("' onclick='onDownload()'>OptiFine " + optiFineVersion.replace("_", " ") +"", "").replace("" + optiFineVersion.replace("_", " ") +"", "").replace(" postExecutions; - /** The plugin manager object */ - private final PluginManager pluginManager; + /** The integration manager object */ + private final IntegrationManager integrationManager; /** Default callback */ public static final IProgressCallback NULL_CALLBACK = new IProgressCallback() @@ -90,7 +89,6 @@ private FlowUpdater(VanillaVersion version, ILogger logger, { this.logger = logger; this.version = version; - this.logger.info(String.format("------------------------- FlowUpdater for Minecraft %s v%s -------------------------", this.version.getName(), "1.5.0")); this.externalFiles = externalFiles; this.postExecutions = postExecutions; this.forgeVersion = forgeVersion; @@ -98,10 +96,9 @@ private FlowUpdater(VanillaVersion version, ILogger logger, this.updaterOptions = updaterOptions; this.callback = callback; this.downloadList = new DownloadList(); + this.integrationManager = new IntegrationManager(this); + this.logger.info(String.format("------------------------- FlowUpdater for Minecraft %s v%s -------------------------", this.version.getName(), "1.5.0")); this.callback.init(this.logger); - if(this.updaterOptions.isEnableCurseForgePlugin() || this.updaterOptions.isEnableOptiFineDownloaderPlugin()) - this.pluginManager = new PluginManager(this); - else this.pluginManager = new FallbackPluginManager(this); } /** @@ -140,17 +137,14 @@ private void updateMinecraft(Path dir) throws Exception if(this.forgeVersion != null && this.version.getVersionType() == VersionType.FORGE) { this.checkMods(this.forgeVersion, modsDirPath); - if(this.updaterOptions.isEnableCurseForgePlugin()) - this.pluginManager.loadCurseForgePlugin(modsDirPath, this.forgeVersion); - if(this.updaterOptions.isEnableOptiFineDownloaderPlugin()) - this.pluginManager.loadOptiFinePlugin(modsDirPath, this.forgeVersion); + this.integrationManager.loadCurseForgeIntegration(modsDirPath, this.forgeVersion); + this.integrationManager.loadOptiFineIntegration(modsDirPath, this.forgeVersion); } if (this.fabricVersion != null && this.version.getVersionType() == VersionType.FABRIC) { this.checkMods(this.fabricVersion, modsDirPath); - if(this.updaterOptions.isEnableCurseForgePlugin()) - this.pluginManager.loadCurseForgePlugin(modsDirPath, this.fabricVersion); + this.integrationManager.loadCurseForgeIntegration(modsDirPath, this.fabricVersion); } if (Files.notExists(dir)) @@ -183,7 +177,7 @@ private void installModLoader(IModLoaderVersion modLoader, Path dir, String name if(!modLoader.isModLoaderAlreadyInstalled(dir)) modLoader.install(dir); else this.logger.info(name + " is already installed ! Skipping installation..."); - modLoader.installMods(dir.resolve("mods"), this.pluginManager); + modLoader.installMods(dir.resolve("mods"), this.integrationManager); } } @@ -212,12 +206,11 @@ private void updateExtFiles(Path dir) private void runPostExecutions() { - if(!this.postExecutions.isEmpty()) - { - this.callback.step(Step.POST_EXECUTIONS); - this.logger.info("Running post executions..."); - this.postExecutions.forEach(Runnable::run); - } + if(this.postExecutions.isEmpty()) return; + + this.callback.step(Step.POST_EXECUTIONS); + this.logger.info("Running post executions..."); + this.postExecutions.forEach(Runnable::run); } private void endUpdate() @@ -225,7 +218,6 @@ private void endUpdate() this.callback.step(Step.END); this.callback.update(this.downloadList.getTotalToDownloadBytes(), this.downloadList.getTotalToDownloadBytes()); this.downloadList.clear(); - this.pluginManager.shutdown(); } /** diff --git a/src/main/java/fr/flowarg/flowupdater/download/DownloadList.java b/src/main/java/fr/flowarg/flowupdater/download/DownloadList.java index 1b87840f..2acbd314 100644 --- a/src/main/java/fr/flowarg/flowupdater/download/DownloadList.java +++ b/src/main/java/fr/flowarg/flowupdater/download/DownloadList.java @@ -1,7 +1,7 @@ package fr.flowarg.flowupdater.download; -import fr.antoineok.flowupdater.optifineplugin.OptiFine; -import fr.flowarg.flowupdater.curseforgeplugin.CurseMod; +import fr.flowarg.flowupdater.integrations.optifineplugin.OptiFine; +import fr.flowarg.flowupdater.integrations.curseforgeplugin.CurseMod; import fr.flowarg.flowupdater.download.json.AssetDownloadable; import fr.flowarg.flowupdater.download.json.Downloadable; import fr.flowarg.flowupdater.download.json.ExternalFile; @@ -24,8 +24,8 @@ public class DownloadList private final Queue downloadableAssets = new ConcurrentLinkedDeque<>(); private final List extFiles = new ArrayList<>(); private final List mods = new ArrayList<>(); - private final List curseMods = new ArrayList<>(); - private Object optiFine = null; + private final List curseMods = new ArrayList<>(); + private OptiFine optiFine = null; private final AtomicLong totalToDownloadBytes = new AtomicLong(0); private final AtomicLong downloadedBytes = new AtomicLong(0); private boolean init = false; @@ -38,9 +38,9 @@ public void init() this.downloadableAssets.forEach(downloadable -> this.totalToDownloadBytes.set(this.totalToDownloadBytes.get() + downloadable.getSize())); this.extFiles.forEach(externalFile -> this.totalToDownloadBytes.set(this.totalToDownloadBytes.get() + externalFile.getSize())); this.mods.forEach(mod -> this.totalToDownloadBytes.set(this.totalToDownloadBytes.get() + mod.getSize())); - this.curseMods.forEach(obj -> this.totalToDownloadBytes.set(this.totalToDownloadBytes.get() + (long)(((CurseMod)obj).getLength()))); + this.curseMods.forEach(obj -> this.totalToDownloadBytes.set(this.totalToDownloadBytes.get() + (long)(obj.getLength()))); if (this.optiFine != null) - this.totalToDownloadBytes.set(this.totalToDownloadBytes.get() + (long)(((OptiFine)this.optiFine).getSize())); + this.totalToDownloadBytes.set(this.totalToDownloadBytes.get() + (long)(this.optiFine.getSize())); this.init = true; } @@ -79,17 +79,17 @@ public List getMods() return this.mods; } - public List getCurseMods() + public List getCurseMods() { return this.curseMods; } - public Object getOptiFine() + public OptiFine getOptiFine() { return this.optiFine; } - public void setOptiFine(Object optiFine) + public void setOptiFine(OptiFine optiFine) { this.optiFine = optiFine; } diff --git a/src/main/java/fr/flowarg/flowupdater/download/ICurseFeaturesUser.java b/src/main/java/fr/flowarg/flowupdater/download/ICurseFeaturesUser.java index 13616fd8..1c912d2e 100644 --- a/src/main/java/fr/flowarg/flowupdater/download/ICurseFeaturesUser.java +++ b/src/main/java/fr/flowarg/flowupdater/download/ICurseFeaturesUser.java @@ -2,6 +2,7 @@ import fr.flowarg.flowupdater.download.json.CurseFileInfo; import fr.flowarg.flowupdater.download.json.CurseModPackInfo; +import fr.flowarg.flowupdater.integrations.curseforgeplugin.CurseMod; import java.util.List; @@ -23,5 +24,5 @@ public interface ICurseFeaturesUser * Define all curse mods to update. * @param curseMods curse mods to define. */ - void setAllCurseMods(List curseMods); + void setAllCurseMods(List curseMods); } diff --git a/src/main/java/fr/flowarg/flowupdater/download/VanillaDownloader.java b/src/main/java/fr/flowarg/flowupdater/download/VanillaDownloader.java index cae518a7..32a4c022 100644 --- a/src/main/java/fr/flowarg/flowupdater/download/VanillaDownloader.java +++ b/src/main/java/fr/flowarg/flowupdater/download/VanillaDownloader.java @@ -4,7 +4,6 @@ import fr.flowarg.flowlogger.ILogger; import fr.flowarg.flowstringer.StringUtils; import fr.flowarg.flowupdater.FlowUpdater; -import fr.flowarg.flowupdater.download.json.AssetDownloadable; import fr.flowarg.flowupdater.download.json.Downloadable; import fr.flowarg.flowupdater.utils.IOUtils; import fr.flowarg.flowzipper.ZipUtils; @@ -29,7 +28,6 @@ public class VanillaDownloader private final ILogger logger; private final IProgressCallback callback; private final DownloadList downloadList; - private final int threadsForAssets; private final Path natives; private final Path assets; private final String vanillaJsonURL; @@ -40,7 +38,6 @@ public VanillaDownloader(Path dir, FlowUpdater flowUpdater) throws IOException this.logger = flowUpdater.getLogger(); this.callback = flowUpdater.getCallback(); this.downloadList = flowUpdater.getDownloadList(); - this.threadsForAssets = flowUpdater.getUpdaterOptions().getNmbrThreadsForAssets(); this.natives = this.dir.resolve("natives"); this.assets = this.dir.resolve("assets"); @@ -153,37 +150,34 @@ private void downloadAssets() this.logger.info("Checking assets..."); this.callback.step(Step.DL_ASSETS); - final ExecutorService executorService = Executors.newFixedThreadPool(this.threadsForAssets); + final ExecutorService executorService = Executors.newCachedThreadPool(); - for (int i = 0; i < this.threadsForAssets; i++) - { - executorService.submit(() -> { - try { - AssetDownloadable assetDownloadable; - while ((assetDownloadable = this.downloadList.getDownloadableAssets().poll()) != null) - { - final Path downloadPath = this.assets.resolve(assetDownloadable.getFile()); - - if (Files.notExists(downloadPath) || FileUtils.getFileSizeBytes(downloadPath) != assetDownloadable.getSize()) - { - final Path localAssetPath = IOUtils.getMinecraftFolder().resolve("assets").resolve(assetDownloadable.getFile()); - if(Files.exists(localAssetPath) && FileUtils.getFileSizeBytes(localAssetPath) == assetDownloadable.getSize()) IOUtils.copy(this.logger, localAssetPath, downloadPath); - else - { - IOUtils.download(this.logger, new URL(assetDownloadable.getUrl()), downloadPath); - this.callback.onFileDownloaded(downloadPath); - } - } + this.downloadList.getDownloadableAssets().forEach(assetDownloadable -> executorService.submit(() -> { + try + { + final Path downloadPath = this.assets.resolve(assetDownloadable.getFile()); - this.downloadList.incrementDownloaded(assetDownloadable.getSize()); - this.callback.update(this.downloadList.getDownloadedBytes(), this.downloadList.getTotalToDownloadBytes()); - } - } catch (Exception e) + if (Files.notExists(downloadPath) || FileUtils.getFileSizeBytes(downloadPath) != assetDownloadable.getSize()) { - this.logger.printStackTrace(e); + final Path localAssetPath = IOUtils.getMinecraftFolder().resolve("assets").resolve(assetDownloadable.getFile()); + if (Files.exists(localAssetPath) && FileUtils.getFileSizeBytes(localAssetPath) == assetDownloadable.getSize()) + IOUtils.copy(this.logger, localAssetPath, downloadPath); + else + { + IOUtils.download(this.logger, new URL(assetDownloadable.getUrl()), downloadPath); + this.callback.onFileDownloaded(downloadPath); + } } - }); - } + + this.downloadList.incrementDownloaded(assetDownloadable.getSize()); + this.callback.update(this.downloadList.getDownloadedBytes(), this.downloadList.getTotalToDownloadBytes()); + } + catch (Exception e) + { + this.logger.printStackTrace(e); + } + })); + try { executorService.shutdown(); diff --git a/src/main/java/fr/flowarg/flowupdater/download/json/CurseFileInfo.java b/src/main/java/fr/flowarg/flowupdater/download/json/CurseFileInfo.java index 62beb85e..71ba6664 100644 --- a/src/main/java/fr/flowarg/flowupdater/download/json/CurseFileInfo.java +++ b/src/main/java/fr/flowarg/flowupdater/download/json/CurseFileInfo.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; public class CurseFileInfo { @@ -52,8 +53,24 @@ public int getProjectID() { return this.projectID; } + public int getFileID() { return this.fileID; } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || this.getClass() != o.getClass()) return false; + final CurseFileInfo that = (CurseFileInfo)o; + return this.projectID == that.projectID && this.fileID == that.fileID; + } + + @Override + public int hashCode() + { + return Objects.hash(this.projectID, this.fileID); + } } diff --git a/src/main/java/fr/flowarg/flowupdater/download/json/MCP.java b/src/main/java/fr/flowarg/flowupdater/download/json/MCP.java index 16f95c89..007eac05 100644 --- a/src/main/java/fr/flowarg/flowupdater/download/json/MCP.java +++ b/src/main/java/fr/flowarg/flowupdater/download/json/MCP.java @@ -1,6 +1,7 @@ package fr.flowarg.flowupdater.download.json; import com.google.gson.JsonObject; +import fr.flowarg.flowupdater.utils.FlowUpdaterException; import fr.flowarg.flowupdater.utils.IOUtils; import java.net.MalformedURLException; @@ -67,8 +68,7 @@ public static MCP getMCPFromJson(String jsonUrl) return getMCPFromJson(new URL(jsonUrl)); } catch (MalformedURLException e) { - e.printStackTrace(); - return new MCP("", "", "", "", -1, -1); + throw new FlowUpdaterException(e); } } diff --git a/CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseForgePlugin.java b/src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseForgeIntegration.java similarity index 61% rename from CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseForgePlugin.java rename to src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseForgeIntegration.java index edb16d28..23a02760 100644 --- a/CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseForgePlugin.java +++ b/src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseForgeIntegration.java @@ -1,17 +1,14 @@ -package fr.flowarg.flowupdater.curseforgeplugin; +package fr.flowarg.flowupdater.integrations.curseforgeplugin; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.therandomlabs.curseapi.CurseAPI; -import com.therandomlabs.curseapi.CurseException; -import com.therandomlabs.curseapi.util.OkHttpUtils; import fr.flowarg.flowio.FileUtils; import fr.flowarg.flowlogger.ILogger; import fr.flowarg.flowstringer.StringUtils; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import org.jetbrains.annotations.Contract; +import fr.flowarg.flowupdater.download.json.CurseFileInfo; +import fr.flowarg.flowupdater.utils.FlowUpdaterException; +import fr.flowarg.flowupdater.utils.IOUtils; import org.jetbrains.annotations.NotNull; import javax.net.ssl.HttpsURLConnection; @@ -19,33 +16,40 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.OutputStream; -import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -public class CurseForgePlugin +public class CurseForgeIntegration { - public static final CurseForgePlugin INSTANCE = new CurseForgePlugin(); + private final ILogger logger; + private final Path folder; - private ILogger logger; - private Path folder; + public CurseForgeIntegration(ILogger logger, Path folder) throws Exception + { + this.logger = logger; + this.folder = folder; + Files.createDirectories(this.folder); + } @NotNull public URL getURLOfFile(int projectID, int fileID) { try { - return CurseAPI.fileDownloadURL(projectID, fileID).map(HttpUrl::url).orElseThrow(CurseForgePluginException::new); - } catch (CurseException e) + return new URL(IOUtils.getContent(new URL(String.format("https://addons-ecs.forgesvc.net/api/v2/addon/%d/file/%d/download-url", projectID, fileID)))); + } catch (Exception e) { - throw new CurseForgePluginException(e); + throw new FlowUpdaterException(e); } } @@ -73,7 +77,7 @@ public CurseMod getCurseMod(int projectID, int fileID) return new CurseMod(url.getFile().substring(url.getFile().lastIndexOf('/') + 1), url.toExternalForm(), md5, length); } catch (Exception e) { - throw new CurseForgePluginException(e); + throw new FlowUpdaterException(e); } finally { if (connection != null) connection.disconnect(); @@ -89,7 +93,8 @@ public CurseModPack getCurseModPack(int projectID, int fileID, boolean installEx } catch (Exception e) { - throw new CurseForgePluginException(e); + e.printStackTrace(); + return null; } } @@ -97,14 +102,12 @@ public CurseModPack getCurseModPack(int projectID, int fileID, boolean installEx { final URL link = this.getURLOfFile(projectID, fileID); final String linkStr = link.toExternalForm(); - final Path outPath = Paths.get(this.getFolder().toString(), linkStr.substring(linkStr.lastIndexOf('/') + 1)); + final Path outPath = this.folder.resolve(linkStr.substring(linkStr.lastIndexOf('/') + 1)); + final String md5 = this.getMD5(link); + + if(Files.notExists(outPath) || (!md5.contains("-") && !FileUtils.getMD5(outPath).equalsIgnoreCase(md5))) + IOUtils.download(this.logger, link, outPath); - if(Files.notExists(outPath) || !FileUtils.getMD5(outPath).equalsIgnoreCase(this.getMD5(link))) - { - this.getLogger().info(String.format("Downloading %s from %s...", outPath.getFileName().toString(), linkStr)); - Files.createDirectories(outPath.getParent()); - Files.copy(this.catchForbidden(link), outPath, StandardCopyOption.REPLACE_EXISTING); - } return outPath; } @@ -122,7 +125,7 @@ public CurseModPack getCurseModPack(int projectID, int fileID, boolean installEx } catch (Exception e) { - throw new CurseForgePluginException(e); + throw new FlowUpdaterException(e); } finally { @@ -133,17 +136,27 @@ public CurseModPack getCurseModPack(int projectID, int fileID, boolean installEx private void extractModPack(@NotNull Path out, boolean installExtFiles) throws Exception { - this.getLogger().info("Extracting mod pack..."); + this.logger.info("Extracting mod pack..."); final ZipFile zipFile = new ZipFile(out.toFile(), ZipFile.OPEN_READ, StandardCharsets.UTF_8); - final Path dirPath = this.getFolder().getParent(); + final Path dirPath = this.folder.getParent(); final Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { final ZipEntry entry = entries.nextElement(); - final Path flPath = Paths.get(dirPath.toString(), StringUtils.empty(entry.getName(), "overrides/")); - if(entry.getName().equalsIgnoreCase("manifest.json") && Files.exists(flPath) && entry.getCrc() == FileUtils.getCRC32(flPath)) - break; - if(installExtFiles && !entry.getName().equals("modlist.html")) + final Path flPath = dirPath.resolve(StringUtils.empty(entry.getName(), "overrides/")); + final String entryName = entry.getName(); + + if(entryName.equalsIgnoreCase("manifest.json")) + { + if(Files.notExists(flPath) || entry.getCrc() != FileUtils.getCRC32(flPath)) + this.transferAndClose(flPath, zipFile, entry); + continue; + } + + if(entryName.equals("modlist.html")) + continue; + + if(installExtFiles) { if(Files.notExists(flPath)) { @@ -153,13 +166,14 @@ private void extractModPack(@NotNull Path out, boolean installExtFiles) throws E this.transferAndClose(flPath, zipFile, entry); } } - else if(entry.getName().equals("manifest.json")) this.transferAndClose(flPath, zipFile, entry); } zipFile.close(); } private void transferAndClose(Path flPath, ZipFile zipFile, ZipEntry entry) throws Exception { + if(Files.notExists(flPath.getParent())) + Files.createDirectories(flPath.getParent()); try(OutputStream pathStream = Files.newOutputStream(flPath); BufferedOutputStream fo = new BufferedOutputStream(pathStream); InputStream is = zipFile.getInputStream(entry) @@ -171,9 +185,9 @@ private void transferAndClose(Path flPath, ZipFile zipFile, ZipEntry entry) thro private @NotNull CurseModPack parseMods() throws Exception { - this.getLogger().info("Fetching mods..."); + this.logger.info("Fetching mods..."); - final Path dirPath = Paths.get(this.getFolder().getParent().toString()); + final Path dirPath = Paths.get(this.folder.getParent().toString()); final BufferedReader manifestReader = Files.newBufferedReader(Paths.get(dirPath.toString(), "manifest.json")); final JsonObject manifestObj = JsonParser.parseReader(manifestReader).getAsJsonObject(); final List manifestFiles = new ArrayList<>(); @@ -186,7 +200,7 @@ private void transferAndClose(Path flPath, ZipFile zipFile, ZipEntry entry) thro final BufferedReader cacheReader = Files.newBufferedReader(cachePath); final JsonArray cacheArray = JsonParser.parseReader(cacheReader).getAsJsonArray(); - final List mods = new ArrayList<>(); + final Queue mods = new ConcurrentLinkedQueue<>(); cacheArray.forEach(jsonElement -> { final JsonObject object = jsonElement.getAsJsonObject(); @@ -195,12 +209,13 @@ private void transferAndClose(Path flPath, ZipFile zipFile, ZipEntry entry) thro final String md5 = object.get("md5").getAsString(); final int length = object.get("length").getAsInt(); final ProjectMod projectMod = ProjectMod.fromJsonObject(object); - final boolean required = projectMod.isRequired(); - mods.add(new CurseModPack.CurseModPackMod(name, downloadURL, md5, length, required)); + mods.add(new CurseModPack.CurseModPackMod(name, downloadURL, md5, length, projectMod.isRequired())); manifestFiles.remove(projectMod); }); - manifestFiles.forEach(projectMod -> { + final ExecutorService executorService = Executors.newCachedThreadPool(); + + manifestFiles.forEach(projectMod -> executorService.submit(() -> { final boolean required = projectMod.isRequired(); final CurseModPack.CurseModPackMod mod = new CurseModPack.CurseModPackMod(this.getCurseMod(projectMod), required); final JsonObject inCache = new JsonObject(); @@ -215,7 +230,16 @@ private void transferAndClose(Path flPath, ZipFile zipFile, ZipEntry entry) thro cacheArray.add(inCache); mods.add(mod); - }); + })); + + try + { + executorService.shutdown(); + executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); + } catch (InterruptedException e) + { + throw new FlowUpdaterException(e); + } manifestReader.close(); cacheReader.close(); @@ -225,115 +249,27 @@ private void transferAndClose(Path flPath, ZipFile zipFile, ZipEntry entry) thro final String modPackVersion = manifestObj.get("version").getAsString(); final String modPackAuthor = manifestObj.get("author").getAsString(); - return new CurseModPack(modPackName, modPackVersion, modPackAuthor, mods); - } - - public void shutdownOKHTTP() - { - final OkHttpClient client = OkHttpUtils.getClient(); - if(client != null) - { - client.dispatcher().executorService().shutdown(); - client.connectionPool().evictAll(); - if(client.cache() != null) - { - try - { - Objects.requireNonNull(client.cache()).close(); - } catch (Exception ignored) {} - } - } - } - - public InputStream catchForbidden(@NotNull URL url) throws Exception - { - final HttpURLConnection connection = (HttpURLConnection)url.openConnection(); - connection.addRequestProperty("User-Agent", "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36"); - connection.setInstanceFollowRedirects(true); - return connection.getInputStream(); + return new CurseModPack(modPackName, modPackVersion, modPackAuthor, new ArrayList<>(mods)); } - private static class ProjectMod + private static class ProjectMod extends CurseFileInfo { - private final int projectID; - private final int fileID; private final boolean required; public ProjectMod(int projectID, int fileID, boolean required) { - this.projectID = projectID; - this.fileID = fileID; + super(projectID, fileID); this.required = required; } - @Contract("_ -> new") private static @NotNull ProjectMod fromJsonObject(@NotNull JsonObject object) { return new ProjectMod(object.get("projectID").getAsInt(), object.get("fileID").getAsInt(), object.get("required").getAsBoolean()); } - public int getProjectID() - { - return this.projectID; - } - - public int getFileID() - { - return this.fileID; - } - public boolean isRequired() { return this.required; } - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - final ProjectMod that = (ProjectMod)o; - - if (this.projectID != that.projectID) return false; - if (this.fileID != that.fileID) return false; - return this.required == that.required; - } - - @Override - public int hashCode() - { - int result = this.projectID; - result = 31 * result + this.fileID; - result = 31 * result + (this.required ? 1 : 0); - return result; - } - } - - public @NotNull ILogger getLogger() - { - return this.logger; - } - - public void setLogger(@NotNull ILogger logger) - { - this.logger = logger; - } - - public @NotNull Path getFolder() - { - return this.folder; - } - - public void setFolder(@NotNull Path folder) - { - try - { - this.folder = folder; - Files.createDirectories(this.folder); - } catch (Exception e) - { - throw new CurseForgePluginException(e); - } } } diff --git a/CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseMod.java b/src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseMod.java similarity index 91% rename from CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseMod.java rename to src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseMod.java index 5b4234e0..d904480b 100644 --- a/CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseMod.java +++ b/src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseMod.java @@ -1,4 +1,4 @@ -package fr.flowarg.flowupdater.curseforgeplugin; +package fr.flowarg.flowupdater.integrations.curseforgeplugin; public class CurseMod { diff --git a/CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseModPack.java b/src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseModPack.java similarity index 95% rename from CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseModPack.java rename to src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseModPack.java index 2ab409fe..0955f486 100644 --- a/CurseForgePlugin/src/main/java/fr/flowarg/flowupdater/curseforgeplugin/CurseModPack.java +++ b/src/main/java/fr/flowarg/flowupdater/integrations/curseforgeplugin/CurseModPack.java @@ -1,4 +1,4 @@ -package fr.flowarg.flowupdater.curseforgeplugin; +package fr.flowarg.flowupdater.integrations.curseforgeplugin; import java.util.List; diff --git a/OptifinePlugin/src/main/java/fr/antoineok/flowupdater/optifineplugin/OptiFine.java b/src/main/java/fr/flowarg/flowupdater/integrations/optifineplugin/OptiFine.java similarity index 71% rename from OptifinePlugin/src/main/java/fr/antoineok/flowupdater/optifineplugin/OptiFine.java rename to src/main/java/fr/flowarg/flowupdater/integrations/optifineplugin/OptiFine.java index 9157cca7..ae582de3 100644 --- a/OptifinePlugin/src/main/java/fr/antoineok/flowupdater/optifineplugin/OptiFine.java +++ b/src/main/java/fr/flowarg/flowupdater/integrations/optifineplugin/OptiFine.java @@ -1,11 +1,12 @@ -package fr.antoineok.flowupdater.optifineplugin; +package fr.flowarg.flowupdater.integrations.optifineplugin; public class OptiFine { private final String name; private final int size; - public OptiFine(String name, int size) { + public OptiFine(String name, int size) + { this.name = name; this.size = size; } diff --git a/src/main/java/fr/flowarg/flowupdater/integrations/optifineplugin/OptiFineIntegration.java b/src/main/java/fr/flowarg/flowupdater/integrations/optifineplugin/OptiFineIntegration.java new file mode 100644 index 00000000..c083d282 --- /dev/null +++ b/src/main/java/fr/flowarg/flowupdater/integrations/optifineplugin/OptiFineIntegration.java @@ -0,0 +1,151 @@ +package fr.flowarg.flowupdater.integrations.optifineplugin; + +import fr.flowarg.flowio.FileUtils; +import fr.flowarg.flowlogger.ILogger; +import fr.flowarg.flowupdater.utils.FlowUpdaterException; +import fr.flowarg.flowupdater.utils.IOUtils; +import org.jetbrains.annotations.NotNull; + +import javax.net.ssl.HttpsURLConnection; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +public class OptiFineIntegration +{ + private final ILogger logger; + private final Path folder; + + public OptiFineIntegration(ILogger logger, Path folder) throws Exception + { + this.logger = logger; + this.folder = folder; + Files.createDirectories(this.folder); + } + + /** + * Get an OptiFine object from the official website. + * @param optiFineVersion the version of OptiFine + * @param preview if the OptiFine version is a preview. + * @return the object that defines the plugin + */ + public OptiFine getOptiFine(String optiFineVersion, boolean preview) + { + try + { + final String name = preview ? (optiFineVersion.contains("preview_") && optiFineVersion.contains("OptiFine_") ? optiFineVersion + ".jar" : "preview_OptiFine_" + optiFineVersion + ".jar") : "OptiFine_" + optiFineVersion + ".jar"; + final String newUrl = this.getNewURL(name, preview, optiFineVersion); + final GetResponse getResponse = this.getResponse(new URL(newUrl), "Content-Length"); + final int length = Integer.parseInt(getResponse.header); + + this.checkForUpdates(name, getResponse.byteStream, length, newUrl); + getResponse.byteStream.close(); + + if(length <= 40) + throw new FlowUpdaterException("Given version of OptiFine not found."); + + return new OptiFine(name, length); + } + catch (Exception e) + { + throw new FlowUpdaterException(e); + } + } + + private @NotNull String getNewURL(String name, boolean preview, String optiFineVersion) + { + return "https://optifine.net/downloadx?f=" + name + "&x=" + (preview ? this.getJsonPreview(optiFineVersion) : this.getJson(optiFineVersion)); + } + + private void checkForUpdates(String name, InputStream byteStream, int length, String newUrl) throws Exception + { + final Path outputPath = this.folder.resolve(name); + if(Files.notExists(outputPath) || FileUtils.getFileSizeBytes(outputPath) != length) + { + this.logger.info(String.format("Downloading %s from %s...", outputPath.getFileName().toString(), newUrl)); + Files.copy(byteStream, outputPath, StandardCopyOption.REPLACE_EXISTING); + } + byteStream.close(); + } + + /** + * @param optiFineVersion the version of OptiFine + * @return the download key + */ + private @NotNull String getJson(String optiFineVersion) + { + try + { + final String[] respLine = IOUtils.getContent(new URL("https://optifine.net/adloadx?f=OptiFine_" + optiFineVersion)).split("\n"); + String keyLine = ""; + for(String line : respLine) + { + if(line.contains("downloadx?f=OptiFine")) + { + keyLine = line; + break; + } + } + + return keyLine.replace("' onclick='onDownload()'>OptiFine " + optiFineVersion.replace("_", " ") +"", "").replace("" + optiFineVersion.replace("_", " ") +"", "").replace(" { + allCurseMods.add(mod); + try + { + final Path filePath = dir.resolve(mod.getName()); + boolean flag = false; + for (String exclude : modPackInfo.getExcluded()) + { + if (!mod.getName().equalsIgnoreCase(exclude)) continue; + + flag = !mod.isRequired(); + break; + } + if(!flag && (Files.notExists(filePath) || !FileUtils.getMD5(filePath).equalsIgnoreCase(mod.getMd5()) || FileUtils.getFileSizeBytes(filePath) != mod.getLength())) + { + if (mod.getMd5().contains("-")) return; + + Files.deleteIfExists(filePath); + this.downloadList.getCurseMods().add(mod); + } + } catch (Exception e) + { + this.logger.printStackTrace(e); + } + }); + + curseFeaturesUser.setAllCurseMods(allCurseMods); + } + catch (Exception e) + { + this.logger.printStackTrace(e); + } + } + + public void loadOptiFineIntegration(Path dir, AbstractForgeVersion forgeVersion) + { + if(forgeVersion.getOptiFineInfo() == null) return; + + try + { + final OptiFineIntegration optifineIntegration = new OptiFineIntegration(this.logger, dir.getParent().resolve(".op")); + final OptiFine optifine = optifineIntegration.getOptiFine(forgeVersion.getOptiFineInfo().getVersion(), forgeVersion.getOptiFineInfo().isPreview()); + this.downloadList.setOptiFine(optifine); + } catch (Exception e) + { + this.logger.printStackTrace(e); + } + } + + public ILogger getLogger() + { + return this.logger; + } +} diff --git a/src/main/java/fr/flowarg/flowupdater/utils/ModFileDeleter.java b/src/main/java/fr/flowarg/flowupdater/utils/ModFileDeleter.java index 0f4acbdf..1d6bfa80 100644 --- a/src/main/java/fr/flowarg/flowupdater/utils/ModFileDeleter.java +++ b/src/main/java/fr/flowarg/flowupdater/utils/ModFileDeleter.java @@ -1,9 +1,9 @@ package fr.flowarg.flowupdater.utils; -import fr.antoineok.flowupdater.optifineplugin.OptiFine; import fr.flowarg.flowio.FileUtils; -import fr.flowarg.flowupdater.curseforgeplugin.CurseMod; import fr.flowarg.flowupdater.download.json.Mod; +import fr.flowarg.flowupdater.integrations.curseforgeplugin.CurseMod; +import fr.flowarg.flowupdater.integrations.optifineplugin.OptiFine; import java.io.IOException; import java.nio.file.Files; @@ -26,13 +26,11 @@ public ModFileDeleter(boolean useFileDeleter, String... modsToIgnore) * Delete all bad files in the provided directory. * @param modsDir the mod's folder. * @param mods the mods list. - * @param cursePluginLoaded is the CurseForge plugin loaded ? * @param allCurseMods the curse's mods list. - * @param optiFinePluginLoaded is the OptiFine plugin loaded ? - * @param optiFineParam the OptiFine object. + * @param optiFine the OptiFine object. * @throws Exception thrown if an error occurred */ - public void delete(Path modsDir, List mods, boolean cursePluginLoaded, List allCurseMods, boolean optiFinePluginLoaded, Object optiFineParam) throws Exception + public void delete(Path modsDir, List mods, List allCurseMods, OptiFine optiFine) throws Exception { if(!this.isUseFileDeleter()) return; @@ -45,37 +43,29 @@ public void delete(Path modsDir, List mods, boolean cursePluginLoaded, List if(verifiedFiles.contains(fileInDir)) continue; - if(mods.isEmpty() && allCurseMods.isEmpty() && optiFineParam == null) + if(mods.isEmpty() && allCurseMods.isEmpty() && optiFine == null) { if (!verifiedFiles.contains(fileInDir)) badFiles.add(fileInDir); } else { - if (cursePluginLoaded) - { - this.processCurseForgeMods(allCurseMods, fileInDir, badFiles, verifiedFiles); - } + this.processCurseForgeMods(allCurseMods, fileInDir, badFiles, verifiedFiles); - if (optiFinePluginLoaded) + if (optiFine != null) { - final OptiFine optifine = (OptiFine)optiFineParam; - if (optifine != null) + if (optiFine.getName().equalsIgnoreCase(fileInDir.getFileName().toString())) { - if (optifine.getName().equalsIgnoreCase(fileInDir.getFileName().toString())) + if (FileUtils.getFileSizeBytes(fileInDir) == optiFine.getSize()) { - if (FileUtils.getFileSizeBytes(fileInDir) == optifine.getSize()) - { - badFiles.remove(fileInDir); - verifiedFiles.add(fileInDir); - } - else badFiles.add(fileInDir); - } - else - { - if (!verifiedFiles.contains(fileInDir)) - badFiles.add(fileInDir); + badFiles.remove(fileInDir); + verifiedFiles.add(fileInDir); } + else badFiles.add(fileInDir); + } + else + { + if (!verifiedFiles.contains(fileInDir)) badFiles.add(fileInDir); } } @@ -111,11 +101,10 @@ public void delete(Path modsDir, List mods, boolean cursePluginLoaded, List badFiles.clear(); } - private void processCurseForgeMods(List allCurseMods, Path fileInDir, Set badFiles, List verifiedFiles) throws Exception + private void processCurseForgeMods(List allCurseMods, Path fileInDir, Set badFiles, List verifiedFiles) throws Exception { - for (Object obj : allCurseMods) + for (CurseMod mod : allCurseMods) { - final CurseMod mod = (CurseMod)obj; if (mod.getName().equalsIgnoreCase(fileInDir.getFileName().toString())) { if (mod.getMd5().contains("-")) diff --git a/src/main/java/fr/flowarg/flowupdater/utils/PluginManager.java b/src/main/java/fr/flowarg/flowupdater/utils/PluginManager.java deleted file mode 100644 index 4d589a35..00000000 --- a/src/main/java/fr/flowarg/flowupdater/utils/PluginManager.java +++ /dev/null @@ -1,172 +0,0 @@ -package fr.flowarg.flowupdater.utils; - -import fr.antoineok.flowupdater.optifineplugin.OptiFine; -import fr.antoineok.flowupdater.optifineplugin.OptiFinePlugin; -import fr.flowarg.flowio.FileUtils; -import fr.flowarg.flowlogger.ILogger; -import fr.flowarg.flowupdater.FlowUpdater; -import fr.flowarg.flowupdater.curseforgeplugin.CurseForgePlugin; -import fr.flowarg.flowupdater.curseforgeplugin.CurseMod; -import fr.flowarg.flowupdater.curseforgeplugin.CurseModPack; -import fr.flowarg.flowupdater.download.DownloadList; -import fr.flowarg.flowupdater.download.ICurseFeaturesUser; -import fr.flowarg.flowupdater.download.IProgressCallback; -import fr.flowarg.flowupdater.download.Step; -import fr.flowarg.flowupdater.download.json.CurseFileInfo; -import fr.flowarg.flowupdater.download.json.CurseModPackInfo; -import fr.flowarg.flowupdater.versions.AbstractForgeVersion; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -public class PluginManager -{ - private final IProgressCallback progressCallback; - private final ILogger logger; - private final DownloadList downloadList; - - private boolean cursePluginLoaded = false; - private boolean optiFinePluginLoaded = false; - - public PluginManager(FlowUpdater updater) - { - this.progressCallback = updater.getCallback(); - this.logger = updater.getLogger(); - this.downloadList = updater.getDownloadList(); - } - - public void loadCurseForgePlugin(Path dir, ICurseFeaturesUser curseFeaturesUser) - { - if (this.cursePluginLoaded) return; - - try - { - Class.forName("fr.flowarg.flowupdater.curseforgeplugin.CurseForgePlugin"); - this.cursePluginLoaded = true; - CurseForgePlugin.INSTANCE.setLogger(this.logger); - CurseForgePlugin.INSTANCE.setFolder(dir.getParent().resolve(".cfp")); - } - catch (ClassNotFoundException e) - { - this.cursePluginLoaded = false; - this.logger.err("Cannot install mods from CurseForge: CurseAPI is not loaded. Please add the flowupdater-curseforgeplugin dependency!"); - return; - } - - final List allCurseMods = new ArrayList<>(curseFeaturesUser.getCurseMods().size()); - - for (CurseFileInfo info : curseFeaturesUser.getCurseMods()) - { - try - { - final CurseForgePlugin curseForgePlugin = CurseForgePlugin.INSTANCE; - final CurseMod mod = curseForgePlugin.getCurseMod(info.getProjectID(), info.getFileID()); - allCurseMods.add(mod); - - final Path filePath = dir.resolve(mod.getName()); - - if(Files.exists(filePath) && FileUtils.getMD5(filePath).equals(mod.getMd5()) && FileUtils.getFileSizeBytes(filePath) == mod.getLength()) continue; - - if (mod.getMd5().contains("-")) continue; - - Files.deleteIfExists(filePath); - this.downloadList.getCurseMods().add(mod); - } catch (Exception e) - { - this.logger.printStackTrace(e); - } - } - - final CurseModPackInfo modPackInfo = curseFeaturesUser.getModPackInfo(); - - if (modPackInfo == null) - { - curseFeaturesUser.setAllCurseMods(allCurseMods); - return; - } - - this.progressCallback.step(Step.MOD_PACK); - final CurseForgePlugin plugin = CurseForgePlugin.INSTANCE; - final CurseModPack modPack = plugin.getCurseModPack(modPackInfo.getProjectID(), modPackInfo.getFileID(), modPackInfo.isInstallExtFiles()); - this.logger.info("Loading mod pack: " + modPack.getName() + " (" + modPack.getVersion() + ") by " + modPack.getAuthor() + '.'); - modPack.getMods().forEach(mod -> { - allCurseMods.add(mod); - try - { - final Path filePath = dir.resolve(mod.getName()); - boolean flag = false; - for (String exclude : modPackInfo.getExcluded()) - { - if (!mod.getName().equalsIgnoreCase(exclude)) continue; - - flag = !mod.isRequired(); - break; - } - if(!flag && (Files.notExists(filePath) || !FileUtils.getMD5(filePath).equalsIgnoreCase(mod.getMd5()) || FileUtils.getFileSizeBytes(filePath) != mod.getLength())) - { - if (mod.getMd5().contains("-")) return; - - Files.deleteIfExists(filePath); - this.downloadList.getCurseMods().add(mod); - } - } catch (IOException e) - { - this.logger.printStackTrace(e); - } - }); - - curseFeaturesUser.setAllCurseMods(allCurseMods); - } - - public void loadOptiFinePlugin(Path dir, AbstractForgeVersion forgeVersion) - { - if(forgeVersion.getOptiFineInfo() == null) return; - - try - { - Class.forName("fr.antoineok.flowupdater.optifineplugin.OptiFinePlugin"); - this.optiFinePluginLoaded = true; - try - { - final OptiFinePlugin optifinePlugin = OptiFinePlugin.INSTANCE; - optifinePlugin.setLogger(this.logger); - optifinePlugin.setFolder(dir.getParent().resolve(".op")); - final OptiFine optifine = optifinePlugin.getOptiFine(forgeVersion.getOptiFineInfo().getVersion(), forgeVersion.getOptiFineInfo().isPreview()); - this.downloadList.setOptiFine(optifine); - } catch (Exception e) - { - this.logger.printStackTrace(e); - } - } catch (ClassNotFoundException e) - { - this.optiFinePluginLoaded = false; - this.logger.err("Cannot install OptiFine: OptiFinePlugin is not loaded. Please add the flowupdater-optifineplugin dependency!"); - } - } - - public void shutdown() - { - if (this.cursePluginLoaded) CurseForgePlugin.INSTANCE.shutdownOKHTTP(); - if (this.optiFinePluginLoaded) OptiFinePlugin.INSTANCE.shutdownOKHTTP(); - this.cursePluginLoaded = false; - this.optiFinePluginLoaded = false; - } - - public ILogger getLogger() - { - return this.logger; - } - - public boolean isCursePluginLoaded() - { - return this.cursePluginLoaded; - } - - public boolean isOptiFinePluginLoaded() - { - return this.optiFinePluginLoaded; - } -} diff --git a/src/main/java/fr/flowarg/flowupdater/utils/UpdaterOptions.java b/src/main/java/fr/flowarg/flowupdater/utils/UpdaterOptions.java index cfeb6931..c7fbe127 100644 --- a/src/main/java/fr/flowarg/flowupdater/utils/UpdaterOptions.java +++ b/src/main/java/fr/flowarg/flowupdater/utils/UpdaterOptions.java @@ -4,8 +4,6 @@ import fr.flowarg.flowupdater.utils.builderapi.BuilderException; import fr.flowarg.flowupdater.utils.builderapi.IBuilder; -import java.util.Random; - /** * Represent some settings for FlowUpdater * @@ -13,22 +11,16 @@ */ public class UpdaterOptions { - public static final UpdaterOptions DEFAULT = new UpdaterOptions(true, false, false, false, new Random().nextInt(2) + 2, new ExternalFileDeleter()); + public static final UpdaterOptions DEFAULT = new UpdaterOptions(true, false, new ExternalFileDeleter()); private final boolean silentRead; private final boolean downloadServer; - private final boolean enableCurseForgePlugin; - private final boolean enableOptiFineDownloaderPlugin; - private final int nmbrThreadsForAssets; private final ExternalFileDeleter externalFileDeleter; - private UpdaterOptions(boolean silentRead, boolean enableCurseForgePlugin, boolean enableOptiFineDownloaderPlugin, boolean downloadServer, int nmbrThreadsForAssets, ExternalFileDeleter externalFileDeleter) + private UpdaterOptions(boolean silentRead, boolean downloadServer, ExternalFileDeleter externalFileDeleter) { this.silentRead = silentRead; - this.enableCurseForgePlugin = enableCurseForgePlugin; - this.enableOptiFineDownloaderPlugin = enableOptiFineDownloaderPlugin; this.downloadServer = downloadServer; - this.nmbrThreadsForAssets = nmbrThreadsForAssets; this.externalFileDeleter = externalFileDeleter; } @@ -52,36 +44,6 @@ public boolean isDownloadServer() return this.downloadServer; } - /** - * Enable CurseForgePlugin (CFP)? - * Default: false - * @return enableCurseForgePlugin value. - */ - public boolean isEnableCurseForgePlugin() - { - return this.enableCurseForgePlugin; - } - - /** - * Enable OptiFineDownloaderPlugin (ODP)? - * Default: false - * @return enableOptiFineDownloaderPlugin value. - */ - public boolean isEnableOptiFineDownloaderPlugin() - { - return this.enableOptiFineDownloaderPlugin; - } - - /** - * Number of threads used to download assets. - * Default: 2 or 3 (random) - * @return nmbrThreadsForAssets value. - */ - public int getNmbrThreadsForAssets() - { - return this.nmbrThreadsForAssets; - } - /** * The external file deleter is used to check if some external files need to be downloaded. * Default: {@link fr.flowarg.flowupdater.utils.ExternalFileDeleter} @@ -95,10 +57,7 @@ public ExternalFileDeleter getExternalFileDeleter() public static class UpdaterOptionsBuilder implements IBuilder { private final BuilderArgument silentReadArgument = new BuilderArgument<>("SilentRead", () -> true).optional(); - private final BuilderArgument enableCurseForgePluginArgument = new BuilderArgument<>("EnableCurseForgePlugin", () -> false).optional(); - private final BuilderArgument enableOptiFineDownloaderPluginArgument = new BuilderArgument<>("EnableOptiFineDownloaderPlugin", () -> false).optional(); private final BuilderArgument downloadServerArgument = new BuilderArgument<>("DownloadServer", () -> false).optional(); - private final BuilderArgument nmbrThreadsForAssetsArgument = new BuilderArgument<>("Number of Threads for assets", () -> new Random().nextInt(2) + 2).optional(); private final BuilderArgument externalFileDeleterArgument = new BuilderArgument<>("External FileDeleter", ExternalFileDeleter::new).optional(); public UpdaterOptionsBuilder withSilentRead(boolean silentRead) @@ -106,17 +65,6 @@ public UpdaterOptionsBuilder withSilentRead(boolean silentRead) this.silentReadArgument.set(silentRead); return this; } - public UpdaterOptionsBuilder withEnableCurseForgePlugin(boolean enableModsFromCurseForge) - { - this.enableCurseForgePluginArgument.set(enableModsFromCurseForge); - return this; - } - - public UpdaterOptionsBuilder withEnableOptiFineDownloaderPlugin(boolean installOptiFineAsMod) - { - this.enableOptiFineDownloaderPluginArgument.set(installOptiFineAsMod); - return this; - } public UpdaterOptionsBuilder withDownloadServer(boolean downloadServer) { @@ -124,12 +72,6 @@ public UpdaterOptionsBuilder withDownloadServer(boolean downloadServer) return this; } - public UpdaterOptionsBuilder withNmbrThreadsForAssets(int nmbrThreadsForAssets) - { - this.nmbrThreadsForAssetsArgument.set(nmbrThreadsForAssets); - return this; - } - public UpdaterOptionsBuilder withExternalFileDeleter(ExternalFileDeleter externalFileDeleter) { this.externalFileDeleterArgument.set(externalFileDeleter); @@ -141,10 +83,7 @@ public UpdaterOptions build() throws BuilderException { return new UpdaterOptions( this.silentReadArgument.get(), - this.enableCurseForgePluginArgument.get(), - this.enableOptiFineDownloaderPluginArgument.get(), this.downloadServerArgument.get(), - this.nmbrThreadsForAssetsArgument.get(), this.externalFileDeleterArgument.get() ); } diff --git a/src/main/java/fr/flowarg/flowupdater/utils/builderapi/BuilderArgument.java b/src/main/java/fr/flowarg/flowupdater/utils/builderapi/BuilderArgument.java index 8ad1d387..aa284156 100644 --- a/src/main/java/fr/flowarg/flowupdater/utils/builderapi/BuilderArgument.java +++ b/src/main/java/fr/flowarg/flowupdater/utils/builderapi/BuilderArgument.java @@ -50,7 +50,7 @@ public BuilderArgument(Supplier badObject, String objectName) public T get() throws BuilderException { - if(this.object == this.badObject) + if(this.object == this.badObject && this.badObject != null) throw new BuilderException("Argument" + this.objectName + " is a bad object!"); if(this.isRequired) diff --git a/src/main/java/fr/flowarg/flowupdater/versions/AbstractForgeVersion.java b/src/main/java/fr/flowarg/flowupdater/versions/AbstractForgeVersion.java index 7fdd5281..0ea7c5c4 100644 --- a/src/main/java/fr/flowarg/flowupdater/versions/AbstractForgeVersion.java +++ b/src/main/java/fr/flowarg/flowupdater/versions/AbstractForgeVersion.java @@ -1,6 +1,7 @@ package fr.flowarg.flowupdater.versions; -import fr.antoineok.flowupdater.optifineplugin.OptiFine; +import fr.flowarg.flowupdater.integrations.curseforgeplugin.CurseMod; +import fr.flowarg.flowupdater.integrations.optifineplugin.OptiFine; import fr.flowarg.flowio.FileUtils; import fr.flowarg.flowlogger.ILogger; import fr.flowarg.flowupdater.FlowUpdater; @@ -14,7 +15,7 @@ import fr.flowarg.flowupdater.download.json.OptiFineInfo; import fr.flowarg.flowupdater.utils.IOUtils; import fr.flowarg.flowupdater.utils.ModFileDeleter; -import fr.flowarg.flowupdater.utils.PluginManager; +import fr.flowarg.flowupdater.utils.IntegrationManager; import fr.flowarg.flowzipper.ZipUtils; import java.io.InputStream; @@ -40,7 +41,7 @@ public abstract class AbstractForgeVersion implements ICurseFeaturesUser, IModLo protected final CurseModPackInfo modPackInfo; protected final boolean old; - protected List allCurseMods; + protected List allCurseMods; protected URL installerUrl; protected DownloadList downloadList; protected ILogger logger; @@ -190,36 +191,31 @@ public boolean checkModLoaderEnv(Path dirToInstall) throws Exception * {@inheritDoc} */ @Override - public void installMods(Path modsDir, PluginManager pluginManager) throws Exception + public void installMods(Path modsDir, IntegrationManager integrationManager) throws Exception { this.callback.step(Step.MODS); - final boolean cursePluginLoaded = pluginManager.isCursePluginLoaded(); - final boolean optiFinePluginLoaded = pluginManager.isOptiFinePluginLoaded(); - this.installAllMods(modsDir, cursePluginLoaded); + this.installAllMods(modsDir); - Object ofObj = null; - if(optiFinePluginLoaded) + OptiFine ofObj = null; + + if(this.downloadList.getOptiFine() != null) { - if(this.downloadList.getOptiFine() != null) + ofObj = this.downloadList.getOptiFine(); + try + { + final Path optiFineFilePath = modsDir.resolve(ofObj.getName()); + + if (Files.notExists(optiFineFilePath)) IOUtils.copy(this.logger, modsDir.getParent().resolve(".op").resolve(ofObj.getName()), optiFineFilePath); + } catch (Exception e) { - final OptiFine optifine = (OptiFine)this.downloadList.getOptiFine(); - ofObj = optifine; - try - { - final Path optiFineFilePath = modsDir.resolve(optifine.getName()); - - if(Files.notExists(optiFineFilePath)) - IOUtils.copy(this.logger, modsDir.getParent().resolve(".op").resolve(optifine.getName()), optiFineFilePath); - } catch (Exception e) - { - this.logger.printStackTrace(e); - } - this.downloadList.incrementDownloaded(optifine.getSize()); - this.callback.update(this.downloadList.getDownloadedBytes(), this.downloadList.getTotalToDownloadBytes()); + this.logger.printStackTrace(e); } + this.downloadList.incrementDownloaded(ofObj.getSize()); + this.callback.update(this.downloadList.getDownloadedBytes(), this.downloadList.getTotalToDownloadBytes()); } - this.fileDeleter.delete(modsDir, this.mods, cursePluginLoaded, this.allCurseMods, optiFinePluginLoaded, ofObj); + + this.fileDeleter.delete(modsDir, this.mods, this.allCurseMods, ofObj); } protected void packPatchedInstaller(final Path tempDir, final Path tempInstallerDir) throws Exception @@ -241,9 +237,10 @@ public List getMods() /** * {@inheritDoc} + * @param allCurseMods */ @Override - public void setAllCurseMods(List allCurseMods) + public void setAllCurseMods(List allCurseMods) { this.allCurseMods = allCurseMods; } @@ -273,12 +270,6 @@ public void attachFlowUpdater(FlowUpdater flowUpdater) { this.logger.printStackTrace(e); } - - if(!this.curseMods.isEmpty() && !flowUpdater.getUpdaterOptions().isEnableCurseForgePlugin()) - this.logger.warn("You must enable the enableCurseForgePlugin option to use curse forge features!"); - - if(this.optiFineInfo != null && !flowUpdater.getUpdaterOptions().isEnableOptiFineDownloaderPlugin()) - this.logger.warn("You must enable the enableOptiFineDownloaderPlugin option to use OptiFine!"); } /** @@ -340,7 +331,7 @@ public URL getInstallerUrl() return this.installerUrl; } - public List getAllCurseMods() + public List getAllCurseMods() { return this.allCurseMods; } diff --git a/src/main/java/fr/flowarg/flowupdater/versions/FabricVersion.java b/src/main/java/fr/flowarg/flowupdater/versions/FabricVersion.java index 7dc7016a..27b63899 100644 --- a/src/main/java/fr/flowarg/flowupdater/versions/FabricVersion.java +++ b/src/main/java/fr/flowarg/flowupdater/versions/FabricVersion.java @@ -14,9 +14,10 @@ import fr.flowarg.flowupdater.download.json.CurseFileInfo; import fr.flowarg.flowupdater.download.json.CurseModPackInfo; import fr.flowarg.flowupdater.download.json.Mod; +import fr.flowarg.flowupdater.integrations.curseforgeplugin.CurseMod; import fr.flowarg.flowupdater.utils.IOUtils; import fr.flowarg.flowupdater.utils.ModFileDeleter; -import fr.flowarg.flowupdater.utils.PluginManager; +import fr.flowarg.flowupdater.utils.IntegrationManager; import fr.flowarg.flowupdater.utils.builderapi.BuilderArgument; import fr.flowarg.flowupdater.utils.builderapi.BuilderException; import fr.flowarg.flowupdater.utils.builderapi.IBuilder; @@ -45,7 +46,7 @@ public class FabricVersion implements ICurseFeaturesUser, IModLoaderVersion private final String fabricVersion; private final List curseMods; private final ModFileDeleter fileDeleter; - private List allCurseMods; + private List allCurseMods; private final String installerVersion; private final CurseModPackInfo modPackInfo; @@ -276,13 +277,12 @@ public boolean checkModLoaderEnv(Path dirToInstall) throws Exception * {@inheritDoc} */ @Override - public void installMods(Path modsDir, PluginManager pluginManager) throws Exception + public void installMods(Path modsDir, IntegrationManager integrationManager) throws Exception { this.callback.step(Step.MODS); - final boolean cursePluginLoaded = pluginManager.isCursePluginLoaded(); - this.installAllMods(modsDir, cursePluginLoaded); - this.fileDeleter.delete(modsDir, this.mods, cursePluginLoaded, this.allCurseMods, false, null); + this.installAllMods(modsDir); + this.fileDeleter.delete(modsDir, this.mods, this.allCurseMods, null); } public ModFileDeleter getFileDeleter() { @@ -304,9 +304,6 @@ public void attachFlowUpdater(FlowUpdater flowUpdater) } catch (Exception e) { this.logger.printStackTrace(e); } - - if(!this.curseMods.isEmpty() && !flowUpdater.getUpdaterOptions().isEnableCurseForgePlugin()) - this.logger.warn("You must enable the enableCurseForgePlugin option to use curse forge features!"); } /** @@ -351,15 +348,16 @@ public URL getInstallerUrl() { return this.installerUrl; } - public List getAllCurseMods() { + public List getAllCurseMods() { return this.allCurseMods; } /** * {@inheritDoc} + * @param allCurseMods */ @Override - public void setAllCurseMods(List allCurseMods) { + public void setAllCurseMods(List allCurseMods) { this.allCurseMods = allCurseMods; } diff --git a/src/main/java/fr/flowarg/flowupdater/versions/IModLoaderVersion.java b/src/main/java/fr/flowarg/flowupdater/versions/IModLoaderVersion.java index 98f66e4c..9493f694 100644 --- a/src/main/java/fr/flowarg/flowupdater/versions/IModLoaderVersion.java +++ b/src/main/java/fr/flowarg/flowupdater/versions/IModLoaderVersion.java @@ -2,12 +2,11 @@ import fr.flowarg.flowlogger.ILogger; import fr.flowarg.flowupdater.FlowUpdater; -import fr.flowarg.flowupdater.curseforgeplugin.CurseMod; import fr.flowarg.flowupdater.download.DownloadList; import fr.flowarg.flowupdater.download.IProgressCallback; import fr.flowarg.flowupdater.download.json.Mod; import fr.flowarg.flowupdater.utils.IOUtils; -import fr.flowarg.flowupdater.utils.PluginManager; +import fr.flowarg.flowupdater.utils.IntegrationManager; import java.io.InputStream; import java.net.MalformedURLException; @@ -49,10 +48,10 @@ public interface IModLoaderVersion /** * Install all mods in the mods' directory. * @param modsDir mods directory. - * @param pluginManager used to check loaded plugins. + * @param integrationManager used to check loaded plugins. * @throws Exception if an I/O error occurred. */ - void installMods(Path modsDir, PluginManager pluginManager) throws Exception; + void installMods(Path modsDir, IntegrationManager integrationManager) throws Exception; /** * Get all processed mods / mods to process. @@ -60,7 +59,7 @@ public interface IModLoaderVersion */ List getMods(); - default void installAllMods(Path modsDir, boolean cursePluginLoaded) + default void installAllMods(Path modsDir) { this.getDownloadList().getMods().forEach(mod -> { try @@ -77,10 +76,7 @@ default void installAllMods(Path modsDir, boolean cursePluginLoaded) this.getCallback().update(this.getDownloadList().getDownloadedBytes(), this.getDownloadList().getTotalToDownloadBytes()); }); - if(!cursePluginLoaded) return; - - this.getDownloadList().getCurseMods().forEach(obj -> { - final CurseMod curseMod = (CurseMod)obj; + this.getDownloadList().getCurseMods().forEach(curseMod -> { try { final Path modFilePath = modsDir.resolve(curseMod.getName());