Astral Realms Documentation Help

Loot, Shop & Rewards

A room's rewardType — set by the door the party walked through — decides what spawns in it once its mobs are cleared: artifacts, coins, or (for shop rooms, unconditionally) a shop offer. Reaching the final room or dying additionally spawns a reward chest. This page covers artifacts.yml, shop.yml, coins.yml, rewards.yml, and the reward carry-over back to the lobby.

Artifacts (artifacts.yml)

artifacts: 1: id: "test-1" chance: 50 unique: false item: "diamond_sword" description: - "<blue>Sword of Testing" - "<gray>A powerful sword used for testing." actions: - "[message] You have used the Sword of Testing!"

Key

Type

Description

artifacts.<n>.id

string

Artifact id, looked up by ArtifactsConfiguration#findById (case-insensitive). Referenced by shop.yml's offers.

artifacts.<n>.chance

double

Relative weight for random selection when an ARTIFACTS room spawns its choices — see below.

artifacts.<n>.unique

boolean

If true, a player who has already discovered this artifact ID in the current instance (instance.hasDiscoveredArtifact) is excluded from future draws for it, for that player.

artifacts.<n>.item

ItemStack (material id)

The display item.

artifacts.<n>.description

component list

Lore/description lines shown above the artifact.

artifacts.<n>.actions

action list

Run against the claiming player when the artifact is selected.

When a room's rewardType is ARTIFACTS, ArtifactService#spawnArtifacts spawns one artifact choice per participant, per REWARD position component in the room — each player sees their own independent draw (weighted by chance, excluding artifacts already marked unique and discovered by that player), with no duplicate artifact picked twice within the same draw for that player.

Selecting an artifact — ArtifactSelectEvent

Fully qualified name: com.astralrealms.tower.event.artifact.ArtifactSelectEvent (extends AbstractCancellableEvent).

Fired by ArtifactService#claimArtifact when a player interacts with one of their spawned artifact entities (via ArtifactsPacketListener). Cancellable — cancelling skips running the artifact's actions and leaves the artifact entity in place.

Field

Type

Description

player

Player

The claiming player.

instance

LocalTowerInstance

The tower instance.

room

RoomInstance

The room the artifact was in.

artifact

ArtifactEntity

The claimed artifact (.blueprint() is the ArtifactsConfiguration.Artifact).

If not cancelled, the artifact's actions run against the player and every artifact entity spawned for that player in the room (RoomInstance#removeArtifactsForPlayer) is despawned and cleared — claiming one of several spawned choices discards the rest, it's not a per-entity removal.

Shop (shop.yml)

offers: test-1: 10 test-2: 50 test-3: 100 price-display: - "<green>Price: <yellow>%price% coins"

Key

Type

Description

offers

map of artifact id → int

Coin price for each artifact offered in shop rooms. Every key must match an artifacts.yml id — ShopService#load throws if it can't resolve one.

price-display

component list

Extra lore lines appended below each shop artifact's own description; %price% is registered directly per-viewer with that offer's price.

Shop rooms (RoomType.SHOP) always spawn one offer per REWARD position component, chosen at random from offers without repeats within the room, and skip mob spawning entirely (setupRoom transitions a shop room straight to RoomPhase.REWARDS). Buying an offer (ShopService#buyShopOffer) checks the offer hasn't already been purchased (shop-already-purchased) and the player has enough %tower_coins% (shop-not-enough-points — see the messages warning), deducts the price from PlayerData.coins(), marks the offer purchased, and runs the artifact's actions.

Coins (coins.yml)

# General rooms drop-rate: 50 min-amount: 1 max-amount: 5 item: gold_nugget # Coins rooms coins-rewards: 450

Key

Type

Description

drop-rate

double

Intended per-kill drop probability. CoinsListener compares it directly against ThreadLocalRandom#nextDouble() (range [0, 1)) with if (random > dropRate) return; — see the warning below.

min-amount/max-amount

int

Inclusive range for how many coins a single mob-kill drop is worth.

item

ItemStack (material id)

The item used to represent dropped/rewarded coin stacks.

coins-rewards

int

Total coin amount granted when a room's rewardType is COINS — split into up to 64-count stacks and scattered at the room's REWARD position components.

Coins are physical display entities (PacketItem) in the world; walking within 3.5 blocks despawns nearby piles and credits every participant's PlayerData.coins() with the summed amount (not just the picker-upper — coins are a shared/party resource). See Placeholders: %tower_coins%.

Room & end rewards (rewards.yml)

rewards: 1: reward-1: item: "diamond_sword" actions: - "[message] Congratulations! You have reached room 1!"

Key

Type

Description

rewards.<roomIndex>.<entryKey>.item

ItemStack (material id)

Display item for the reward chest at that room index.

rewards.<roomIndex>.<entryKey>.actions

action list

Run against the claiming player when the chest is opened.

rewards.<roomIndex>.<entryKey>.chance

double

Weight used to pick between multiple entries under the same room index (only consulted if more than one entry exists for that index — a single entry is always used).

RewardsConfiguration#getReward(roomIndex) picks (or weighted-randomly selects, if more than one entry exists for that index) the entry for a given room index. A reward chest is spawned (RoomService#spawnRewardsChests) whenever an instance ends with cause DEATH, or with COMPLETED on the instance's last room — right-clicking it (RewardListener) marks that player as having claimed it, plays a totem effect, sends room-reward (or completion-reward on the last room, with <room> = the room index), and queues the chest's actions for carry-over. Disconnecting from a tower instance before claiming a chest queues that room's reward automatically (RewardListener#onQuit) so players don't lose it by leaving.

Once every participant has claimed the room's reward chest, the instance is destroyed (InstanceService#endInstance(instance, EndCause.COMPLETED), checked 5 ticks after the last claim).

Reward carry-over

Rewards are never granted directly inside the tower; they accumulate as CachedRewards (a PaperAction string list + the room index they were earned at) in a 14-day-TTL Redis-backed cache (RewardService, keyed tower:rewards/tower:player_rewards:<uuid>), and are claimed back on the lobby:

  1. Claiming a room-reward or end-of-run chest (or quitting before claiming) calls RewardService#cacheReward(playerId, CachedRewards), which stores the entry and links it to the player.

  2. On the lobby, once AstralSync fires PlayerDataLoadedEvent for the returning player, the bridge's RewardsListener reads every cached reward for that player (findRewardsByPlayer), runs each entry's action list against the player from the console (PaperActionFactory), fires a TowerFinishedEvent per reward, deletes the cache entry (RewardService#deleteReward), logs a tower_instance_finished analytics event, and finally deducts one daily ticket from the player's TowerPlayerData for each reward whose room index is ≥ 1 (the lobby room, index 0, doesn't consume a ticket).

TowerFinishedEvent

Fully qualified name: com.astralrealms.tower.bridge.event.TowerFinishedEvent (extends AbstractEvent, bridge module).

Fired by RewardsListener once per claimed CachedRewards entry being processed on the lobby. Not cancellable — notification only, after the reward's actions have already run.

Field

Type

Description

player

Player

The player whose reward was just processed.

room

int

The room index the reward was earned at.

@EventHandler public void onTowerFinished(TowerFinishedEvent event) { // event.room() -> how far the player's run reached }
Last modified: 25 July 2026