Astral Realms Documentation Help

Developer API

AstralSkyblock exposes its services through the AstralSkyblock.get() singleton, fires eight custom Bukkit events around island/world/member/co-op lifecycle, and registers eleven actions plus three ACF completions and two context resolvers that other menus, dialogs and commands can reuse. Cross-server coherency (island load routing, membership sync, cache invalidation) flows over RabbitMQ through ASPacketRegistry.

Maven coordinates

<dependency> <groupId>com.astralrealms</groupId> <artifactId>skyblock</artifactId> <version>1.0-SNAPSHOT</version> <scope>provided</scope> </dependency>

Repository: https://maven.astralrealms.fr/repository/maven-public/.

Accessing the plugin

AstralSkyblock is @Getter-annotated (Lombok), so every field constructed in onEnable is exposed as a same-named getter off the singleton:

import com.astralrealms.skyblock.AstralSkyblock; AstralSkyblock plugin = AstralSkyblock.get(); IslandService islands = plugin.islands(); MemberService members = plugin.members(); CoopService coops = plugin.coops(); InvitationService invitations = plugin.invitations(); RoleService roles = plugin.roles(); UpgradeService upgrades = plugin.upgrades(); GeneratorService generators = plugin.generators(); BlueprintService blueprints = plugin.blueprints(); WorldService worlds = plugin.worlds(); ServerService servers = plugin.servers(); PlayerService players = plugin.players();

Getter

Type

Use

islands()

IslandService

Island CRUD, cross-server spawn resolution, settings flush, cache warmup.

members()

MemberService

Membership CRUD (add/kick/leave/promote/demote/transfer), cross-server member sync.

coops()

CoopService

Co-op grant CRUD, cross-server sync.

invitations()

InvitationService

Invitation lifecycle (create/accept/decline/cancel), periodic pruning of expired invites.

roles()

RoleService

Role CRUD and permission-flag updates.

upgrades()

UpgradeService

Loaded IslandUpgrade tracks, per-island level lookups and purchases.

generators()

GeneratorService

Loaded generators/*.yml configurations, default-generator lookup.

blueprints()

BlueprintService

Loaded IslandBlueprints, default-blueprint lookup, blueprint ids for completion.

worlds()

WorldService

ASP SlimeWorld create/load/save/unload, host-server bookkeeping, idle-unload sweep.

servers()

ServerService

Emptiest-island-server lookup, per-island host-server mapping.

players()

PlayerService

Records/loads last-seen player rows.

AstralSkyblock also exposes configuration(), rolesConfiguration(), blockValuesConfiguration(), database(), cache(), messaging(), menus() (AstralCore MenuContainer) and dialogs() (AstralCore DialogContainer) through the same Lombok getters — see Overview for the full service table.

Custom Bukkit events

AstralSkyblock fires eight custom events, none of them Cancellable — every one is a post-fact notification fired after its underlying database write has already succeeded. They live under event/island, event/island/world, event/member and event/coop.

Island lifecycle

Both events in this group compute their own async flag from the calling thread at construction time (super(!Bukkit.isPrimaryThread())), because they're fired from inside a CompletableFuture callback chain that isn't guaranteed to land back on the main thread. They are the only two events in this catalogue that behave this way — check Event#isAsynchronous() (or simply write your handler to be thread-safe) before touching Bukkit API from a listener.

IslandCreateEvent

Field

Type

Description

player

Player

The player who created the island.

island

Island

The newly created island.

world

World

The Bukkit world the island's SlimeWorld was loaded into.

Fired by IslandService#create once the island row (with seeded roles/owner) is persisted and its world has finished loading — after the player has already been teleported and the ISLAND_CREATED message sent.

IslandDeletedEvent

Field

Type

Description

player

Player

The player who requested the deletion.

island

Island

The deleted island (its row is already gone from the database).

Fired by IslandService#delete after the island row is removed, before the world-delete cleanup and the ISLAND_DELETED message. No permission or ownership check happens before this fires — see Commands for the caller-side gap.

World lifecycle

Both events use Lombok's default (synchronous) Event() constructor and are always dispatched with .callEvent() from inside a Bukkit.getScheduler().runTask(plugin, ...) block in WorldService, so listeners can always touch Bukkit API directly.

IslandWorldLoadedEvent

Field

Type

Description

island

Island

The island whose world was loaded.

world

World

The now-loaded Bukkit world.

Fired by WorldService#loadWorld right after the world is registered in loadedWorlds, its environment settings applied (IslandSettingsListener#applyEnvironment), and its host-server mapping set — but before any player is necessarily present.

IslandWorldUnloadedEvent

Field

Type

Description

island

Island

The island whose world was unloaded.

world

World

The Bukkit world that was just unloaded.

Fired by WorldService#unload after Bukkit.unloadWorld succeeds and the host-server mapping is cleared. Only fires if the island can still be resolved from the world-service cache — a warning is logged instead if it can't.

Membership & co-op

All four events in this group also use the synchronous Event() constructor, but the services that fire them run inside asynchronous repository callbacks, so each call site explicitly hops back to the main thread first: Bukkit.getScheduler().runTask(plugin, () -> Bukkit.getPluginManager().callEvent(...)).

IslandMemberJoinEvent

Field

Type

Description

island

Island

The island the player joined.

playerId

UUID

The joining player.

invitedBy

UUID

The player who sent the accepted invitation.

Fired by MemberService#addMember after the membership row is persisted, and again locally on every other server by MemberService's MEMBER_SYNC_CHANNEL packet handler when it receives the MemberJoinPacket broadcast from the originating server — so a listener registered on any server sees every join, not just the one that happened locally.

IslandMemberLeaveEvent

Field

Type

Description

island

Island

The island the player left.

playerId

UUID

The departing player.

reason

Reason

VOLUNTARY, KICKED, or BANNED.

Fired by MemberService#kick (Reason.KICKED) and MemberService#leave (Reason.VOLUNTARY), and relayed network-wide the same way as IslandMemberJoinEvent via MemberLeavePacket. Reason.BANNED is defined on the enum but no code path in this build currently fires it — ban enforcement isn't wired into MemberService yet (there is no BanRepository), even though IslandBan exists as a model and island-bans/island-confirm-ban menus ship in resources/menus/.

IslandCoopAddEvent

Field

Type

Description

island

Island

The island granting co-op access.

playerId

UUID

The player granted co-op.

addedBy

UUID

The player who sent the accepted co-op invitation.

Fired by CoopService#add after the IslandCoop row is persisted and the local island snapshot is updated. CoopAddPacket is also broadcast on COOP_SYNC_CHANNEL so other servers update their own cache/snapshot, but — unlike the member-join/leave events below — the event itself is not re-fired on those other servers; CoopService's packet handler explicitly skips it (its Javadoc: "Does NOT fire an event (already fired on the originating server)"). Listen for it only where you expect the originating action to happen, not network-wide.

IslandCoopRemoveEvent

Field

Type

Description

island

Island

The island revoking co-op access.

playerId

UUID

The player whose co-op grant was removed.

Fired by CoopService#remove. Same cache-only cross-server relay as IslandCoopAddEventCoopRemovePacket syncs state on other servers but does not re-fire this event there.

@EventHandler public void onMemberJoin(IslandMemberJoinEvent event) { Island island = event.getIsland(); UUID player = event.getPlayerId(); // Grant a "newcomer" badge, log analytics, … }

Key service methods

The full method surface is longer than what's listed here — these are the entry points other plugins are most likely to call.

IslandService

Method

Returns

Behavior

create(Player, String name, IslandBlueprint)

void

Validates the name is free, inserts the island (with seeded roles + owner) and its world in one flow, teleports the player, and fires IslandCreateEvent. Rolls the island row back if world creation fails.

delete(Player, Island)

void

Deletes the island row, then the world (best-effort), then fires IslandDeletedEvent. No permission check — the caller is responsible for gating this.

spawnIsland(Island)

CompletableFuture<NetworkLocation>

Resolves where to teleport a visitor: checks the live host-server mapping, falls back to the emptiest island server, loads the world locally or requests a remote load, and times out after 15 seconds.

islands()

Collection<Island> (@Unmodifiable)

Every island currently in the local L1 cache — not a full database scan.

refreshRelationships(UUID islandId)

CompletableFuture<Void>

Re-cascades a cached island's members/roles/co-ops after a membership or role write.

refreshUpgrades(UUID islandId)

CompletableFuture<Void>

Rebuilds a cached island's upgrade-level snapshot after an upgrade purchase.

updateSettings(Player, Island)

void

Flushes the island's dirty IslandSettings toggles to the database and re-applies world environment state if hosted locally. Requires IslandPermission#SET_SETTINGS.

warmup()

CompletableFuture<Void>

Pages every island into the L1 cache on startup; failures are logged, not fatal.

MemberService

Method

Returns

Behavior

findPlayerIsland(UUID playerId)

Optional<Island>

Synchronous cached lookup — the island the player is a member of, if any. This is the resolver behind the bare-argument form of /is commands and the IslandContextResolver.

addMember(Island, UUID playerUuid, UUID invitedBy)

CompletableFuture<IslandMember>

Adds the player under the island's default role. No validation — callers (InvitationService) must check the member limit and pre-existing membership themselves. Fires IslandMemberJoinEvent and broadcasts MemberJoinPacket.

kick(Island, Player kicker, UUID targetUuid)

CompletableFuture<Void>

Requires IslandPermission#KICK_MEMBER and that the kicker outrank the target (the owner can never be kicked). Fires IslandMemberLeaveEvent (KICKED).

promote(Island, Player sender, UUID targetUuid)

CompletableFuture<Void>

Moves the target one step up the non-owner role ladder (roles sorted ascending by weight()). Requires IslandPermission#PROMOTE_MEMBERS; a non-owner sender cannot promote to or above their own weight.

demote(Island, Player sender, UUID targetUuid)

CompletableFuture<Void>

Moves the target one step down the ladder. Requires IslandPermission#DEMOTE_MEMBERS; a non-owner sender must outrank the target.

transfer(Island, Player currentOwner, IslandMember newOwner)

CompletableFuture<Void>

Only the current owner may call this. Demotes the ex-owner to the island's highest-weight MEMBER-kind role and promotes newOwner to owner, transactionally.

WorldService

Method

Returns

Behavior

load(Island)

CompletableFuture<SlimeWorldInstance>

Loads the island's SlimeWorld on this server if not already loaded, coalescing concurrent calls for the same island onto one in-flight future. Applies environment settings and sets the host-server mapping on success; fires IslandWorldLoadedEvent.

create(UUID islandId, IslandBlueprint)

CompletableFuture<SlimeWorldInstance>

Clones the blueprint's source world for the island, loads it, and saves it. Tears down whatever was created if any step fails.

save(UUID islandId)

CompletableFuture<Void>

Saves the currently-loaded SlimeWorldInstance for the island; fails if it isn't loaded on this server.

unload(UUID islandId)/unload(UUID islandId, boolean save)

CompletableFuture<Void>

Unloads the world from this server (optionally without saving — used by the delete path so a deleted island's world can't be re-persisted). Clears the host-server mapping and fires IslandWorldUnloadedEvent.

findByWorld(World)

Optional<Island>

Resolves the island that owns a loaded Bukkit world, by world name.

findByIslandId(UUID)

Optional<SlimeWorldInstance>

The loaded SlimeWorldInstance for an island, if this server currently hosts it.

Registered actions

AstralSkyblock registers eleven actions with registerAction (its own local action registry — see Actions for the general [id] args syntax). They resolve inside any actions:/close-actions:/view-requirements:-adjacent action list parsed by AstralSkyblock's own menus/dialogs, and any other plugin can trigger them programmatically through the same registry. Five of them (invite-member, coop-player, promote-member, demote-member, transfer-ownership) aren't referenced by any menu shipped in resources/menus/ in this build — they exist for custom menus/dialogs (or other plugins) that want a menu-click equivalent of the matching /is subcommand.

Every action's first argument is a PlaceholderWrapper<Island> — in shipped menus this resolves from either a direct Island placeholder (e.g. %parameters_island%) or an id string that's looked up (e.g. %parameters_island_id%); both forms are used interchangeably in the examples below because both appear in the shipped resource files.

toggle-role-permission

Toggles one IslandPermission on a role. Requires IslandPermission#SET_PERMISSION and Island#canEditRole (the caller must outrank the role being edited, or be the owner/skyblock.admin). Plays a pickup-orb sound on enable, a button-click sound on disable.

Arg

Type

Description

island

PlaceholderWrapper<Island>

The island the role belongs to.

role

PlaceholderWrapper<IslandRole>

The role being edited.

permission

PlaceholderWrapper<IslandPermission>

The permission to toggle.

actions: - "[toggle-role-permission] %parameters_island% %parameters_role% %parameter_permission%"

update-role-permissions

Flushes a role's pending permission toggles (accumulated by toggle-role-permission, held in IslandRole#dirtyPermissions until this fires) to the database. Same permission/rank checks as toggle-role-permission. Typically wired as a menu's close-actions: so edits persist when the player exits.

Arg

Type

Description

island

PlaceholderWrapper<Island>

The island the role belongs to.

role

PlaceholderWrapper<IslandRole>

The role whose dirty permissions should be persisted.

close-actions: - "[update-role-permissions] %parameters_island% %parameters_role%"

toggle-island-setting

Toggles one IslandSettings flag. Requires IslandPermission#SET_SETTINGS. Time-lock and weather-lock settings are mutually exclusive within their group (see IslandSettings#conflictingSettings) — enabling one silently clears the conflicting one. Immediately re-applies world environment state if the island is hosted on this server, since time/weather locks are world state rather than cancellable events.

Arg

Type

Description

island

PlaceholderWrapper<Island>

The island being edited.

setting

PlaceholderWrapper<IslandSettings>

The setting to toggle.

actions: - "[toggle-island-setting] %parameters_island% %parameter_setting%"

update-island-settings

Flushes an island's pending setting toggles to the database via IslandService#updateSettings. Same permission check and environment re-apply as toggle-island-setting.

Arg

Type

Description

island

PlaceholderWrapper<Island>

The island whose dirty settings should be persisted.

close-actions: - "[update-island-settings] %parameters_island%"

invite-member

Sends a member invitation. Requires IslandPermission#INVITE_MEMBER; silently returns (no message) if the caller lacks the island entirely. Delegates to InvitationService#create with InvitationType.MEMBER.

Arg

Type

Description

island

PlaceholderWrapper<Island>

The inviting island.

target

PlaceholderWrapper<MinecraftPlayer>

The player to invite.

No shipped menu wires this action — build the second argument from whatever placeholder in your menu/dialog resolves to a MinecraftPlayer (e.g. a name-entry dialog result).

kick-member

Kicks a member — see MemberService#kick for the outrank rules. From resources/menus/confirm/confirm-kick.yml:

Arg

Type

Description

island

PlaceholderWrapper<Island>

The island to kick from.

targetUuid

PlaceholderWrapper<UUID>

The member to kick.

actions: - "[kick-member] %parameters_island_id% %parameters_member_playerId%" - "[open-menu] island-members:island=%parameters_island%"

promote-member

Promotes a member one step up the role ladder — see MemberService#promote.

Arg

Type

Description

island

PlaceholderWrapper<Island>

The island the target belongs to.

targetUuid

PlaceholderWrapper<UUID>

The member to promote.

No shipped menu wires this action — see kick-member above for the shipped pattern a menu would follow to supply a member's playerId.

demote-member

Demotes a member one step down the role ladder — see MemberService#demote.

Arg

Type

Description

island

PlaceholderWrapper<Island>

The island the target belongs to.

targetUuid

PlaceholderWrapper<UUID>

The member to demote.

No shipped menu wires this action either — same shape as promote-member.

transfer-ownership

Transfers ownership to an existing member — see MemberService#transfer. Only the current owner may invoke this.

Arg

Type

Description

island

PlaceholderWrapper<Island>

The island to transfer.

newOwner

PlaceholderWrapper<IslandMember>

The member becoming the new owner.

No shipped menu wires this action — the second argument needs a placeholder resolving to a full IslandMember (not just a playerId), e.g. a member picked from an island-members-style layout.

coop-player

Sends a co-op invitation. Requires IslandPermission#COOP_MEMBER. Delegates to InvitationService#create with InvitationType.COOP.

Arg

Type

Description

island

PlaceholderWrapper<Island>

The inviting island.

target

PlaceholderWrapper<MinecraftPlayer>

The player to invite as co-op.

No shipped menu wires this action — same argument shape as invite-member.

uncoop-player

Removes a co-op grant. Requires IslandPermission#COOP_MEMBER — note this checks COOP_MEMBER, not a separate UNCOOP_MEMBER node, despite /is uncoop (the command) gating on IslandPermission#UNCOOP_MEMBER. From resources/menus/coops.yml:

Arg

Type

Description

island

PlaceholderWrapper<Island>

The island to remove the co-op from.

targetUuid

PlaceholderWrapper<UUID>

The co-op player to remove.

actions: - "[uncoop-player] %parameters_island_id% %parameter_coop_playerId%" - "[refresh]"

Command extension points

AstralSkyblock registers its ACF completions and context resolvers on its own PaperCommandManager (AstralPaperPlugin#commands()), so any command class registered by this plugin — including one added by a dependent plugin sharing the same manager — can reference them via @CommandCompletion/@Values.

Registered as

Handler

Behavior

@islandBlueprints

IslandBlueprintCompletionHandler

Every loaded blueprint id (blueprints().keys()).

@islands

IslandCompletionHandler

Every island's name on this server (islands().repository().names()).

@islandMembers

IslandMemberCompletionHandler

Names of the caller's island's members, excluding the caller; empty if the caller has no island or isn't a Player.

Type

Resolver

Behavior

IslandBlueprint

IslandBlueprintContextResolver

Pops the first argument, resolves via blueprints().findById(name); throws InvalidCommandArgument if not found.

Island (issuer-aware)

IslandContextResolver

Pops the first argument. If absent and the parameter is @Optional, resolves null. If absent without a real flag, falls back to the caller's own island via members().findPlayerIsland(...). Otherwise resolves by exact name via islands().repository().findByName(name).

@Subcommand("info") @CommandCompletion("@islands") @Syntax("[island]") public void onInfo(Player player, @Optional Island island) { // `island` is resolved by IslandContextResolver: the caller's own island if omitted, // or the named island (tab-completed from @islands) if given. }

See Commands for how SkyblockCommand/MemberCommand /etc. use these resolvers in practice.

Cross-server messaging

ASPacketRegistry (registered on MessagingService in onEnable) is the RabbitMQ packet catalog for everything that has to stay consistent across servers. Understanding it is useful for tracing how island state propagates, even though most plugins should prefer the service methods and events above over sending these packets directly.

ID range

Packet

Fields

Purpose

0x100

IslandLoadRequestPacket

islandId, serverId

Sent by IslandService#spawnIsland to ask the resolved emptiest island server to load an island's world; awaited via sendWithReply.

0x101

IslandLoadResponsePacket

success

Reply to a load request.

0x102

MemberJoinPacket

islandId, playerId, invitedBy

Broadcast by MemberService#addMember; every server fires IslandMemberJoinEvent locally on receipt (no database write).

0x103

MemberLeavePacket

islandId, playerId, reason

Broadcast by kick/leave; every server fires IslandMemberLeaveEvent locally on receipt.

0x104

CoopAddPacket

islandId, playerId, addedBy

Broadcast by CoopService#add.

0x105

CoopRemovePacket

islandId, playerId

Broadcast by CoopService#remove.

0x106

IslandDeletePacket

islandId

Broadcast by WorldService#delete so whichever server currently hosts the world drops it without saving, before its database row is removed.

0x00/0x01

UniqueObjectUpdatePacket/Delete

uniqueId

Generic UUID-keyed cache sync, used by IslandRepository and PlayerRepository (UUIDSyncedRepository). Update triggers a cache refresh(); delete triggers a local invalidation.

0x02/0x03

LongObjectUpdatePacket/Delete

id

Same, Long-keyed — used by RoleRepository.

0x04/0x05

MemberObjectUpdatePacket/Delete

islandId, playerUuid

Same, composite-keyed — used by MemberRepository.

0x06/0x07

IslandStringKeyUpdatePacket/Delete

islandId, key

Same, island+string-keyed — used by UpgradeRepository (key is the UpgradeType name).

0x08/0x09

IslandPlayerKeyUpdatePacket/Delete

islandId, playerUuid

Registered in the catalog but not currently sent by any repository — CoopRepository (the only IndexedSyncedRepository<IslandPlayerKey, …>) has no-op publishUpdate/publishInvalidation, delegating co-op cache coherency entirely to CoopAddPacket/CoopRemovePacket instead.

Each *SyncedRepository registers its own exchange handler on construction (plugin.messaging().registerExchange(exchangeChannel, ...)), keyed by a channel constant from ASConstants (e.g. ISLAND_MANAGEMENT_CHANNEL, MEMBER_SYNC_CHANNEL, COOP_SYNC_CHANNEL, and one *_UPDATE_CHANNEL per repository) — these are the "three-tier cache" (local Caffeine → Redis → MySQL) invalidation paths described on SyncedRepository.

Model types worth knowing

Island

@Entity("islands"), implements ComplexPlaceholder (namespace island). Persisted fields: uniqueId, name, locked, level, spawn pose (spawnX/Y/Z/spawnYaw/spawnPitch), updatedAt/createdAt. Transient (hydrated relationships, not persisted): owner (IslandMember), members(), roles(), coops(), settings (EnumSet<IslandSettings>), upgrades() (Map<UpgradeType, Integer>).

Method

Behavior

hasPermission(Player, IslandPermission)

Owner and skyblock.admin always pass. Otherwise checks the caller's member role, then — if not a member — their co-op role.

canEditRole(Player, IslandRole)

Owner/skyblock.admin always pass. Otherwise the caller's role must outrank (weight() >) the role being edited.

findMember(UUID)/findCoop(UUID)

Optional lookups into the hydrated members/coops collections.

toggleSetting(IslandSettings)/flushSettings()

Stage a setting toggle (respecting mutual-exclusion groups) / commit staged toggles and clear the dirty map.

upgradeLevel(UpgradeType)

The island's current level for that upgrade track, 0 if never purchased.

IslandRole

@Entity("island_roles"), implements ComplexPlaceholder (namespace role). Fields: id (Long), islandId, kind (IslandRole.Type: MEMBER/VISITOR/COOP), name, weight (int, seniority — higher outranks lower), isDefault, createdAt. Transient: permissions (EnumSet<IslandPermission>).

Method

Behavior

hasPermission(IslandPermission)

true if the permission (or the ALL wildcard) is set, checking staged toggles first.

togglePermission(IslandPermission)/flushPermissions()

Stage a permission toggle / commit staged toggles.

IslandUpgrade/UpgradeType

IslandUpgrade is a @ConfigSerializable record (type, levels: Map<Integer, Level>) loaded from upgrades/*.yml, implementing ComplexPlaceholder (namespace upgrade). Each nested Level record carries level, price, currency, currencyDisplay, value, and unlockActions (a PaperActionList run once when that level is purchased).

UpgradeType is a plain enum with nine tracks: WORLDBORDER_SIZE, MEMBERS_LIMIT, COOP_LIMIT, GENERATOR, HOPPERS_LIMIT, CROP_GROWTH_SPEED, SPAWNERS_RATE, MOB_DROPS, MINECART_LIMITS.

IslandSettings

Enum of 18 togglable environment flags (ALWAYS_DAY, PVP, CREEPER_EXPLOSION, TNT_EXPLOSION, …), implementing ConfigurationEnum<ItemStackWrapper> (each value carries a menu icon loaded from settings.yml). ALWAYS_DAY/ALWAYS_MIDDLE_DAY/ALWAYS_NIGHT/ALWAYS_MIDDLE_NIGHT form a mutually exclusive time-lock group; ALWAYS_RAIN/ALWAYS_SHINY form a mutually exclusive weather-lock group (see conflictingSettings()).

IslandPermission

Enum of 52 in-island permission nodes plus the ALL wildcard, also ConfigurationEnum<ItemStackWrapper> (icons from permissions.yml). Checked via Island#hasPermission/IslandRole#hasPermission — these are not Bukkit permission nodes; see Roles, Permissions & Settings for the full catalogue and how roles.yml seeds them onto default roles.

Placeholders

Every model above doubles as a ComplexPlaceholder, so %island_*%, %role_*%, %member_*%, %upgrade_*% and the menu-scoped %setting_*%/%permission_*% chains resolve without extra wiring wherever an Island/IslandRole/IslandMember/IslandUpgrade is in scope. SkyblockPlaceholders additionally exposes %skyblock_player_island_*% — a chain point that resolves MemberService#findPlayerIsland for the placeholder's Player context, then continues into Island's own namespace (e.g. %skyblock_player_island_hasPermission_KICK_MEMBER%, used throughout the shipped menus as a view-requirements gate). See Placeholders for the full reference.

Last modified: 25 July 2026