Astral Realms Documentation Help

Pet Blueprints

A blueprint defines one pet species: its display item, the entity it spawns as, its rarity, and the effects that scale with level. Blueprints live in plugins/AstralPets/blueprints/*.yml (sub-folders are scanned recursively) and are loaded by BlueprintService — each file deserialises into exactly one PetBlueprint.

Minimal example

The plugin ships a single example blueprint, blueprints/simple.yml:

id: "simple" default-name: "<gray>Simple Cow" rarity: "test" max-level: 20 item: material: "stone" name: "%pet_name% Lvl %pet_level%" lore: - "A simple cow." - "It doesn't do much." - "Level: %pet_level%" - "Experience: %pet_experience%" - "" - "Effects" - "%pet_effects%" entity: type: "cow" baby: true rideable: false name: "%pet_name%" sub-name: "Level %pet_level%" attributes: "minecraft:max_health": 10 "minecraft:follow_range": 16 "minecraft:movement_speed": 0.2 "minecraft:flying_speed": 0.1 "minecraft:scale": 0.7 "minecraft:jump_strength": 2 effects: example-stats: type: "stats" display: "%value% Stats" next-level-display: "+%value% Stats" stat: "astralrealms:speed" modifier-key: "astralpets:speed_boost" modifier-type: "PERCENTAGE" modifier-values: 1: 10 2: 20 3: 30 shop-modifier: type: "shop-modifier" display: "%value% Shop Modifier" next-level-display: "+%value% Shop Modifier" key: "astralpets:shop_modifier" scope: BUY modifier-type: "RELATIVE" values: 1: 5 2: 10 jobs-modifier: type: "jobs-modifier" display: "%value% Jobs Modifier" next-level-display: "+%value% Jobs Modifier" modifier-key: "astralpets:jobs_modifier" modifier-scope: MONEY modifier-type: "RELATIVE" job-id: null values: 1: 5 2: 10

Top-level fields

Field

Type

Required

Description

id

String

Yes

Blueprint identifier. If two files resolve to the same id, the duplicate is logged and skipped — since files are loaded into an unordered Set first, which copy is kept isn't guaranteed to follow file/folder order.

default-name

Component (MiniMessage)

Yes

Name given to a newly-created Pet instance. Players can rename their pet afterwards; this is only the initial value.

rarity

String

Yes

Id of a rarity defined in rarities.yml (see Rarities). Loading fails with Invalid rarity ID: <id> if it doesn't resolve.

max-level

int

No

Highest level the pet can reach. Defaults to 20 if omitted.

item

ItemStackWrapper

Yes

The pet's inventory/menu representation (see item).

entity

EntityBlueprint

Yes

The world entity spawned when the pet is summoned (see entity).

effects

Map<String, WrappedPetEffect>

No

Named effect entries that scale with level (see effects). Map key is a free-form id, unused beyond YAML organisation.

If id, default-name, item, entity, or rarity is missing, PetBlueprintTypeSerializer throws and the file fails to load (BlueprintService logs the error and continues with the remaining files).

item

item is a standard AstralCore ItemStackWrapper — the same template used by menu items, so material, name, lore, enchantments, item-flags, amount, and item components all work the same way. See Menu Items for the full field reference.

The name and lore are placeholder-aware and are re-rendered against the specific Pet instance every time the item is built (PetService.buildItemStack). In addition to the general AstralCore placeholders, the pet placeholders are available directly (unprefixed, since the item template is resolved with the pet registered as the current placeholder context):

Placeholder

Resolves to

%pet_name%

The pet's current (possibly player-renamed) display name.

%pet_level%

The pet's current level.

%pet_experience%

Experience accumulated toward the next level (resets to 0 on level-up, see How leveling works).

%pet_effects%

One lore line per configured effect, using each effect's display (or display-stats-max once maxed) component. A single %pet_effects% lore entry expands into multiple lines — one per entry under effects.

The built ItemStack carries the full Pet (id, name, blueprint, experience, level, inventory) serialised into its PDC, so a live pet item always reflects that specific pet's state — not just the blueprint template.

entity

entity (PetBlueprint.EntityBlueprint) describes the world entity spawned when the pet is summoned.

Field

Type

Description

type

Bukkit EntityType

Mob type to spawn, e.g. cow, wolf, allay. See Supported entity behaviors for which types get bespoke movement/AI.

baby

boolean

Spawns the pet as a baby variant. Only honoured for entity types that resolve to AgeablePetEntity (cow, pig, happy_ghast) or its subclass ArmadilloPetEntity (armadillo) — every other type always renders as an adult.

rideable

boolean

Whether the entity can be mounted at all. This is only half the gate: the pet also needs its rideable effect to reach a value of at least 1 at its current level — the [ride-pet] action (EntityService.ride) checks both and messages the player with the level still required if the effect isn't there yet.

name

Component (MiniMessage)

First line of the floating nametag rendered above the entity. Supports %pet_level% and the other pet placeholders (resolved through the same placeholder container as the name/sub-name pair).

sub-name

Component (MiniMessage)

Second line of the floating nametag, rendered below name.

attributes

Map<Attribute, Double>

Namespaced Bukkit attribute keys (e.g. minecraft:max_health) mapped to their base value. Applied via Attribute#setBaseValue right after the entity spawns — any attribute the target mob type doesn't support is silently skipped. Common keys: minecraft:max_health, minecraft:follow_range, minecraft:movement_speed, minecraft:flying_speed, minecraft:scale, minecraft:jump_strength.

Supported entity behaviors

Any Bukkit EntityType can be used as entity.type — unrecognised types fall back to the generic PetEntity packet implementation with no goal selector (it just follows its owner). The following types resolve to a dedicated PetEntity subclass with type-appropriate movement and rendering:

entity.type

Implementation

slime, magma_cube

SlimePetEntity

cow, pig, happy_ghast

AgeablePetEntity

armadillo

ArmadilloPetEntity (extends AgeablePetEntity)

hoglin

HoglinPetEntity

strider

StriderPetEntity

allay

AllayPetEntity

frog

FrogPetEntity

polar_bear

PolarBearPetEntity

wolf

WolfPetEntity (extends TameablePetEntity)

sniffer

SnifferPetEntity

donkey

ChestedHorsePetEntity

effects

Each entry under effects is a WrappedPetEffect — it wraps one of the registered effect implementations (type) with the display text and per-level value scaling shared by every effect. Available types: stats, money, potion, storage, rideable, no-fall, shop-modifier, jobs-modifier, rotating-shop-modifier. Field-by-field behavior of each type is documented on Pet Effects; the shared shape every entry accepts is:

Field

Type

Description

type

String

The effect implementation id. Unknown types fail blueprint loading.

display

Component

Text shown for %pet_effects% while the effect is active. Supports %value% (the effect's cumulative value at the pet's current level) and %maxValue% (its cumulative value at its highest configured level).

next-level-display

Component

Text used to preview the next level's gain, with %value% bound to that single level's increment.

display-stats-max

Component

Optional. Overrides display once the effect is maxed (current level ≥ its highest configured level, or its cumulative value already reached the max).

values/modifier-values

Map<int, double>

Per-level value map: key is the pet level, value is the amount added at that level. Either key name is accepted — values is checked first, and modifier-values is used if it's absent or empty.

…effect-specific fields

e.g. stat/modifier-key/modifier-type for stats, key/scope for shop-modifier. See Pet Effects.

How the value map drives scaling

values/modifier-values entries do not need one per level — but the two consumers of the map read it differently:

  • The value an effect actually applies (e.g. the stat modifier StatPetEffect grants) sums every entry whose key is at or below the pet's current level, so it's safe to leave gaps between levels.

  • Displayed totals, "is maxed" checks, and the storage effect's inventory-size lookup read a precomputed running total keyed by the exact level — a level with no explicit entry (and no prior entry carried forward into it) resolves to 0. In practice blueprints define an entry at every level they want the display/scaling to reflect.

The storage effect type is special-cased: PetBlueprint.build() reads its value at level 1 to size the pet's initial storage inventory, and Pet.handleLevelUps() re-reads it at the pet's new level after every level-up to resize the inventory in place.

Rarities

Rarities are shared across all blueprints and defined once in rarities.yml (not per-file), loaded into a RaritiesConfiguration at plugin startup/reload, before blueprints are loaded:

rarities: commun: id: common display: "<#d5d5d5>Commun" level-expression: "32+((level-1)^2/4)" color: "#d5d5d5" uncommun: id: uncommon display: "<#6aa84f>Inhabituel" level-expression: "34+((level-1)^2/2)" color: "#6aa84f" rare: id: rare display: "<#357df8>Rare" level-expression: "36+(level-1)^2" color: "#357df8" epic: id: epic display: "<#9441d3>Épique" level-expression: "38+((level-1)^2*1.5)" color: "#9441d3" legendary: id: legendary display: "<#ffd700>Légendaire" level-expression: "40+((level-1)^2*2)" color: "#ffd700"

Field

Type

Description

id

String

Identifier blueprints reference via their own rarity key. The map key above it (commun, rare, …) is free-form and only used to organise the file — lookups match on id, not the map key.

display

Component (MiniMessage)

Rarity label, e.g. used in menus/lore.

color

TextColor

Hex or named color associated with the rarity.

level-expression

String (Crunch expression)

Formula, in terms of a single variable level, for the experience required to advance into that level. See How leveling works.

rarities.yml ships the five rarities above (common, uncommon, rare, epic, legendary) — none of them is named test, the rarity id referenced by the shipped simple.yml blueprint.

How leveling works

Pet.experienceForLevel(level) compiles the pet's rarity level-expression with Crunch (variable level) and evaluates it for the level being levelled into. That result is the experience required to go from level - 1 to level — not a cumulative lifetime total. PetService.gainExperience adds incoming experience to pet.experience(), then loops: while the accumulated amount is at least experienceForLevel(pet.level() + 1), it subtracts that requirement, fires a PetLevelUpEvent, and increments the pet's level (stopping at max-level, where any surplus experience is discarded). %pet_experience% and %pet_nextLevelExperience% (see Placeholders) reflect this same per-level counter.

Using the shipped simple.yml's rare rarity as an example — 36+(level-1)^2 — reaching level 2 costs 36 + (2-1)^2 = 37 XP, reaching level 3 costs 36 + (3-1)^2 = 40 XP, and so on; each figure is the cost of that single level, not a running total.

Item suppliers

AstralPets registers a pets ItemStackSupplier (PetsItemSupplier) with AstralPaperAPI at startup. Anything elsewhere in AstralCore/AstralItems that accepts a generic supplier-backed item key (menus, shops, kits, /items give-style commands) can reference a pet blueprint as pets:<blueprint-id> — e.g. pets:simple for the shipped example. Resolving that key builds a fresh level-1 pet from the blueprint (a new UUID each time) via PetService.buildItemStack(PetBlueprint), distinct from /pets give, which uses the same builder directly rather than going through the supplier lookup. The supplier's completion list is rebuilt from BlueprintService.ids() on every reload, and PetsItemSupplier.keyOf(ItemStack) reverses an existing pet item back to its blueprint's key by reading the Pet stored in its PDC.

Hot reload

/pets reload (pets.reload) calls AstralPets.loadConfiguration(), which reloads rarities.yml before BlueprintService.load() re-reads every file under blueprints/ — so a blueprint referencing a rarity added in the same reload will resolve correctly. The blueprint registry and the max-level preview cache (BlueprintService.cachedPets(), one synthetic max-level Pet per blueprint, exposed as %pets_blueprints% for menus that list every blueprint without requiring a player to own one) are cleared and rebuilt from scratch, and PetsItemSupplier/PetsFoodItemSupplier completions are refreshed immediately after.

Last modified: 25 July 2026