-
Notifications
You must be signed in to change notification settings - Fork 12
Project Structure
This page serves as a comprehensive template for your plugin and is not meant to be a "tutorial" as such but instead a reference for what your plugin "should" look like.
No actual java code in this module, but the build.gradle
should look something like this to avoid repeating yourself in subprojects:
plugins {
id 'java'
}
subprojects {
group "org.anvilpowered"
version "A1.0-1.0.0-SNAPSHOT"
sourceCompatibility = 1.8
if (project.hasProperty("buildNumber") && version.contains("-SNAPSHOT")) {
version = version.replace("-SNAPSHOT", "-RC${buildNumber}")
}
}
This marks the Anvil API version this plugin was built for (A1.0 means compatibility with v >= 1.0 && v < 2.0)
This checks whether the property "buildNumber" was provided and is responsible for injecting the build number into release candidate jars. Can be run with e.g. ./gradlew build -PbuildNumber=58
.
The API is where the structure of your plugin is defined and is full of method contracts but no actual implementation. Package names in this module should start with the format <groupid>.<artifactid>.api
. For Anvil, this is org.anvilpowered.anvil.api
. The build.gradle
for this module should look something like this:
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.anvilpowered:anvil-api:1.0'
implementation 'org.anvilpowered:anvil-api-mongodb:1.0'
implementation 'org.anvilpowered:anvil-api-xodus:1.0'
implementation guice
implementation morphia
implementation xodus_entity_store
}
This is where your shared code goes. Anything that doesn't require direct access to a platform's code should go in here. One of the things you should have in this module is the main plugin class, which will later be extended by the main classes in the platform modules. It should look something like this:
package org.anvilpowered.simpletickets.common.plugin;
import com.google.inject.Injector;
import com.google.inject.Module;
import org.anvilpowered.anvil.api.Environment;
import org.anvilpowered.anvil.base.plugin.BasePlugin;
public abstract class SimpleTickets<TPluginContainer> extends BasePlugin<TPluginContainer> {
protected SimpleTickets(Injector injector, Module module) {
super(SimpleTicketsPluginInfo.id, injector, module);
}
@Override
protected void applyToBuilder(Environment.Builder builder) {
builder.withRootCommand(); // tell Anvil to load root command node
}
}
The main function of BasePlugin
is to provide a quick way to create an environment. Very simple plugins will only need a constructor here. However, you can use applyToBuilder(Environment.Builder)
(as in the above example) for more control. For complete control, use the BasePlugin(String)
constructor which does not create an environment for you. If you do this, you must use Anvil.getEnvironmentBuilder()
to create an environment yourself.
Please note that you do not have to extend BasePlugin
. This base implementation should cover most use cases, but it is also possible to just implement Plugin
instead.
Implement the PluginInfo
interface to store your plugin's metadata. This should look something like this:
package org.anvilpowered.simpletickets.common.plugin;
import com.google.inject.Inject;
import org.anvilpowered.anvil.api.plugin.PluginInfo;
import org.anvilpowered.anvil.api.util.TextService;
public class SimpleTicketsPluginInfo<TString, TCommandSource> implements PluginInfo<TString> {
public static final String id = "simpletickets";
public static final String name = "Simple Tickets";
public static final String version = "$modVersion"; // replaced by blossom from gradle
public static final String description = "A simple ticket plugin";
public static final String url = "https://github.com/AnvilPowered/SimpleTickets";
public static final String[] authors = {"Cableguy20"};
public static final String organizationName = "AnvilPowered";
public static final String buildDate = "$buildDate"; // replaced by blossom from gradle
public TString pluginPrefix;
@Inject
public void setPluginPrefix(TextService<TString, TCommandSource> textService) {
pluginPrefix = textService.builder()
.blue().append("[")
.aqua().append(name)
.blue().append("] ") // space at the end to make it easier to append text later
.build();
}
... getters and setters not included ...
The build.gradle
for this module should look something like this:
import java.text.SimpleDateFormat
plugins {
id 'java'
id "net.kyori.blossom" version "1.1.0"
}
repositories {
mavenCentral();
}
dependencies {
implementation project(':api')
implementation 'org.anvilpowered:anvil-api:1.0'
implementation 'org.anvilpowered:anvil-api-mongodb:1.0'
implementation 'org.anvilpowered:anvil-api-xodus:1.0'
implementation 'org.anvilpowered:anvil-base:1.0'
implementation 'org.anvilpowered:anvil-base-mongodb:1.0'
implementation 'org.anvilpowered:anvil-base-xodus:1.0'
implementation guice
implementation morphia
implementation xodus_entity_store
}
// for replacing placeholders in string literals
blossom {
replaceToken '$modVersion', version
SimpleDateFormat format = new SimpleDateFormat("uuuu-MM-dd-HH:mm:ss z")
format.setTimeZone(TimeZone.getTimeZone("UTC"))
String buildDate = format.format(new Date())
replaceToken '$buildDate', buildDate
}
The platform module is where all code goes that needs direct access to a platform's API. A good example of this is command registration with CommandSpec
from Sponge.
This is also where the main plugin classes are located. These main classes are very important, as they are currently the only way your plugin can get loaded. A Sponge main class should look something like this:
package org.anvilpowered.simpletickets.sponge.plugin;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import org.anvilpowered.simpletickets.common.plugin.SimpleTickets;
import org.anvilpowered.simpletickets.common.plugin.SimpleTicketsPluginInfo;
import org.anvilpowered.simpletickets.sponge.module.SpongeModule;
import org.spongepowered.api.plugin.Dependency;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.plugin.PluginContainer;
@Plugin(
id = SimpleTicketsPluginInfo.id,
name = SimpleTicketsPluginInfo.name,
version = SimpleTicketsPluginInfo.version,
dependencies = @Dependency(id = "anvil"),
description = SimpleTicketsPluginInfo.description,
url = SimpleTicketsPluginInfo.url,
authors = "Cableguy20"
)
public class SimpleTicketsSponge extends SimpleTickets<PluginContainer> {
@Inject
public SimpleTicketsSponge(Injector injector) {
super(injector, new SpongeModule());
}
}
Finally, the build.gradle
for a Sponge module should look something like this:
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '5.2.0'
id 'org.spongepowered.plugin' version '0.9.0'
}
jar.enabled = false // we only want shadowJar
repositories {
mavenCentral()
maven { url 'https://repo.spongepowered.org/maven' }
}
dependencies {
implementation project(':api')
implementation project(':common')
implementation 'org.anvilpowered:anvil-api:1.0'
implementation 'org.anvilpowered:anvil-api-mongodb:1.0'
implementation 'org.anvilpowered:anvil-api-xodus:1.0'
implementation 'org.anvilpowered:anvil-base:1.0'
implementation 'org.anvilpowered:anvil-base-mongodb:1.0'
implementation 'org.anvilpowered:anvil-base-xodus:1.0'
implementation guice
implementation bson
implementation javasisst
implementation mongo_java_driver
implementation xodus_entity_store
compileOnly('org.spongepowered:spongeapi:7.2.0-SNAPSHOT') {
exclude(module: 'configurate-gson')
exclude(module: 'configurate-yaml')
}
annotationProcessor 'org.spongepowered:spongeapi:7.2.0-SNAPSHOT'
}
shadowJar {
String jarName = "SimpleTickets-Sponge-${project.version}.jar"
println "Building: " + jarName
archiveFileName = jarName
// include these projects in the final jar
dependencies {
include project(':api')
include project(':common')
}
}
artifacts {
archives shadowJar
}