-
-
Notifications
You must be signed in to change notification settings - Fork 3
Sponge
Henri Schubin edited this page Jul 5, 2024
·
12 revisions
Due to Sponge not exposing a way to load dependencies in during runtime, we need to have our own ClassLoader load them in, for that we'll need that ClassLoader to load in our plugin's code (that's going to use those dependencies) as well. We also need to make a interface that can post state changes to the bootstrap from the loader class.
This guide is for Gradle, that is also the only way to use the DependencyDownload metadata generation plugin
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '7.0.0'
}
repositories {
mavenCentral()
maven {
url 'https://repo.spongepowered.org'
}
}
dependencies {
compileOnly 'org.spongepowered:spongeapi:7.3.0'
annotationProcessor 'org.spongepowered:spongeapi:7.3.0'
+ implementation 'dev.vankka:dependencydownload-jarinjar-loader:VERSION'
}
jar {
finalizedBy shadowJar
}
shadowJar {
+ from {
+ findProject(':sponge').tasks.shadowJar.archiveFile
+ }
}
If the main part of the plugin is the root project, you can use rootProject
instead of findProject(':sponge')
package com.example.sponge.bootstrap;
...
public interface ISpongeBootstrap {
void onServerStart(GameStartedServerEvent event);
}
package com.example.sponge;
...
@Plugin(
id = "example-plugin",
name = "ExamplePlugin"
)
public class SpongeLoader implements ILoader {
+ private ISpongeBootstrap bootstrap;
private final Logger logger;
private final PluginContainer container;
private final Path configDirectory;
@Inject
public SpongeLoader(Logger logger, PluginContainer container, @ConfigDir(sharedRoot = false) Path configDirectory) {
this.logger = logger;
this.container = container;
this.configDirectory = configDirectory;
+ initialize();
}
+ private Optional<ISpongeBootstrap> bootstrap() {
+ return Optional.ofNullable(bootstrap);
+ }
+ @Override
+ public String getBootstrapClassName() {
+ return "com.example.sponge.bootstrap.SpongeBootstrap";
+ }
+ @Override
+ public void initiateBootstrap(Class<?> aClass, JarInJarClassLoader jarInJarClassLoader) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+ Constructor<?> constructor = aClass.getConstructor(JarInJarClassLoader.class, Logger.class, PluginContainer.class, Path.class);
+ bootstrap = (ISpongeBootstrap) constructor.newInstance(jarInJarClassLoader, logger, container, configDirectory);
+ }
+ @Override
+ public String getName() {
+ return container.getName();
+ }
+ @Override
+ public ClassLoader getParentClassLoader() {
+ return getClass().getClassLoader();
+ }
+ @Override
+ public URL getJarInJarResource() {
+ return getParentClassLoader().getResource("sponge.jarinjar");
+ }
@Listener
public void onServerStart(GameStartedServerEvent event) {
- // plugin enable logic
+ bootstrap().ifPresent(bootstrap -> bootstrap.onServerStart(event));
}
}
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '7.0.0'
+ id 'dev.vankka.dependencydownload.plugin' version 'VERSION'
}
repositories {
mavenCentral()
maven {
url 'https://repo.spongepowered.org'
}
}
dependencies {
compileOnly 'org.spongepowered:spongeapi:7.3.0'
annotationProcessor 'org.spongepowered:spongeapi:7.3.0'
+ compileOnly project(':sponge:loader')
+ implementation 'dev.vankka:dependencydownload-jarinjar-bootstrap:1.0.0'
}
jar {
+ dependsOn generateRuntimeDownloadResourceForRuntimeDownload
finalizedBy shadowJar
}
shadowJar {
+ archiveFileName = 'sponge.jarinjar'
}
package com.example.sponge;
...
public class SpongeBootstrap extends AbstractBootstrap implements ISpongeBootstrap {
private final Logger logger;
private final PluginContainer pluginContainer;
private final Path configDirectory;
// If this is changed the SpongeLoader needs to be changed too
public SpongeBootstrap(JarInJarClassLoader classLoader, Logger logger, PluginContainer pluginContainer, Path configDirectory) {
super(classLoader);
this.logger = logger;
this.pluginContainer = pluginContainer;
this.configDirectory = configDirectory;
}
@Override
public void onServerStart(GameStartedServerEvent event) {
try {
DependencyManager manager = new DependencyManager(configDirectory.resolve("cache"));
manager.loadFromResource(getClass().getClassLoader().getResource("runtimeDownload.txt"));
Executor executor = Executors.newCachedThreadPool();
manager.downloadAll(executor, Collections.singletonList(new StandardRepository("https://repo.example.com/maven2"))).join();
manager.relocateAll(executor).join();
manager.loadAll(executor, new JarInJarClasspathAppender(super.getClassLoader())).join();
} catch (Throwable t) {
logger.error("Failed to load dependencies", t);
return;
}
// plugin enable logic
}
}