Portals & Keys
Everything on this page lives on the bridge module (AstralDungeons-Bridge, data folder plugins/AstralDungeons-Bridge/), and only comes alive on a server whose group matches portal-group in its config.yml. It covers how a party gets into a dungeon; how the dungeon is generated once they are in is Dungeon & Room Blueprints, a different file format on a different server.
Bridge blueprints (blueprints/)
One YAML file per dungeon, loaded by the bridge's BlueprintService on enable and keyed by its own id field. A duplicate id is logged as a warning and the later file is skipped.
Field | Type | Description |
|---|---|---|
| String | The blueprint id. Must match the id of a dungeon blueprint on the dungeon servers — this is the string sent in |
|
| Display name, exposed as |
|
| The item that acts as this dungeon's key. See Keys. |
|
| The region that triggers entry. Two |
|
| Extra AstralCore requirements every party member must satisfy, evaluated after the key check. May be omitted or empty. |
| int | Smallest party (leader included) allowed to enter. |
| int | Largest party (leader included) allowed to enter. |
| Bukkit | Ambient particle rendered inside the portal region. Omit to render nothing. See Portal particles. |
There is no validation pass beyond the duplicate-id check: a blueprint whose id matches no dungeon server, or whose portal sits in a world that does not exist on this server, loads without complaint and simply never works.
Keys
A key is an ordinary item stack built from the blueprint's key block with one addition: BlueprintService stamps the persistent-data key dungeons:blueprint (a STRING) with the blueprint id. That stamp — not the material, name or lore — is what identifies a key, so two blueprints may share an appearance and remain distinguishable, and a hand-crafted look-alike is not a key.
Keys are required to enter and consumed on completion, but not at the portal: the key check at the portal only verifies possession. The stack is taken later, on the lobby, when the run's rewards are claimed — PlayerDataService#claimRewards scans the returning player's inventory for a key matching the blueprint they ran and removes exactly one (decrementing the stack if it holds more). A player who never reaches the reward claim keeps their key.
Obtaining keys — the dungeons.keys supplier
The bridge registers an AstralCore ItemStackSupplier under the namespace dungeons.keys, so a stamped key can be produced from any config that accepts an item:
The supplier completes to every loaded blueprint id, and implements the reverse lookup too — an existing stack resolves back to dungeons.keys:<blueprint id>, so crates, shops and quest rewards that ask "what item is this?" identify keys correctly. An unknown id yields no item rather than an error.
Entering a portal
PortalListener reacts to PlayerMoveEvent (explicit block changes only) and fires once per entry: the portal the player currently stands in is remembered, so walking around inside it does not retrigger, and leaving re-arms it. While a create request is in flight for a player, every further move is ignored.
The gates run in this order. Each of the first four sends its message and bumps the player back out — a velocity impulse opposite to the direction they walked in, plus an enderman-teleport sound:
A server must be available.
ServerService#findEmptiest(id)must find a dungeon server that advertises this blueprint and is below itsmax-instances. →no-available-serverThe player must be in a party. →
no-partyThe player must be the party leader. A member who walks in gets bounced; only the leader can pull the party in. →
not-party-leaderParty size must fit.
party.members().size() + 1must be within[minimum-players, maximum-players]. →invalid-party-size(with%min%/%max%)Every member must pass the requirements. Each member — leader included — must hold a key for this blueprint and satisfy the blueprint's
requirementslist. →failed-requirements
Only step 5 is asynchronous, and it is the point where the player is marked "processing". Note that a failure at step 5 does not bump the player back out; they stay standing in the portal, and must step out and back in to retry.
Once every gate passes, the player gets creation-start and the create RPC goes out — see Overview for the rest of the handshake.
Checking requirements across servers
A party's members may be spread across the network, so the key/requirement check cannot assume they are local. RequirementsService#checkForRequirements resolves each member individually:
Player is online here → checked locally, synchronously.
Player is elsewhere → a
CheckRequirementsRequestPacket{playerId, blueprintId}goes out on thedungeons.requirementsRPC exchange; whichever server has that player replies with aCheckRequirementsResponsePacketcarrying the same local check's result.
The party passes only if every member's future resolves true. A member nobody can resolve (offline, or on a server that does not reply) never completes a true, so the party does not get in.
The local check itself is deliberately strict: no key means an immediate false, and a requirement list that throws while evaluating counts as unmet (the player is shown unexpected-error and the failure is logged) rather than being waved through.
Portal particles
When the server's group matches portal-group, a task runs every 5 ticks (starting 5 seconds after enable) and, for each blueprint that declares a particle, spawns 5 particles at the portal cuboid's centre with the offset set to half the region's width/height/length — so the particles fill the region rather than sitting at a point. They are forced (rendered even with reduced particle settings) and sent only to players within 64 blocks.
A blueprint with no particle is skipped, so an invisible portal is a supported configuration.