Service System
AstralCore uses a ServiceRepository to allow loose coupling between plugins. Any AstralService implementation can be registered and retrieved without creating a hard compile-time dependency.
AstralService Interface
AstralService is a marker interface in commons. Implement it to mark your service class:
import com.astralrealms.core.service.AstralService;
public interface MyEconomyService extends AstralService {
double getBalance(Player player);
void pay(Player player, double amount);
}
Registering a Service
Register your implementation during onEnable:
@Override
public void onEnable() {
AstralPaperAPI.registerService(MyEconomyService.class, new MyEconomyServiceImpl());
}
Retrieving a Service
Optional<MyEconomyService> economy = AstralPaperAPI.getService(MyEconomyService.class);
economy.ifPresent(e -> {
double balance = e.getBalance(player);
player.sendMessage("Balance: " + balance);
});
Or directly via the repository:
ServiceRepository repo = AstralPaperAPI.services();
repo.get(MyEconomyService.class).ifPresent(...);
Built-in Services
AstralCore ships several built-in services accessible through the main plugin instance:
Service | Access | Description |
|---|
PlayerService
| AstralPaperAPI.players()
| Network-wide player tracking and lookup |
ServerService
| AstralPaperAPI.servers()
| Server discovery and heartbeat management |
MenuService
| AstralCore.get().menus()
| Menu blueprint management and opening |
DialogService
| AstralCore.get().dialogs()
| Dialog blueprint management and opening |
BlockService
| AstralCore.get().blocks()
| Player-placed block tracking |
PaperTeleporationService
| AstralCore.get().teleportation()
| Cross-server teleportation |
EconomyService
| AstralPaperAPI.getService(EconomyService.class)
| Multi-currency economy: balances, deposit / withdraw / transfer, bulk transactions |
PlayerService
PlayerService players = AstralPaperAPI.players();
// Online check
boolean online = players.isOnline(uuid);
// Lookup by name (async, hybrid cache/DB)
players.findByName("Steve").thenAccept(opt -> {
opt.ifPresent(p -> System.out.println(p.server()));
});
// All online player names
Collection<String> names = players.onlinePlayerNames();
ServerService
ServerService servers = AstralPaperAPI.servers();
// Find the least-populated server in a group
servers.findEmptiestByGroup("survival").thenAccept(opt -> {
opt.ifPresent(server -> {
// Transfer player to that server
});
});
EconomyService
A built-in multi-currency economy abstraction (com.astralrealms.core.service.impl.EconomyService). Mutating operations are asynchronous (CompletableFuture<Boolean>); balances are also available synchronously from a local cache. Most methods come in default-currency and explicit-currency overloads, and deposit/withdraw take an optional notify flag.
EconomyService economy = AstralPaperAPI.getService(EconomyService.class).orElseThrow();
// Cached (sync) balance in the default currency
BigDecimal balance = economy.getCachedBalance(playerId);
// Async operations
economy.deposit(playerId, 100.0);
economy.withdraw(playerId, "gems", 5.0);
economy.transfer(fromId, toId, 50.0);
economy.hasBalance(playerId, 25.0).thenAccept(ok -> { /* ... */ });
Bulk transactions
bulkTransactions settles many deposits / withdrawals / transfers as a single batched future — use it instead of chaining individual operations when applying a whole set of balance changes at once.
economy.bulkTransactions(List.of(
new EconomyService.TransactionRequest(null, winnerId, 1000, "coins", TransactionType.DEPOSIT),
new EconomyService.TransactionRequest(loserId, null, 250, "coins", TransactionType.WITHDRAW),
new EconomyService.TransactionRequest(payerId, payeeId, 500, "coins", TransactionType.TRANSFER)
));
TransactionRequest field
| Type | Notes |
|---|
source
| @Nullable UUID
| Payer. null for a DEPOSIT. |
target
| UUID
| Recipient. |
amount
| double | Transaction amount. |
currency
| String | Currency id. |
type
| TransactionType
| DEPOSIT, WITHDRAW, or TRANSFER.
|
Service Lifecycle
Services are registered once and persist until the plugin is disabled. There is no built-in unregister — if your plugin is reloaded it should re-register its services on the next onEnable.
Last modified: 25 July 2026