Skip to content
BlazingGames is still work-in-progress and this documentation is probably inaccurate

Development Setup (for devs)

Everything BlazingGames does is split into “features”. Each feature has its own data, which has a name, description, dependencies, lifecycle, and more.

Features can do just about anything, including acting as libraries. They can use all Paper APIs. For some feature examples, see the built-in features in the sidebar.

To begin, you want to add blazinggames as a dependency for both bootstrap and runtime. It should load after with a joined classpath.

For example:

paper-plugin.yml
name: example-plugin
dependencies:
bootstrap:
blazinggames:
load: AFTER
required: true
join-classpath: true
server:
blazinggames:
load: AFTER
required: true
join-classpath: true

You’ll also want to use BlazingGames as a library in your plugin. Please do not shade or bundle it, as it will be available at runtime.

Repeat this section for each feature you’d like to add. For this example, we’ll make a feature called “Walrus” for no reason in particular.

First, make a class for it which extends FeatureLifecycle:

WalrusFeature.java
public class WalrusFeature extends FeatureLifecycle {
}

Now, we need to add a constructor. The super contructor takes the following values:

  • key: This is the key/id of your feature. The namespace should be your plugin’s namespace, like Bukkit does it when you create a NamespacedKey with your Plugin instance.

    • Example: myawesomeplugin:walrus
  • friendlyName: The name of your feature that users will see.

    • Example: Walrus
  • description: Describe what your feature does.

    • Example: Adds walruses to the game!
  • enabledByDefault: If the feature should be enabled by default when its configuration is generated. This is up to you to decide, but it will cause problems if not all of your dependencies are also enabled by default.

    • Example: false
  • dependencies: A list of the keys of other FeatureLifecycles that this feature depends on. Assuming your dependencies also followed this guide they should have a key property with their key. (we’ll get to this in a minute)

    • Example: ContentLib.key, SocialCore.key (depend on built-in content and social)
WalrusFeature.java
public class WalrusFeature extends FeatureLifecycle {
public WalrusFeature() {
super(
Key.key("myawesomeplugin", "walrus"),
"Walrus",
"Adds walruses to the game!",
false,
ContentLib.key, SocialCore.key
);
}
}

Next, your key should be public and static so that other features can depend on it.

WalrusFeature.java
public class WalrusFeature extends FeatureLifecycle {
public static final Key key = Key.key("myawesomeplugin", "walrus");
public WalrusFeature() {
super(
Key.key("myawesomeplugin", "walrus"),
key,
"Walrus",
"Adds walruses to the game!",
false,
ContentLib.key, SocialCore.key
);
}
}

And that’s it for the code! You can now add your feature logic.

WalrusFeature.java
public class WalrusFeature extends FeatureLifecycle {
...
@Override
public void onInitialize(FileConfiguration config) {
// This method allows you to load your configuration file. It will always
// be called before any method here.
}
@Override
public void onEnable(LifecycleContext context) {
// Called during Bukkit's onEnable
}
@Override
public void onDisable(BlazingGames plugin) {
// Called during Bukkit's onDisable
}
}

Your feature will fail to load if you do not have a default configuration file for it. Create a configtemplates folder in your plugin’s resources to store default configuration files.

A file with your feature’s key (without the namespace) and a .yml file extension is mandatory. Your feature your fail to load otherwise.

For example, if your feature is myawesomeplugin:walrus, you need a file at /configtemplates/walrus.yml.

This configuration file will be copied to /plugins/BlazingGames/configs/NAMESPACE/KEY.yml, regardless of what plugin registered it, and users can configure it there.

Example configuration file:

walrus.yml
# If the legendary blue walrus should be enabled.
blue-walrus: false

Here’s a brief overview of what you can do with the LifecycleContext given in onEnable:

// Listen to an event
context.registerEvent(PlayerInteractEvent.class, new WalrusInteractHandler());
// Register a timer
context.registerTimer(new WalrusBukkitRunnable(), 0, 20);
// Just do something else entirely, some other features act as libraries
ResourcePackManager.installHook(new WalrusHook(this));

This is how BlazingGames gets the list of features to get from your plugin. Just like before, let’s start with a class:

MyFeatureProvider.java
public class MyFeatureProvider implements FeatureProvider {
}

Then, register it as a Java service (with Java’s SPI).

No idea what this means? Just add Google’s AutoService as a dependency and annotate your FeatureProvider implementation like this:

MyFeatureProvider.java
@AutoService(FeatureProvider.class)
public class MyFeatureProvider implements FeatureProvider {
}

Now, we need to implement getFeatures. There are plenty of ways to do this, so do it however you’d like. A few examples:

Feature instances on the FeatureProvider This is the easiest to implement, but it might accidentally allow other plugins to initalize your feature (unless the lifecycle is package-private, which is impractical depending on your code organization).

MyFeatureProvider.java
@AutoService(FeatureProvider.class)
public class MyFeatureProvider implements FeatureProvider {
public static final WalrusFeature walrus = new WalrusFeature();
@Override
public List<FeatureLifecycle> getFeatures() {
return List.of(walrus);
}
}

Feature instances on their FeatureLifecycle This is probably the cleanest solution, but requires a bit more effort. Other plugins will be unable to initalize stuff they shouldn’t.

First, in each feature’s lifecycle:

WalrusFeature.java
public class WalrusFeature extends FeatureLifecycle {
public static final WalrusFeature instance = new WalrusFeature();
public static final Key key = Key.key("myawesomeplugin", "walrus");
public WalrusFeature() {
private WalrusFeature() {
super(
key,
"Walrus",
"Adds walruses to the game!",
false,
ContentLib.key, SocialCore.key
);
}
...
}

Then, in your feature provider:

MyFeatureProvider.java
@AutoService(FeatureProvider.class)
public class MyFeatureProvider implements FeatureProvider {
@Override
public List<FeatureLifecycle> getFeatures() {
return List.of(WalrusFeature.instance);
}
}

Launch a Paper server however you usually do it to test. If you’d like, you can also read the admin setup guide for some important information.

Make sure BlazingGames is loaded, because it loads your feature and crashes if it fails to. If it isn’t, check your server logs for any stacktraces, and make sure BlazingGames detects your feature in the first place.

A few common problems you might encouter are documented below:

Feature or FeatureProvider wasn’t detected at discovery time Was your FeatureProvider registered as a Java SPI service? If you’re using AutoService, is it also in your annotation processor classpath?

Make sure the FeatureProvider also has a public no-args constructor.

If it worked, you should see a file in META-INF in your jar somewhere with the full class name of FeatureProvider containing a line with the full class name of your implementation. Otherwise, it didn’t register.

Feature was detected, but didn’t load Is your feature enabledByDefault? If not, you’ll need to enable it yourself at /plugins/BlazingGames/configs/NAMESPACE/KEY.yml by setting enabled to true.

Bukkit/Server isn’t initialized or something exception During construction of your FeatureProvider and FeatureLifecycles, along with onInitialize and onBootstrap, the server doesn’t yet exist. Check the stacktrace to see what tried to use a Bukkit API.