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.
A spawned pet is an AstralMobs mob. PetEntity#spawn looks up the pet's mob-blueprint (entity.mob-blueprint, defaulting to pet-<blueprint id>) and calls MobsAPI.spawnOwnedMob(...) bound to the owner, so AstralMobs drives everything in the world: the rendered type, the follow-owner and idle-animation goals, move control and pathing. AstralPets keeps only the pet-domain concerns on top of it — a two-line packet nametag mounted on the mob, owner/pet bookkeeping, riding and equipment helpers, and the despawn event.
The pet is grafted onto the mob's placeholder tree as part of the spawn, so the mob blueprint's goals, skills, requirement-gated gear and spawn actions can read %mob_pet_name%, %mob_pet_level%, %mob_pet_blueprint_id% and so on. The Pet is held by reference, so levelling up or renaming is picked up without re-attaching. A pet naming an unknown mob blueprint logs an error and does not spawn.
PetEntity still extends the plugin's PacketEntity, but the packet entity itself is dormant: spawning broadcasts no packet-entity spawns, and the identity accessors delegate to the live AstralMobs entity. The old BaseEntityPacketListener is gone — AstralMobs' own packet listener does the type spoofing, so nothing needs to rewrite or cancel the real mob's packets any more.
Attributes are layered: the mob blueprint's, then the pet blueprint's entity.attributes, then the skin's — the skin is applied last, so its minecraft:scale or movement_speed wins.
Pets, blueprints and player data
Concept | Type | Notes |
|---|---|---|
Pet |
| An owned instance: a random |
PetBlueprint |
| The template: |
PetRarity |
|
|
PetSkin |
| A permanent look loaded from |
PetPreset |
| A named snapshot of a player's active pets ( |
PetPlayerData |
| Per-player, synced via AstralSync: the full |
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'slevelExpression(e.g. the shippedcommonrarity is32+((level-1)^2/4)).gainExperienceloops applying level-ups (firingPetLevelUpEventeach time) while accumulated XP covers the next level's requirement, up to the blueprint'smaxLevel; at max level further food is rejected withPET_MAX_LEVELand XP is not accumulated.Every level-up recalculates the pet's storage size from its
storageeffect 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 (a label, a free-form unit, a Map<Integer, Double> of cumulative values per level, a maxValue/maxLevel/unlockLevel, and the underlying PetEffect). How an effect reads is no longer part of the blueprint: a PetEffectView binds an effect to the pet's level and transformers turn that into lines. 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 |
|---|---|---|---|
|
| AstralStats | Adds a |
|
| Core economy | Deposits money on a per-effect |
|
| Bukkit | Grants an infinite |
|
| — | Sizes the pet's own storage inventory, openable via |
|
| — | Unlocks riding once its cumulative value reaches 1 and the blueprint's |
|
| — | Cancels fall damage for the owner while any active pet has a positive value at its level. |
|
| AstralShop | Adds an item- or category-scoped |
|
| AstralJobs | Adds a |
|
| AstralRotatingShop | Adds a percentage modifier via |
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]enforcesmax-active-pets(config.yml, default1, overridable per permission — the shipped default grantsgroup.roturiera cap of2) 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#spawncallsfindByPlayer(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
petsflag denies the location,[spawn-pet]aborts withPET_SPAWN_DENIED_HERE.[ride-pet]mounts the owner on the currently spawned pet if its blueprint isrideableand itsrideableeffect value at the current level is at least 1.
Menus & commands
/pets(aliasespet,familiers,familier) opens thepets-mainmenu by default; give/food/reset/ reload are admin subcommands under the same base command. See Commands./pokedex(aliasesanimalerie,bestiaire) opens thepokedexmenu, populated from a max-levelPetinstance cached per loaded blueprint (BlueprintService#cachedPets) — a bestiary of every blueprint regardless of ownership.Renaming runs through the
renamedialog indialogs/, enforcingmax-pet-name-lengthbefore invoking[rename-pet].config.yml's oldrename-dialogblock is gone.Presets are created and deleted through the
preset-create/preset-deletedialogs and applied from thepresetslayout of the main menu.
See Pet Blueprints for authoring blueprints, Pet Skins for looks, Pet Presets for saved loadouts, and Pet Food for food items, the feeding flow, and the food item supplier.
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 |
|
AstralCore | Yes |
|
AstralMobs | Yes | Spawns and drives every pet — see the engine description above. A pet's |
packetevents | Yes | The nametag display and the |
AstralStats | Yes | Backs the |
AstralShop | Optional (softdepend) | Backs the |
AstralJobs | Optional (softdepend) | Backs the |
AstralRotatingShop | Optional (softdepend) | Backs the |
AstralSync | Functional | Not listed in |
WorldGuard | Optional (softdepend) | Registers the |
WorldEdit | Optional (softdepend) | Used by WorldGuard's location adapter. |
The three shop/jobs effects are provided by hooks: their effect classes are only registered once the matching plugin is present, and a blueprint naming one on a server without it has that effect skipped with a warning rather than failing to load.
Architecture at a glance
Getter | Class | Responsibility |
|---|---|---|
|
| Loads pet blueprints from the |
|
| Loads skins, builds and recognises skin items, applies a skin, and turns an applied skin into AstralMobs spawn overrides. |
|
| Loads food items and their XP values. |
|
| XP/level-up logic, building pet |
|
| Packet-entity lifecycle: spawn/despawn, viewer & world tracking, riding, spawn-location resolution. |
|
|
|
|
| The |
|
| The plugin-scoped transformers loaded from |
Player-triggered behavior is exposed as AstralCore actions rather than direct API calls:
Registered name | Class | Purpose |
|---|---|---|
|
| Marks a pet active, subject to |
|
| Marks a pet inactive and removes its effects. |
|
| Spawns the pet through AstralMobs (WorldGuard-gated) and sets it as selected. |
|
| Removes the spawned entity and clears the selected pet. |
|
| Converts a pet back into an item stack in the player's inventory/mailbox and removes it from their data. |
|
| Opens the pet's storage inventory (no-op if its storage size is 0). |
|
| Mounts the owner on the currently spawned pet if it's rideable at its level. |
|
| Renames a pet, enforcing |
|
| Saves the active pets as a named preset. |
|
| Swaps the active pets for a preset's. |
|
| Deletes a preset. |
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.