2022-05-06 13:39:00 +02:00
|
|
|
package com.falsepattern.lib.dependencies;
|
|
|
|
|
|
2022-05-06 23:53:11 +02:00
|
|
|
import com.falsepattern.lib.StableAPI;
|
2022-06-10 00:09:13 +02:00
|
|
|
import com.falsepattern.lib.internal.*;
|
|
|
|
|
|
2022-06-08 16:01:06 +02:00
|
|
|
import java.io.BufferedOutputStream;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.net.URL;
|
2022-06-08 16:06:35 +02:00
|
|
|
import java.nio.file.Files;
|
2022-06-08 16:01:06 +02:00
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Set;
|
2022-07-23 00:00:17 +02:00
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
2022-06-09 22:18:49 +02:00
|
|
|
|
2022-06-15 18:39:15 +02:00
|
|
|
import com.falsepattern.lib.util.FileUtil;
|
2022-06-10 00:09:13 +02:00
|
|
|
import lombok.*;
|
2022-05-06 13:39:00 +02:00
|
|
|
import net.minecraft.launchwrapper.LaunchClassLoader;
|
|
|
|
|
|
|
|
|
|
|
2022-05-06 23:53:11 +02:00
|
|
|
@StableAPI(since = "0.6.0")
|
2022-05-06 13:39:00 +02:00
|
|
|
public class DependencyLoader {
|
|
|
|
|
|
|
|
|
|
private static final Map<String, Version> loadedLibraries = new HashMap<>();
|
|
|
|
|
private static final Map<String, String> loadedLibraryMods = new HashMap<>();
|
|
|
|
|
private static final Set<String> mavenRepositories = new HashSet<>();
|
|
|
|
|
|
|
|
|
|
public static void addMavenRepo(String url) {
|
|
|
|
|
mavenRepositories.add(url);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-08 18:57:08 +02:00
|
|
|
@Builder
|
2022-06-10 00:09:13 +02:00
|
|
|
public static void loadLibrary(@NonNull String loadingModId,
|
|
|
|
|
@NonNull String groupId,
|
|
|
|
|
@NonNull String artifactId,
|
2022-06-08 16:01:06 +02:00
|
|
|
@NonNull Version minVersion,
|
|
|
|
|
Version maxVersion,
|
|
|
|
|
@NonNull Version preferredVersion,
|
|
|
|
|
String regularSuffix,
|
|
|
|
|
String devSuffix) {
|
2022-05-06 13:39:00 +02:00
|
|
|
val suffix = FalsePatternLib.isDeveloperEnvironment() ? devSuffix : regularSuffix;
|
2022-06-10 00:09:13 +02:00
|
|
|
val artifactLogName = String.format("%s:%s:%s%s", groupId, artifactId, preferredVersion, suffix != null ? "-" + suffix : "");
|
2022-06-08 16:01:06 +02:00
|
|
|
FalsePatternLib.getLog()
|
2022-06-10 00:09:13 +02:00
|
|
|
.info("Adding library {}, requested by mod {}", artifactLogName,
|
2022-06-08 16:01:06 +02:00
|
|
|
loadingModId);
|
2022-05-06 13:39:00 +02:00
|
|
|
var artifact = groupId + ":" + artifactId + ":" + suffix;
|
|
|
|
|
if (loadedLibraries.containsKey(artifact)) {
|
|
|
|
|
val currentVer = loadedLibraries.get(artifact);
|
2022-06-08 16:01:06 +02:00
|
|
|
if (currentVer.equals(preferredVersion)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-05-06 13:39:00 +02:00
|
|
|
val rangeString = "(minimum: " + minVersion + (maxVersion == null ? "" : ", maximum: " + maxVersion) + ")";
|
|
|
|
|
if (minVersion.compareTo(currentVer) > 0 || (maxVersion != null && maxVersion.compareTo(currentVer) < 0)) {
|
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
|
|
|
FalsePatternLib.getLog().fatal("ALERT VVVVVVVVVVVV ALERT");
|
|
|
|
|
}
|
2022-06-08 16:01:06 +02:00
|
|
|
FalsePatternLib.getLog()
|
|
|
|
|
.fatal("Library {}:{}{} already loaded with version {}, " +
|
|
|
|
|
"but a version in the range {} was requested! Thing may go horribly wrong! " +
|
|
|
|
|
"Requested by mod: {}, previously loaded by mod: {}",
|
|
|
|
|
groupId,
|
|
|
|
|
artifactId,
|
|
|
|
|
suffix != null ? ":" + suffix : "",
|
|
|
|
|
currentVer,
|
|
|
|
|
rangeString,
|
|
|
|
|
loadingModId,
|
|
|
|
|
loadedLibraryMods.get(artifact));
|
2022-05-06 13:39:00 +02:00
|
|
|
for (int i = 0; i < 16; i++) {
|
|
|
|
|
FalsePatternLib.getLog().fatal("ALERT ^^^^^^^^^^^^ ALERT");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-06-08 16:01:06 +02:00
|
|
|
FalsePatternLib.getLog()
|
|
|
|
|
.info("Attempted loading of library {}:{}{} with preferred version {}, " +
|
|
|
|
|
"but version {} was already loaded, which matched the range {}. This is not an " +
|
|
|
|
|
"error. " + "Requested by mod: {}, previously loaded by mod: {}",
|
|
|
|
|
groupId,
|
|
|
|
|
artifactId,
|
|
|
|
|
suffix != null ? ":" + suffix : "",
|
|
|
|
|
preferredVersion,
|
|
|
|
|
currentVer,
|
|
|
|
|
rangeString,
|
|
|
|
|
loadingModId,
|
|
|
|
|
loadedLibraryMods.get(artifact));
|
2022-05-06 13:39:00 +02:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-15 18:39:15 +02:00
|
|
|
val modsDir = new File(FileUtil.getMinecraftHome(), "mods");
|
2022-06-08 16:01:06 +02:00
|
|
|
val mavenJarName =
|
|
|
|
|
String.format("%s-%s%s.jar", artifactId, preferredVersion, (suffix != null) ? ("-" + suffix) : "");
|
2022-05-06 13:39:00 +02:00
|
|
|
val jarName = groupId + "-" + mavenJarName;
|
|
|
|
|
val libDir = new File(modsDir, "falsepattern");
|
|
|
|
|
if (!libDir.exists()) {
|
2022-06-08 16:06:35 +02:00
|
|
|
if (!libDir.mkdirs()) {
|
|
|
|
|
FalsePatternLib.getLog().fatal("Failed to create directory {}", libDir);
|
|
|
|
|
throw new RuntimeException("Failed to create directory " + libDir);
|
|
|
|
|
}
|
2022-05-06 13:39:00 +02:00
|
|
|
}
|
|
|
|
|
val file = new File(libDir, jarName);
|
|
|
|
|
if (file.exists()) {
|
|
|
|
|
try {
|
|
|
|
|
addToClasspath(file);
|
|
|
|
|
loadedLibraries.put(artifact, preferredVersion);
|
2022-06-08 16:01:06 +02:00
|
|
|
FalsePatternLib.getLog()
|
2022-06-10 00:09:13 +02:00
|
|
|
.info("Library {} successfully loaded from disk!", artifactLogName);
|
2022-05-06 13:39:00 +02:00
|
|
|
return;
|
|
|
|
|
} catch (RuntimeException e) {
|
2022-06-08 16:01:06 +02:00
|
|
|
FalsePatternLib.getLog()
|
2022-06-10 00:09:13 +02:00
|
|
|
.warn("Failed to load library {} from file! Redownloading...", artifactLogName);
|
2022-06-08 16:06:35 +02:00
|
|
|
if (!file.delete()) {
|
|
|
|
|
FalsePatternLib.getLog().fatal("Failed to delete file {}", file);
|
|
|
|
|
throw new RuntimeException("Failed to delete file " + file);
|
|
|
|
|
}
|
2022-05-06 13:39:00 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-06-09 22:18:49 +02:00
|
|
|
if (!LibraryConfig.ENABLE_LIBRARY_DOWNLOADS) {
|
|
|
|
|
val errorMessage = "Failed to load library " + groupId + ":" + artifactId + ":" + preferredVersion +
|
2022-06-10 00:09:13 +02:00
|
|
|
((suffix != null) ? ":" + suffix : "") + ": " + Tags.MODNAME +
|
|
|
|
|
" library downloading has been disabled in the config, and the library is not present " +
|
|
|
|
|
"on disk! Requested by mod: " + loadingModId;
|
2022-06-09 22:18:49 +02:00
|
|
|
FalsePatternLib.getLog().fatal(errorMessage);
|
|
|
|
|
throw new IllegalStateException(errorMessage);
|
|
|
|
|
}
|
2022-06-08 16:01:06 +02:00
|
|
|
for (var repo : mavenRepositories) {
|
2022-05-06 13:39:00 +02:00
|
|
|
try {
|
2022-06-08 16:01:06 +02:00
|
|
|
if (!repo.endsWith("/")) {
|
|
|
|
|
repo = repo + "/";
|
|
|
|
|
}
|
|
|
|
|
val url = new URL(String.format("%s%s/%s/%s/%s",
|
|
|
|
|
repo,
|
|
|
|
|
groupId.replace('.', '/'),
|
|
|
|
|
artifactId,
|
|
|
|
|
preferredVersion,
|
|
|
|
|
mavenJarName));
|
2022-06-10 00:09:13 +02:00
|
|
|
String finalRepo = repo;
|
2022-07-23 00:00:17 +02:00
|
|
|
val success = new AtomicBoolean(false);
|
2022-06-10 00:09:13 +02:00
|
|
|
Internet.connect(url, (ex) -> {
|
2022-06-08 16:01:06 +02:00
|
|
|
FalsePatternLib.getLog()
|
2022-06-10 00:09:13 +02:00
|
|
|
.info("Artifact {} could not be downloaded from repo {}: {}",
|
|
|
|
|
artifactLogName,
|
|
|
|
|
finalRepo,
|
|
|
|
|
ex.getMessage());
|
|
|
|
|
}, (input) -> {
|
|
|
|
|
FalsePatternLib.getLog()
|
|
|
|
|
.info("Downloading {} from {}",
|
|
|
|
|
artifactLogName,
|
|
|
|
|
finalRepo);
|
|
|
|
|
download(input, file);
|
|
|
|
|
FalsePatternLib.getLog().info("Downloaded {}", artifactLogName);
|
|
|
|
|
loadedLibraries.put(artifact, preferredVersion);
|
|
|
|
|
loadedLibraryMods.put(artifact, loadingModId);
|
|
|
|
|
addToClasspath(file);
|
2022-07-23 00:00:17 +02:00
|
|
|
success.set(true);
|
2022-06-10 00:09:13 +02:00
|
|
|
});
|
2022-07-23 00:00:17 +02:00
|
|
|
if (success.get()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-08 16:01:06 +02:00
|
|
|
} catch (IOException ignored) {
|
|
|
|
|
}
|
2022-05-06 13:39:00 +02:00
|
|
|
}
|
2022-06-08 16:01:06 +02:00
|
|
|
val errorMessage = "Failed to download library " + groupId + ":" + artifactId + ":" + preferredVersion +
|
|
|
|
|
((suffix != null) ? ":" + suffix : "") + " from any repository! Requested by mod: " +
|
|
|
|
|
loadingModId;
|
2022-05-06 13:39:00 +02:00
|
|
|
FalsePatternLib.getLog().fatal(errorMessage);
|
|
|
|
|
throw new IllegalStateException(errorMessage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void addToClasspath(File file) {
|
|
|
|
|
try {
|
|
|
|
|
val cl = (LaunchClassLoader) DependencyLoader.class.getClassLoader();
|
|
|
|
|
cl.addURL(file.toURI().toURL());
|
|
|
|
|
FalsePatternLib.getLog().info("Injected file {} into classpath!", file.getPath());
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
throw new RuntimeException("Failed to add library to classpath: " + file.getAbsolutePath(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-10 00:09:13 +02:00
|
|
|
@SneakyThrows
|
|
|
|
|
private static void download(InputStream is, File target) {
|
2022-06-08 16:01:06 +02:00
|
|
|
if (target.exists()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-10 00:09:13 +02:00
|
|
|
Internet.transferAndClose(is, new BufferedOutputStream(Files.newOutputStream(target.toPath())));
|
2022-05-06 13:39:00 +02:00
|
|
|
}
|
|
|
|
|
}
|