Astral Realms Documentation Help

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 (sync, local online cache only) Optional<MinecraftPlayer> cached = players.findByName("Steve"); // Lookup by name (async: cache first, then the database) players.findOrLoad("Steve").thenAccept(opt -> { opt.ifPresent(p -> System.out.println(p.serverInfo())); }); // All online player names Collection<String> names = players.onlinePlayerNames();

Method

Returns

Notes

findOrLoad(String)

CompletableFuture<Optional<MinecraftPlayer>>

Local cache first, then the repository.

findById(UUID)

CompletableFuture<Optional<MinecraftPlayer>>

Local cache first, then the repository.

findByName(String)

Optional<MinecraftPlayer>

Synchronous, local online cache (name index) only.

findByUniqueId(UUID)

Optional<MinecraftPlayer>

Synchronous, local cache only.

isOnline(String)/isOnline(UUID)

boolean

Cached player exists and online().

onlinePlayers()

Collection<MinecraftPlayer>

Unmodifiable view of the cache.

onlinePlayerNames()

Collection<String>

Unmodifiable view of the name index.

clear()

void

Empties the cache and the name index.

MinecraftPlayer

Field / accessor

Type

Notes

uniqueId()

UUID

Player UUID (primary key).

name()

String

Last known username, refreshed on quit.

firstLogin()

long

First login timestamp, stamped once. <= 0 when never set.

lastLogin()

long

Start of the current (or last) login. Not touched on quit — it is the instant the live playtime delta is measured from.

lastSeen()

long

Last time the player was observed connected. Stamped on login and again on quit. <= 0 = never seen.

playtime()

long

Persisted playtime, only settled when the player disconnects — it lags by the running session.

effectivePlaytime()

long

playtime plus the live session delta (now - lastLogin) while online(); the settled playtime otherwise. Use this for every user-facing surface.

serverInfo()

@Nullable CompactServerInfo

Transient. The server the player is on.

online()

boolean

serverInfo() != null.

texture()/hasTexture()

@Nullable String/ boolean

Transient skin texture.

recentlyCreated()

boolean

true when firstLogin <= 0 or it is less than 5 seconds old.

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: 03 September 2026