Astral Realms Documentation Help

Overview

AstralDungeons adds instanced, party-based procedural dungeons to the AstralRealms network. A party requests a dungeon blueprint from the lobby; the request is broadcast to the dedicated dungeon servers, one of which generates a fresh instanced world for that blueprint and pulls the party in. Inside the instance the party explores procedurally arranged rooms, fights mobs and a boss for experience and loot, and — once they return to the lobby — the loot and experience they earned are handed to them there.

Two-module architecture

The plugin ships as two separate builds of the same com.astralrealms.dungeons.AstralDungeons main class, each targeting a different tier of the network:

Module

plugin.yml name

Runs on

Depends on

Role

Bridge

AstralDungeons-Bridge

Lobby / proxy-facing servers

AstralCore, AstralParty, AstralSync

Owns /dungeon create, advertises no dungeons of its own, tracks which dungeon servers exist and what they can host, brokers instance creation over RPC, and pays out the rewards a party collected once a player reconnects to the lobby.

Paper

AstralDungeons

Dedicated dungeon servers

AstralCore, AstralMobs

Owns dungeon generation, gameplay (room population, mob/boss spawning, decorated-pot loot, guidance trail), and per-player reward bookkeeping while a party is inside an instance.

Both modules are load: POSTWORLD and target api-version: 26.1.2.

Creating a dungeon instance

Player runs /dungeon create <blueprintId> (bridge, on the lobby) │ ▼ PartyAPI.findByPlayer(player) — must be in a party, else "You must be in │ a party to create a dungeon instance." ▼ ServerService#createInstance(player, party, blueprintId) │ RPC request over the "dungeons.servers" exchange (fanout — every subscribed │ dungeon server receives it): CreateDungeonRequestPacket{playerId, partyId, blueprintId} ▼ Every dungeon server: DungeonCreationListener │ ├─ ignores the request (no reply) if it is already at max-instances │ ├─ ignores the request (no reply) if it doesn't have that blueprint loaded │ ├─ replies success=false if that party already has an instance on it, or the │ │ party can't be resolved via PartyAPI │ └─ otherwise calls DungeonService#create(party, blueprint) — generates the world, │ rooms and spawn points — and replies success=true ▼ Bridge: acts on whichever CreateDungeonResponsePacket arrives first (5s RPC timeout); on success, TeleportationService sends the requesting player and every other party member to that response's serverId.

Because the request fans out to every eligible dungeon server and each one races to reply, capacity is balanced implicitly: only servers with a free instance slot and the blueprint attempt generation at all, and the first one to finish wins. ServerService#findEmptiest(String) exists on the bridge but is not currently called from this flow.

Server discovery (dungeons:servers)

Each dungeon server heartbeats its own state into the shared dungeons:servers Redis cache every 30 seconds (starting 1 second after enable), writing a DungeonServer record: its unique ID, name, current instance count, max-instances, and the set of blueprint IDs it has loaded. The bridge keeps a Caffeine cache of this data (refreshed every minute, 1‑minute repository TTL) and uses it to drive /dungeon create's tab completion — ServerService#availableBlueprints() returns the union of blueprint IDs offered by every server that still has a free instance slot.

Inside the dungeon

Once the party is teleported in, DungeonService#registerPlayer drops each player at the blueprint's spawn room component. From there the gameplay loop is:

  1. Explore the procedurally generated layout — rooms are pasted from schematics and stitched together from the blueprint's start/end/normal/cap room lists. See Dungeon & Room Blueprints.

  2. Fight mobs that spawn as participants walk within a room's detection/activation range; killing one awards the experience configured for that mob ID and rolls its loot table. See Loot & Rewards.

  3. Smash decorated pots scattered through the instance for a chance at loot from the blueprint's pots loot table; each pot holds a few rewards before it breaks.

  4. Reach and defeat the boss, spawned once a participant comes within activation range of the blueprint's boss location — killing it ends the instance with cause WON (an instance also ends early, with cause NO_ALIVE_PARTICIPANTS, if every participant dies or disconnects). See Dungeon Instances for the full lifecycle and state machine.

Instances are looked up and keyed three ways at once — by party ID, by world, and by player ID — so gameplay listeners (mob kills, pot interactions, player movement) can resolve "which dungeon is this?" from whichever context they fire in.

Reward carry-over

Rewards are not granted directly in the dungeon; they accumulate on a per-player DungeonPlayerData (experience total + a set of queued command strings) and are claimed back on the lobby:

  1. On join, if the player's party has an active instance, the dungeon server adds an empty DungeonPlayerData to its in-memory cache for that player.

  2. Killing mobs adds to experience; picking up a loot item that carries commands (dropped by mob kills or pots) cancels the pickup and instead adds those commands to the player's queued commands.

  3. On quit (including the forced kick after an instance ends), the dungeon server flushes the player's data to the dungeons:players_data:<uuid> Redis key and drops it from its own cache.

  4. Back on the lobby, once AstralSync fires PlayerDataLoadedEvent for the player, the bridge's PlayerDataService#claimRewards reads that key, runs the configured reward-actions (a PaperActionList, with the data exposed as %data_experience% via the player's placeholder container), dispatches any queued commands from the console, and deletes the Redis entry.

Feature map

Area

Page

Dungeon & room blueprints, generation

Dungeon & Room Blueprints

Mob/pot loot tables, reward carry-over

Loot & Rewards

Instance lifecycle, state machine, timeouts

Dungeon Instances

config.yml keys for both modules

Configuration

/dungeon command tree, permissions

Commands

Placeholders exposed by the plugin

Placeholders

Requirements

Dependency

Required by

Notes

AstralCore

Both modules

Configuration, messaging, cache, placeholder framework, AstralPaperPlugin base.

AstralParty

Bridge

A party is required to create an instance (PartyAPI.findByPlayer).

AstralSync

Bridge

Fires PlayerDataLoadedEvent, the trigger for reward claiming on the lobby.

AstralMobs

Paper

Spawns room/boss mobs and resolves a killed entity back to its MobBlueprint ID.

RabbitMQ

Both modules

Backs MessagingService — the dungeons.servers RPC exchange used for instance creation.

Redis

Both modules

Backs CacheService — the dungeons:servers server-advertisement cache and dungeons:players_data reward cache.

Last modified: 25 July 2026