Astral Realms Documentation Help

Overview

AstralPets is the collectible pet system for the AstralRealms network. Players acquire pets as items, consume the item to add the pet to their collection, feed it food to level it up, and equip (activate) up to a configurable number of pets at once to receive passive bonuses — stats, periodic money, potion effects, storage, no-fall, and modifiers to AstralShop / AstralJobs / AstralRotatingShop. One equipped pet can also be spawned: rendered in the world, following the player, and (for some blueprints) rideable.

Under the hood a spawned pet is driven by a hybrid, packet-based entity engine rather than a normal Bukkit mob. Each PetEntity pairs:

  • a real, server-side vanilla mob (a Pig - or Parrot-derived NMS entity chosen by EntityTags.FLYING) that is actually added to the world and drives physics, collision and goal-based pathfinding — including a custom FollowOwnerGoal built on vanilla PathNavigation (GroundPathNavigation/FlyingPathNavigation/WallClimberNavigation depending on the entity type) — with

  • a separate, fully plugin-controlled packet entity (PacketEntity) that is the only thing players ever actually see: it owns its own entity ID, per-viewer spawn/metadata/destroy packets, custom equipment and a floating name tag.

BaseEntityPacketListener (a PacketEvents listener) is what stitches the two together: every packet the real mob would normally broadcast (spawn, metadata, equipment, sound, status, NBT) is cancelled outright, while its movement packets (teleport, relative move, rotation, head/look, passengers, velocity) are rewritten to use the packet entity's ID and resent — so the client only ever perceives the fake, fully controlled entity moving around.

Pets, blueprints and player data

Concept

Type

Notes

Pet

Pet

An owned instance: a random UUID, a renamable Component name, its PetBlueprint, experience/level, a PetInventory (storage), and timestamps (equippedSince, lastMoneyGainTime) used for the money effect.

PetBlueprint

PetBlueprint (@ConfigSerializable)

The template: id, defaultName, display item, an EntityBlueprint (entity type, name tag, baby, rideable, attribute overrides), a PetRarity, its effects list, and maxLevel. Loaded from blueprints/*.yml.

PetRarity

PetRarity

id, display, color, and a levelExpression — a Crunch-compiled math expression over level that yields the XP required to reach that level.

PetPlayerData

PetPlayerData

Per-player, synced via AstralSync: the full pets list the player owns, the activePetsIds (equipped pets, up to the max-active-pets cap), and a single selectedPetId — the pet currently spawned in the world.

A pet is added to PetPlayerData by right-clicking with its item (PetListener#onConsume), which consumes the item and calls PetPlayerData#addPet. The reverse — [pickup-pet] — rebuilds the item stack via PetService#buildItemStack and removes the pet from the player's data.

Leveling

Pets gain experience only by being fed: right-clicking a spawned pet with a registered food item fires PetInteractEvent, and EntityListener looks the item up against foodBlueprints() and calls PetService#gainExperience(player, pet, entity, foodBlueprint.experience() * amount).

  • The XP required for the pet's next level is Pet#experienceForLevel(level), evaluated from its rarity's levelExpression (e.g. the shipped common rarity is 32+((level-1)^2/4)).

  • gainExperience loops applying level-ups (firing PetLevelUpEvent each time) while accumulated XP covers the next level's requirement, up to the blueprint's maxLevel; at max level further food is rejected with PET_MAX_LEVEL and XP is not accumulated.

  • Every level-up recalculates the pet's storage size from its storage effect and re-applies all of the pet's effects (Pet#removeEffect + Pet#applyEffect) so level-scaled values immediately update.

  • A short-lived floating text display shows XP gained above the player's head after every feed.

Passive effects

Effects live on the blueprint as a list of WrappedPetEffect (display text, next-level text, a Map<Integer, Double> of cumulative values per level, a maxValue/maxLevel, and the underlying PetEffect). Every PetEffect implementation is level-scaling: value(level) sums every entry at or below the pet's current level. Effects are (re)applied to the owner on equip (PetEquipEvent), on player-data load, and after every level-up, and removed on unequip (PetUnequipEvent), quitting, or being fed past max level; unequipping one pet re-applies the remaining active pets afterwards so overlapping effect types on other equipped pets aren't lost.

Registered id

Class

Target system

Behavior

stats

StatPetEffect

AstralStats

Adds a StatModifier (additive or percentage) to a given stat key while equipped.

money

MoneyPetEffect

Core economy

Deposits money on a per-effect interval, paid out by an async task that runs every 30s and only pays once the pet has been equipped (and last paid) longer than the interval.

potion

PotionPetEffect

Bukkit

Grants an infinite PotionEffect at an amplifier equal to the effect's value; applied synchronously.

storage

StoragePetEffect

Sizes the pet's own storage inventory, openable via [open-pet-container].

rideable

RideablePetEffect

Unlocks riding once its cumulative value reaches 1 and the blueprint's entity.rideable is true.

no-fall

NoFallPetEffect

Cancels fall damage for the owner while any active pet has a positive value at its level.

shop-modifier

ShopModifierPetEffect

AstralShop

Adds an item- or category-scoped ShopModifier via ShopAPI.

jobs-modifier

JobModifierPetEffect

AstralJobs

Adds a JobModifier (scoped to money or experience, optionally to one job) via JobsAPI.

rotating-shop-modifier

RotatingShopModifierPetEffect

AstralRotatingShop

Adds a percentage modifier via RotatingShopAPI.

See Pet Effects for the full per-effect configuration shape.

Active vs. equipped pets

  • Active (equipped) pets contribute their passive effects regardless of whether one is currently spawned. [equip-pet] enforces max-active-pets (config.yml, default 1, overridable per permission — the shipped default grants group.roturier a cap of 2) and refuses to equip two pets that share the same blueprint (CANNOT_EQUIP_IDENTICAL_PET).

  • Selected/spawned is a single pet — PetPlayerData#selectedPetId — that is actually rendered in the world. [spawn-pet] despawns any pet already spawned for that player first (EntityService#spawn calls findByPlayer(player).forEach(PetEntity::remove)), so only one pet can follow the player at a time even if several are active.

  • Spawning is gated by the WorldGuard integration: if the pets flag denies the location, [spawn-pet] aborts with PET_SPAWN_DENIED_HERE.

  • [ride-pet] mounts the owner on the currently spawned pet if its blueprint is rideable and its rideable effect value at the current level is at least 1.

  • /pets (aliases pet, familiers, familier) opens the pets-main menu by default; give/food/reset/ reload are admin subcommands under the same base command. See Commands.

  • /pokedex (aliases animalerie, bestiaire) opens the pokedex menu, populated from a max-level Pet instance cached per loaded blueprint (BlueprintService#cachedPets) — a bestiary of every blueprint regardless of ownership.

  • Renaming runs through a dialog whose title/body/field/button text comes from rename-dialog in config.yml, enforcing max-pet-name-length before invoking [rename-pet].

See Pet Blueprints for authoring blueprints and Pet Food for food items, the feeding flow, and the food item supplier. (config.yml's food-conversion key and the nothing-to-convert/conversion-success messages are leftovers from a removed conversion feature — they are currently dead and read/fired by nothing in the plugin.)

WorldGuard integration

If WorldGuard is present, WorldGuardHook registers a custom StateFlag named pets (default state ALLOW) during onLoad, and registers a SessionManager handler (PetsWGSessionHandler) during onEnable. WorldGuardHook.isPetsAllowed(player, location) returns false only when the flag resolves to DENY for that location — [spawn-pet] is the only caller, so the flag blocks spawning a pet in a region, not owning or equipping one. WorldGuard absent (or the flag failing to register) always allows spawning.

Requirements

Dependency

Required

Notes

Paper 1.21+

Yes

api-version: '1.21'; built against Java 25.

AstralCore

Yes

AstralPaperPlugin base, actions, placeholders, menus, dialogs, Configurate-based config loading.

packetevents

Yes

Drives the packet entity engine and the PetInteractListener/PetInventoryListener client-packet handling.

AstralStats

Yes

Backs the stats pet effect.

AstralShop

Yes

Backs the shop-modifier pet effect.

AstralJobs

Yes

Backs the jobs-modifier pet effect.

AstralRotatingShop

Yes

Backs the rotating-shop-modifier pet effect.

AstralSync

Functional

Not listed in plugin.yml, but PetPlayerData is persisted and synced across servers through SyncAPI and a registered PetSnapshotAdapter.

WorldGuard

Optional (softdepend)

Registers the pets region flag; see above.

WorldEdit

Optional (softdepend)

Used by WorldGuard's location adapter.

Architecture at a glance

plugins/AstralPets/ ├── config.yml ← menu title, rename-dialog text, max-active-pets, max-pet-name-length ├── rarities.yml ← rarity tiers + XP curve (level-expression) per rarity ├── messages.yml ├── blueprints/*.yml ← pet definitions: item, entity, rarity, effects, max-level └── food/*.yml ← food items and their XP value

Getter

Class

Responsibility

blueprints()

BlueprintService

Loads pet blueprints from the blueprints/ folder, caches a max-level Pet per blueprint for the pokedex.

foodBlueprints()

FoodBlueprintService

Loads food items and their XP values.

pets()

PetService

XP/level-up logic, building pet ItemStacks, PDC (de)serialization.

entities()

EntityService

Packet-entity lifecycle: spawn/despawn, viewer & world tracking, riding, spawn-location resolution.

menus()

MenuService

pets-main, pet-menu, pokedex menus.

dialogs()

DialogContainer

The rename dialog.

Player-triggered behavior is exposed as AstralCore actions rather than direct API calls:

Registered name

Class

Purpose

equip-pet

EquipPetAction

Marks a pet active, subject to max-active-pets and the no-duplicate-blueprint rule.

unequip-pet

UnequipPetAction

Marks a pet inactive and removes its effects.

spawn-pet

SpawnPetAction

Spawns the pet's packet entity (WorldGuard-gated) and sets it as selected.

despawn-pet

DespawnPetAction

Removes the spawned packet entity and clears the selected pet.

pickup-pet

PickupPetAction

Converts a pet back into an item stack in the player's inventory/mailbox and removes it from their data.

open-pet-container

OpenPetContainerAction

Opens the pet's storage inventory (no-op if its storage size is 0).

ride-pet

RidePetAction

Mounts the owner on the currently spawned pet if it's rideable at its level.

rename-pet

RenamePetAction

Renames a pet, enforcing max-pet-name-length.

For configuration keys and defaults see Configuration; for the full command surface see Commands; for placeholders see Placeholders; for static/programmatic APIs see Developer API.

Last modified: 25 July 2026