Developer API
AstralPaperAPI is the static entry point for other plugins integrating with AstralCore.
import com.astralrealms.core.paper.AstralPaperAPI;
Availability Check
Always verify the API is initialised before calling it (e.g. in onEnable after adding AstralCore as a dependency):
if (!AstralPaperAPI.isInitialized()) {
getLogger().warning("AstralCore not available!");
return;
}
Services
Register and retrieve arbitrary AstralService implementations:
// Registration (during your plugin's onEnable)
AstralPaperAPI.registerService(MyEconomyService.class, new MyEconomyServiceImpl());
// Retrieval (anywhere)
Optional<MyEconomyService> economy = AstralPaperAPI.getService(MyEconomyService.class);
economy.ifPresent(e -> e.pay(player, 100));
// Direct access to the repository
ServiceRepository services = AstralPaperAPI.services();
Your service class must extend AstralService (a marker interface in commons).
Item Stack Suppliers
Register a named provider so items with your namespace prefix are resolved automatically wherever an ItemStack is parsed (menus, dialogs, NPC equipment, /give):
AstralPaperAPI.registerItemStackSupplier("mymod", new MyItemStackSupplier());
Usage in YAML (the substring before the first - is the namespace):
material: "mymod-special_sword"
Built-in suppliers: vanilla (always), hdb (when HeadDatabase is installed), ce (when CraftEngine is installed).
See Item System for the full ItemStackSupplier contract.
PlaceholderContainer
Create an isolated placeholder context for a player. The returned container is pre-populated with player_* and the PlaceholderAPI fallback:
PlaceholderContainer ctx = AstralPaperAPI.createPlaceholderContainer(player);
ctx.registerPlaceholder(new MyCustomPlaceholder());
Or attach player_* and PAPI fallback onto an existing container:
AstralPaperAPI.adaptPlaceholdersFor(player, existingContainer);
Placeholder Substitution
Apply %key% substitution on a string using a function:
String result = AstralPaperAPI.replacePlaceholder(
"Hello %player_name%, you have %kills% kills.",
key -> switch (key) {
case "kills" -> playerKills;
default -> null;
}
);
Accessing Core Services
// Server information from config.yml
ServerInformation info = AstralPaperAPI.serverInformation();
// Network player service
PlayerService players = AstralPaperAPI.players();
Optional<MinecraftPlayer> target = players.findByName("Steve");
// Server discovery service
ServerService servers = AstralPaperAPI.servers();
Type Adapters
A type adapter converts an already-resolved value into a target constructor-parameter type, so custom actions, requirements, and functions can declare rich argument types (a Location, a MinecraftPlayer, an ItemProvider, …) and let AstralCore coerce whatever the placeholder layer produced into that type.
Implement AstralAdapter<T>:
import com.astralrealms.core.adapter.AdapterContext;
import com.astralrealms.core.adapter.AstralAdapter;
import com.astralrealms.core.adapter.exception.AdapterDeserializationException;
public class MyTypeAdapter implements AstralAdapter<MyType> {
@Override
public Object deserialize(AdapterContext context) throws AdapterDeserializationException {
return switch (context.object()) {
case MyType value -> value; // passthrough
case String string -> new MyType(string);
default -> throw new AdapterDeserializationException(
"Cannot convert " + context.object().getClass().getName() + " to MyType");
};
}
@Override public Class<MyType> targetType() { return MyType.class; }
@Override public String name() { return "my-type"; }
}
Register it — globally (shared across every plugin on the network) or scoped to your own plugin:
// Global, e.g. during onEnable
AdapterRegistry.shared().register(new MyTypeAdapter());
// Or, from an AstralMCPlugin subclass:
registerAdapterGlobally(new MyTypeAdapter()); // shared registry
registerAdapter(new MyTypeAdapter()); // this plugin only
Built-in adapters
Common target types are registered out of the box, including:
name()
| Target type | Converts from |
|---|
integer
| java.lang.Integer
| any Number; numeric string; decimal string (truncated toward zero). Anything else adapts to null |
long
| java.lang.Long
| any Number; numeric string; decimal string (truncated toward zero). Anything else throws |
player
| org.bukkit.entity.Player
| Player, PlayerPlaceholder, MinecraftPlayer, or a player name resolved with Bukkit.getPlayer(name)
|
itemstack
| org.bukkit.inventory.ItemStack
| ItemStack, ItemStackPlaceholder, ItemStackWrapper
|
location
| org.bukkit.Location
| Location, LocationPlaceholder, NetworkLocation, MinecraftLocation
|
minecraft-player
| MinecraftPlayer
| MinecraftPlayerPlaceholder, Bukkit Player/OfflinePlayer, MinecraftPlayer
|
item-provider
| ItemProvider
| ItemProvider, Placeholder[], Map, a List/Collection of placeholders, or a single Placeholder
|
world
| org.bukkit.World
| World, WorldPlaceholder, a UUID, or a world name String (both resolved with Bukkit.getWorld)
|
entity
| org.bukkit.entity.Entity
| Entity, EntityPlaceholder, or a UUID resolved with Bukkit.getEntity
|
block
| org.bukkit.block.Block
| Block, BlockPlaceholder, or a Location (uses the block at that location)
|
enchantment
| org.bukkit.enchantments.Enchantment
| Enchantment, or an enchantment placeholder (%…_enchantment_<key>%, with or without a level). Anything else throws
|
collection
| java.util.Collection
| any Collection (passthrough), an array (wrapped with Arrays.asList), or a single value (wrapped in a one-element list). Defaults to the empty list when the value is absent |
number
| java.lang.Number
| any Number; a numeric string, always parsed as a double. Anything else throws |
double
| java.lang.Double
| any Number; numeric string. Anything else adapts to null |
float
| java.lang.Float
| any Number; numeric string. Anything else throws |
Last modified: 03 September 2026