mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-04 00:45:57 +00:00
Merge remote-tracking branch 'origin/ver/6.0.0' into ver/6.0.0
This commit is contained in:
commit
a1306c88c0
@ -24,20 +24,21 @@ import com.dfsek.terra.api.inject.annotations.Inject;
|
|||||||
|
|
||||||
|
|
||||||
public class ManifestAddon implements BaseAddon {
|
public class ManifestAddon implements BaseAddon {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ManifestAddon.class);
|
||||||
private final AddonManifest manifest;
|
private final AddonManifest manifest;
|
||||||
|
|
||||||
private final List<AddonInitializer> initializers;
|
private final List<AddonInitializer> initializers;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Platform platform;
|
private Platform platform;
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ManifestAddon.class);
|
|
||||||
|
|
||||||
public ManifestAddon(AddonManifest manifest, List<AddonInitializer> initializers) {
|
public ManifestAddon(AddonManifest manifest, List<AddonInitializer> initializers) {
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.initializers = initializers;
|
this.initializers = initializers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AddonManifest getManifest() {
|
||||||
|
return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getID() {
|
public String getID() {
|
||||||
return manifest.getID();
|
return manifest.getID();
|
||||||
@ -50,7 +51,7 @@ public class ManifestAddon implements BaseAddon {
|
|||||||
Injector<Platform> platformInjector = Injector.get(platform);
|
Injector<Platform> platformInjector = Injector.get(platform);
|
||||||
platformInjector.addExplicitTarget(Platform.class);
|
platformInjector.addExplicitTarget(Platform.class);
|
||||||
|
|
||||||
logger.info("Initializing addon {}", getID());
|
logger.debug("Initializing addon {}", getID());
|
||||||
|
|
||||||
initializers.forEach(initializer -> {
|
initializers.forEach(initializer -> {
|
||||||
logger.debug("Invoking entry point {}", initializer.getClass());
|
logger.debug("Invoking entry point {}", initializer.getClass());
|
||||||
@ -60,10 +61,6 @@ public class ManifestAddon implements BaseAddon {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddonManifest getManifest() {
|
|
||||||
return manifest;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, VersionRange> getDependencies() {
|
public Map<String, VersionRange> getDependencies() {
|
||||||
return manifest.getDependencies();
|
return manifest.getDependencies();
|
||||||
|
@ -13,16 +13,21 @@ import ca.solostudios.strata.version.VersionRange;
|
|||||||
import com.dfsek.tectonic.exception.LoadException;
|
import com.dfsek.tectonic.exception.LoadException;
|
||||||
import com.dfsek.tectonic.loading.ConfigLoader;
|
import com.dfsek.tectonic.loading.ConfigLoader;
|
||||||
import com.dfsek.tectonic.yaml.YamlConfiguration;
|
import com.dfsek.tectonic.yaml.YamlConfiguration;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.file.FileVisitOption;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||||
import com.dfsek.terra.addons.manifest.impl.config.AddonManifest;
|
import com.dfsek.terra.addons.manifest.impl.config.AddonManifest;
|
||||||
@ -32,75 +37,76 @@ import com.dfsek.terra.addons.manifest.impl.config.loaders.VersionRangeLoader;
|
|||||||
import com.dfsek.terra.addons.manifest.impl.exception.AddonException;
|
import com.dfsek.terra.addons.manifest.impl.exception.AddonException;
|
||||||
import com.dfsek.terra.addons.manifest.impl.exception.ManifestException;
|
import com.dfsek.terra.addons.manifest.impl.exception.ManifestException;
|
||||||
import com.dfsek.terra.addons.manifest.impl.exception.ManifestNotPresentException;
|
import com.dfsek.terra.addons.manifest.impl.exception.ManifestNotPresentException;
|
||||||
import com.dfsek.terra.api.Platform;
|
|
||||||
import com.dfsek.terra.api.addon.bootstrap.BootstrapBaseAddon;
|
import com.dfsek.terra.api.addon.bootstrap.BootstrapBaseAddon;
|
||||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
|
|
||||||
public class ManifestAddonLoader implements BootstrapBaseAddon<ManifestAddon> {
|
public class ManifestAddonLoader implements BootstrapBaseAddon<ManifestAddon> {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ManifestAddonLoader.class);
|
private static final Logger logger = LoggerFactory.getLogger(ManifestAddonLoader.class);
|
||||||
|
|
||||||
private static final Version VERSION = Versions.getVersion(1, 0, 0);
|
private static final Version VERSION = Versions.getVersion(1, 0, 0);
|
||||||
|
|
||||||
|
private final ConfigLoader manifestLoader = new ConfigLoader()
|
||||||
|
.registerLoader(Version.class, new VersionLoader())
|
||||||
|
.registerLoader(VersionRange.class, new VersionRangeLoader())
|
||||||
|
.registerLoader(WebsiteConfig.class, WebsiteConfig::new);
|
||||||
|
|
||||||
|
public ManifestAddon loadAddon(Path addonPath) {
|
||||||
|
try(JarFile jar = new JarFile(addonPath.toFile())) {
|
||||||
|
logger.debug("Loading addon from JAR {}", addonPath);
|
||||||
|
|
||||||
|
JarEntry manifestEntry = jar.getJarEntry("terra.addon.yml");
|
||||||
|
if(manifestEntry == null) {
|
||||||
|
throw new ManifestNotPresentException("Addon " + addonPath + " does not contain addon manifest.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//noinspection NestedTryStatement
|
||||||
|
try {
|
||||||
|
AddonManifest manifest = manifestLoader.load(new AddonManifest(),
|
||||||
|
new YamlConfiguration(jar.getInputStream(manifestEntry),
|
||||||
|
"terra.addon.yml"));
|
||||||
|
|
||||||
|
logger.debug("Loading addon {}@{}", manifest.getID(), manifest.getVersion());
|
||||||
|
|
||||||
|
@SuppressWarnings({ "IOResourceOpenedButNotSafelyClosed", "resource" })
|
||||||
|
ManifestAddonClassLoader loader = new ManifestAddonClassLoader(new URL[]{ addonPath.toUri().toURL() },
|
||||||
|
getClass().getClassLoader());
|
||||||
|
|
||||||
|
List<AddonInitializer> initializers = manifest.getEntryPoints().stream().map(entryPoint -> {
|
||||||
|
try {
|
||||||
|
Object in = loader.loadClass(entryPoint).getConstructor().newInstance();
|
||||||
|
if(!(in instanceof AddonInitializer)) {
|
||||||
|
throw new AddonException(in.getClass() + " does not extend " + AddonInitializer.class);
|
||||||
|
}
|
||||||
|
return (AddonInitializer) in;
|
||||||
|
} catch(InvocationTargetException e) {
|
||||||
|
throw new AddonException("Exception occurred while instantiating addon", e);
|
||||||
|
} catch(NoSuchMethodException | IllegalAccessException | InstantiationException e) {
|
||||||
|
throw new AddonException(String.format("No valid default constructor found in entry point %s", entryPoint), e);
|
||||||
|
} catch(ClassNotFoundException e) {
|
||||||
|
throw new AddonException(String.format("Entry point %s not found in JAR.", entryPoint), e);
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
return new ManifestAddon(manifest, initializers);
|
||||||
|
|
||||||
|
} catch(LoadException e) {
|
||||||
|
throw new ManifestException("Failed to load addon manifest", e);
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<ManifestAddon> loadAddons(Path addonsFolder, ClassLoader parent) {
|
public Iterable<ManifestAddon> loadAddons(Path addonsFolder, ClassLoader parent) {
|
||||||
LOGGER.info("Loading addons...");
|
logger.debug("Loading addons...");
|
||||||
|
|
||||||
ConfigLoader manifestLoader = new ConfigLoader();
|
try(Stream<Path> addons = Files.walk(addonsFolder, 1, FileVisitOption.FOLLOW_LINKS)) {
|
||||||
manifestLoader.registerLoader(Version.class, new VersionLoader())
|
return addons.filter(path -> path.toFile().isFile())
|
||||||
.registerLoader(VersionRange.class, new VersionRangeLoader())
|
.filter(path -> path.toFile().canRead())
|
||||||
.registerLoader(WebsiteConfig.class, WebsiteConfig::new);
|
.filter(path -> path.toString().endsWith(".jar"))
|
||||||
|
.map(this::loadAddon)
|
||||||
try {
|
.collect(Collectors.toList());
|
||||||
return Files.walk(addonsFolder, 1)
|
|
||||||
.filter(path -> path.toFile().isFile() && path.toString().endsWith(".jar"))
|
|
||||||
.map(path -> {
|
|
||||||
try {
|
|
||||||
LOGGER.debug("Loading addon from JAR {}", path);
|
|
||||||
JarFile jar = new JarFile(path.toFile());
|
|
||||||
|
|
||||||
JarEntry manifestEntry = jar.getJarEntry("terra.addon.yml");
|
|
||||||
if(manifestEntry == null) {
|
|
||||||
throw new ManifestNotPresentException("Addon " + path + " does not contain addon manifest.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
AddonManifest manifest = manifestLoader.load(new AddonManifest(),
|
|
||||||
new YamlConfiguration(jar.getInputStream(manifestEntry),
|
|
||||||
"terra.addon.yml"));
|
|
||||||
|
|
||||||
LOGGER.info("Loading addon {}", manifest.getID());
|
|
||||||
|
|
||||||
ManifestAddonClassLoader loader = new ManifestAddonClassLoader(new URL[]{ path.toUri().toURL() },
|
|
||||||
getClass().getClassLoader());
|
|
||||||
|
|
||||||
return new ManifestAddon(manifest, manifest.getEntryPoints().stream().map(entryPoint -> {
|
|
||||||
try {
|
|
||||||
Object in = loader.loadClass(entryPoint).getConstructor().newInstance();
|
|
||||||
if(!(in instanceof AddonInitializer)) {
|
|
||||||
throw new AddonException(in.getClass() + " does not extend " + AddonInitializer.class);
|
|
||||||
}
|
|
||||||
return (AddonInitializer) in;
|
|
||||||
} catch(InvocationTargetException e) {
|
|
||||||
throw new AddonException("Exception occurred while instantiating addon: ", e);
|
|
||||||
} catch(NoSuchMethodException | IllegalAccessException | InstantiationException e) {
|
|
||||||
throw new AddonException("No valid default constructor found in entry point " + entryPoint);
|
|
||||||
} catch(ClassNotFoundException e) {
|
|
||||||
throw new AddonException("Entry point " + entryPoint + " not found in JAR.");
|
|
||||||
}
|
|
||||||
}).collect(Collectors.toList()));
|
|
||||||
|
|
||||||
} catch(LoadException e) {
|
|
||||||
throw new ManifestException("Failed to load addon manifest", e);
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
throw new UncheckedIOException(e);
|
throw new UncheckedIOException(e);
|
||||||
}
|
}
|
||||||
|
@ -185,12 +185,30 @@ public abstract class AbstractPlatform implements Platform {
|
|||||||
platformInjector.addExplicitTarget(Platform.class);
|
platformInjector.addExplicitTarget(Platform.class);
|
||||||
|
|
||||||
bootstrapAddonLoader.loadAddons(addonsFolder, getClass().getClassLoader())
|
bootstrapAddonLoader.loadAddons(addonsFolder, getClass().getClassLoader())
|
||||||
.forEach(bootstrap -> {
|
.forEach(bootstrapAddon -> {
|
||||||
platformInjector.inject(bootstrap);
|
platformInjector.inject(bootstrapAddon);
|
||||||
bootstrap.loadAddons(addonsFolder, getClass().getClassLoader())
|
|
||||||
.forEach(addonList::add);
|
bootstrapAddon.loadAddons(addonsFolder, getClass().getClassLoader())
|
||||||
|
.forEach(addonList::add);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(logger.isInfoEnabled()) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("Loading ")
|
||||||
|
.append(addonList.size())
|
||||||
|
.append(" Terra addons:");
|
||||||
|
|
||||||
|
for(BaseAddon addon : addonList) {
|
||||||
|
builder.append("\n ")
|
||||||
|
.append("- ")
|
||||||
|
.append(addon.getID())
|
||||||
|
.append("@")
|
||||||
|
.append(addon.getVersion().getFormatted());
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(builder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
DependencySorter sorter = new DependencySorter();
|
DependencySorter sorter = new DependencySorter();
|
||||||
addonList.forEach(sorter::add);
|
addonList.forEach(sorter::add);
|
||||||
sorter.sort().forEach(addon -> {
|
sorter.sort().forEach(addon -> {
|
||||||
@ -199,18 +217,17 @@ public abstract class AbstractPlatform implements Platform {
|
|||||||
addonRegistry.register(addon.getID(), addon);
|
addonRegistry.register(addon.getID(), addon);
|
||||||
});
|
});
|
||||||
|
|
||||||
eventManager
|
eventManager.getHandler(FunctionalEventHandler.class)
|
||||||
.getHandler(FunctionalEventHandler.class)
|
.register(internalAddon, PlatformInitializationEvent.class)
|
||||||
.register(internalAddon, PlatformInitializationEvent.class)
|
.then(event -> {
|
||||||
.then(event -> {
|
logger.info("Loading config packs...");
|
||||||
logger.info("Loading config packs...");
|
configRegistry.loadAll(this);
|
||||||
getRawConfigRegistry().loadAll(this);
|
logger.info("Loaded packs.");
|
||||||
logger.info("Loaded packs.");
|
})
|
||||||
})
|
.global();
|
||||||
.global();
|
|
||||||
|
|
||||||
|
|
||||||
logger.info("Loaded addons.");
|
logger.info("Terra addons successfully loaded.");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CommandUtil.registerAll(manager);
|
CommandUtil.registerAll(manager);
|
||||||
|
@ -26,10 +26,12 @@ import java.io.IOException;
|
|||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.file.FileVisitOption;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.dfsek.terra.addon.exception.AddonLoadException;
|
import com.dfsek.terra.addon.exception.AddonLoadException;
|
||||||
import com.dfsek.terra.api.Platform;
|
import com.dfsek.terra.api.Platform;
|
||||||
@ -44,44 +46,54 @@ public class BootstrapAddonLoader implements BootstrapBaseAddon<BootstrapBaseAdd
|
|||||||
|
|
||||||
public BootstrapAddonLoader(Platform platform) { this.platform = platform; }
|
public BootstrapAddonLoader(Platform platform) { this.platform = platform; }
|
||||||
|
|
||||||
|
private BootstrapBaseAddon<?> loadAddon(Path addonPath, ClassLoader parent) {
|
||||||
|
logger.debug("Loading bootstrap addon from JAR {}", addonPath);
|
||||||
|
try(JarFile jar = new JarFile(addonPath.toFile())) {
|
||||||
|
String entry = jar.getManifest().getMainAttributes().getValue("Bootstrap-Addon-Entry-Point");
|
||||||
|
|
||||||
|
if(entry == null) {
|
||||||
|
throw new AddonLoadException("No Bootstrap-Addon-Entry-Point attribute defined in addon manifest.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection NestedTryStatement
|
||||||
|
try {
|
||||||
|
@SuppressWarnings({ "resource", "IOResourceOpenedButNotSafelyClosed" })
|
||||||
|
AddonClassLoader loader = new AddonClassLoader(new URL[]{ addonPath.toUri().toURL() }, parent);
|
||||||
|
|
||||||
|
Object addonObject = loader.loadClass(entry).getConstructor().newInstance();
|
||||||
|
|
||||||
|
if(!(addonObject instanceof BootstrapBaseAddon<?> addon)) {
|
||||||
|
throw new AddonLoadException(
|
||||||
|
addonObject.getClass() + " does not extend " + BootstrapBaseAddon.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Loaded bootstrap addon {}@{} with entry point {}",
|
||||||
|
addon.getID(), addon.getVersion().getFormatted(), addonObject.getClass());
|
||||||
|
return addon;
|
||||||
|
} catch(InvocationTargetException e) {
|
||||||
|
throw new AddonLoadException("Exception occurred while instantiating addon", e);
|
||||||
|
} catch(NoSuchMethodException | IllegalAccessException | InstantiationException e) {
|
||||||
|
throw new AddonLoadException(String.format("No valid default constructor found in entry point %s", entry), e);
|
||||||
|
} catch(ClassNotFoundException | NoClassDefFoundError e) {
|
||||||
|
throw new AddonLoadException(String.format("Entry point %s not found in JAR.", entry), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<BootstrapBaseAddon<?>> loadAddons(Path addonsFolder, ClassLoader parent) {
|
public Iterable<BootstrapBaseAddon<?>> loadAddons(Path addonsFolder, ClassLoader parent) {
|
||||||
Path bootstrapAddons = addonsFolder.resolve("bootstrap");
|
Path bootstrapFolder = addonsFolder.resolve("bootstrap");
|
||||||
logger.info("Loading bootstrap addons from {}", bootstrapAddons);
|
logger.debug("Loading bootstrap addons from {}", bootstrapFolder);
|
||||||
try {
|
|
||||||
return Files.walk(bootstrapAddons, 1)
|
|
||||||
.filter(path -> path.toFile().isFile() && path.toString().endsWith(".jar"))
|
|
||||||
.map(path -> {
|
|
||||||
try {
|
|
||||||
logger.info("Loading bootstrap addon from JAR {}", path);
|
|
||||||
JarFile jar = new JarFile(path.toFile());
|
|
||||||
String entry = jar.getManifest().getMainAttributes().getValue("Bootstrap-Addon-Entry-Point");
|
|
||||||
|
|
||||||
if(entry == null) {
|
try(Stream<Path> bootstrapAddons = Files.walk(bootstrapFolder, 1, FileVisitOption.FOLLOW_LINKS)) {
|
||||||
throw new AddonLoadException("No Bootstrap-Addon-Entry-Point attribute defined in addon manifest.");
|
return bootstrapAddons.filter(path -> path.toFile().isFile())
|
||||||
}
|
.filter(path -> path.toFile().canRead())
|
||||||
|
.filter(path -> path.toString().endsWith(".jar"))
|
||||||
AddonClassLoader loader = new AddonClassLoader(new URL[]{ path.toUri().toURL() }, parent);
|
.map(path -> loadAddon(path, parent))
|
||||||
|
.collect(Collectors.toList());
|
||||||
try {
|
|
||||||
Object in = loader.loadClass(entry).getConstructor().newInstance();
|
|
||||||
if(!(in instanceof BootstrapBaseAddon)) {
|
|
||||||
throw new AddonLoadException(in.getClass() + " does not extend " + BootstrapBaseAddon.class);
|
|
||||||
}
|
|
||||||
logger.info("Loaded bootstrap addon {}", ((BootstrapBaseAddon<?>) in).getID());
|
|
||||||
return (BootstrapBaseAddon<?>) in;
|
|
||||||
} catch(InvocationTargetException e) {
|
|
||||||
throw new AddonLoadException("Exception occurred while instantiating addon: ", e);
|
|
||||||
} catch(NoSuchMethodException | IllegalAccessException | InstantiationException e) {
|
|
||||||
throw new AddonLoadException("No valid default constructor found in entry point " + entry);
|
|
||||||
} catch(ClassNotFoundException e) {
|
|
||||||
throw new AddonLoadException("Entry point " + entry + " not found in JAR.");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch(IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
throw new UncheckedIOException(e);
|
throw new UncheckedIOException(e);
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,10 @@ dependencies {
|
|||||||
shadedApi(project(":common:implementation:base"))
|
shadedApi(project(":common:implementation:base"))
|
||||||
|
|
||||||
shadedApi("org.slf4j:slf4j-api:1.7.32") {
|
shadedApi("org.slf4j:slf4j-api:1.7.32") {
|
||||||
because("Minecraft 1.17+ includes slf4j 1.8.0-beta4, so we need to shade it for other versions.")
|
because("Minecraft 1.17+ includes slf4j 1.8.0-beta4, but we want slf4j 1.7.")
|
||||||
}
|
}
|
||||||
shadedImplementation("org.apache.logging.log4j:log4j-slf4j-impl:2.14.1") {
|
shaded("org.apache.logging.log4j:log4j-slf4j-impl:2.14.1") {
|
||||||
because("Minecraft 1.17+ includes slf4j 1.8.0-beta4, so we need to shade it for other versions.")
|
because("Minecraft 1.17+ includes slf4j 1.8.0-beta4, but we want slf4j 1.7.")
|
||||||
exclude("org.apache.logging.log4j")
|
exclude("org.apache.logging.log4j")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user