-
Notifications
You must be signed in to change notification settings - Fork 0
Addon API
Mixer addons are ordinary Paper plugins. They declare Mixer as a dependency, obtain
MixerApi from Bukkit's Services API, and register an addon instance. An addon must
only depend on the api module; classes under me.andromedov.mixer.core are internal.
The API examples below target Mixer 2.3.0, Paper 1.21.4+, and Java 21. Mixer itself is validated on Paper versions from 1.21.4 through 26.2.
Until the API artifact is published to a remote Maven repository, install the current checkout into Maven Local:
./gradlew :api:publishToMavenLocalThen configure the addon project:
repositories {
mavenLocal()
maven("https://repo.papermc.io/repository/maven-public/")
}
dependencies {
compileOnly("me.andromedov:mixer-api:2.3.0")
compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}The addon's plugin.yml must load after Mixer:
name: RadioAddon
version: 1.0.0
main: com.example.radio.RadioAddonPlugin
api-version: '1.21.4'
depend: [Mixer]package com.example.radio;
import me.andromedov.mixer.api.MixerApi;
import me.andromedov.mixer.api.addon.MixerAddon;
import me.andromedov.mixer.api.addon.MixerAddonContext;
import me.andromedov.mixer.api.source.MixerAudioSourceResolver;
import org.bukkit.plugin.java.JavaPlugin;
public final class RadioAddonPlugin extends JavaPlugin {
@Override
public void onEnable() {
MixerApi.get().addons().register(this, new MixerAddon() {
@Override
public String id() {
return "radio";
}
@Override
public String name() {
return "Radio Addon";
}
@Override
public String version() {
return getPluginMeta().getVersion();
}
@Override
public void onEnable(MixerAddonContext context) {
context.registerSourceResolver(new MixerAudioSourceResolver() {
@Override
public String id() {
return "station";
}
@Override
public int priority() {
return 100;
}
@Override
public boolean supports(String source) {
return source.startsWith("radio:");
}
@Override
public String resolve(String source) {
String station = source.substring("radio:".length());
return switch (station) {
case "ambient" -> "https://radio.example/ambient.ogg";
case "rock" -> "https://radio.example/rock.ogg";
default -> throw new IllegalArgumentException("Unknown station: " + station);
};
}
});
}
});
}
}Players and burned discs can now use radio:ambient. Mixer stores that stable source
on the disc and asks the addon to resolve it each time playback starts. This allows an
addon to return expiring URLs without writing those URLs into item data.
Source resolver supports and resolve methods run asynchronously. They may perform
blocking HTTP or database work, but must not access Bukkit APIs that require the main
server thread. Resolvers run by descending priority; equal priorities use their stable
registration key as a tiebreaker.
All registrations created through MixerAddonContext are automatically removed when
the addon is disabled. Manual cleanup is only necessary for resources created outside
the Mixer API.
MixerApi mixer = MixerApi.get();
var audioPlayer = mixer.getOrCreatePlayer(jukebox.getLocation());
audioPlayer.clearAndPlay("radio:ambient");
audioPlayer.currentTrack().ifPresent(track ->
getLogger().info(track.author() + " - " + track.title()));
audioPlayer.dsp().setGain(0.75);
audioPlayer.dsp().setHighPass(120.0F);
audioPlayer.dsp().setFlanger(0.003, 0.5, 1.5);
audioPlayer.clearQueue();
mixer.stopPlayer(jukebox.getLocation());Creating/stopping players, changing DSP, and registering/unregistering addons or resolvers must happen on the Bukkit main thread. Reading player state and resolving audio sources is thread-safe. Collections returned by the API are immutable snapshots.
Portable players are also available through createPortablePlayer,
findPortablePlayer, and stopPortablePlayer.