Developer API
AstralMobs exposes its services through the MobsAPI static façade and through the main plugin instance. Mobs are runtime entities that do not persist on reload — they spawn on demand and are cleaned up when the plugin disables or when a mob dies.
Maven coordinates
Repository: https://maven.astralrealms.fr/repository/maven-public/.
MobsAPI
Static lookups suitable for spawning mobs and querying blueprints without taking a hard dependency on the service classes. Initialized in onEnable and available immediately.
Method | Returns | Use |
|---|---|---|
|
| Resolve a blueprint by id. |
|
| Spawn a mob by blueprint id. Throws |
|
| Spawn a mob from an existing blueprint object. |
|
| Retrieve the blueprint of a spawned mob by its entity UUID. |
|
| Spawn a mob bound to an owning player. |
|
| The same, returning the tracked wrapper (blueprint, health display, |
|
| Spawn with placeholder attachments. |
|
| Spawn with per-spawn overrides. |
|
| The tracked mob behind an entity, if AstralMobs spawned it. |
|
| Remove a spawned mob and its displays. |
|
| Whether the entity is an AstralMobs mob. Reads the entity's own handle rather than looking anything up, so it is cheap enough to ask about every entity on the server. |
|
| A live view of every mob currently spawned, in no particular order — backed by the tracking map, not copied. Meant to be walked, not kept. |
|
| The same as Bukkit handles, for APIs that deal in those. |
Everything here is main thread only.
Placeholder attachments
spawnOwnedMob(blueprint, location, ownerId, attachments) grafts placeholder trees onto the mob, reachable as %mob_<key>_…% — which lets a plugin expose a domain object AstralMobs knows nothing about. AstralPets attaches the Pet behind a pet mob under "pet", so a blueprint can read %mob_pet_level%.
Prefer this over attaching after the fact: the attachments are in place before the blueprint's requirement-gated gear, health display and spawn actions run, so those already resolve against them.
Per-spawn overrides
The last overload takes a MobOverrides: it alters the blueprint for that spawn only — another rendered entity type or BetterModel model, another size, a baby form, extra equipment or potion effects, raw client-side metadata. Anything the overrides leave unset comes from the blueprint, and its goals, movement, animations and actions are untouched: the mob behaves exactly as the blueprint says, it just looks different. A null spawns the plain blueprint.
This is how AstralPets applies a pet skin: one mob-blueprint defines how a pet behaves, and each skin re-dresses it.
Plugin handle
Services
BlueprintService — plugin.blueprints()
Manages blueprint loading and resolution.
Method | Returns | Use |
|---|---|---|
|
| Re-scan |
|
| Resolve a blueprint by id. |
|
| Every loaded blueprint (read-only). |
MobService — plugin.mobs()
Manages the lifecycle of spawned mobs, including the repeating display/gear/metadata loops.
Method | Returns | Use |
|---|---|---|
|
| Spawn a mob and return its Bukkit entity handle. Automatically spawns configured passengers and wires move control. |
|
| Retrieve a spawned mob's wrapper by its entity UUID. |
|
| Retrieve a spawned mob's wrapper by its entity id (network id). |
|
| Every currently spawned mob (read-only map of UUID → AstralEntity). |
|
| Manually remove a mob from tracking and despawn it. |
Background loops: MobService runs three repeating tasks:
Display loop (configurable interval, default disabled): refreshes health displays (boss bars or overhead text) every N ticks. Controlled by
config.ymlforce-update-interval.Gear loop (configurable interval, default every tick): re-applies requirement-gated equipment and potion effects to track dynamic changes. Only touches mobs whose blueprint has requirement-gated gear. Controlled by
config.ymlrequirement-update-interval.Metadata reconciliation loop (every 10 ticks): re-broadcasts client-side metadata overrides to tracking players so dropped or mis-ordered packets self-heal. Only touches mobs with active overrides.
All three loops are cancelled and every spawned mob is despawned when the plugin disables.
AstralEntity wrapper
When a mob is spawned, the MobService wraps it in an AstralEntity that holds identity and display state. Retrieve an AstralEntity by calling plugin.mobs().findByUniqueId(uuid) or findByEntityId(id).
Method | Returns | Use |
|---|---|---|
|
| The entity's UUID. |
|
| The entity's network id. |
|
| The blueprint this mob is spawned from. |
|
| The underlying NMS mob (extends Pig). |
|
| Whether the mob is still spawned and alive. |
|
| Force an immediate refresh of the health bar / overhead display. |
|
| Despawn the mob and untrack it. Cleans up display entities. |
NMSMob — server-side mob entity
The NMSMob class extends Pig and represents the server-side mob entity. It implements ComplexPlaceholder for the mob: placeholder namespace (see Placeholders for available keys).
Memory and timers
Mobs have a shared memory store (persistent during the mob's lifetime, cleared on despawn) and a timer store for tracking elapsed time since a marker.
Method | Parameters | Returns | Use |
|---|---|---|---|
| key, value |
| Store an arbitrary value in the mob's memory. |
| key |
| Retrieve a memory value, or |
| key |
| Mark the current time for a named timer. |
| key |
| Return elapsed milliseconds since the timer was started, or |
Active goal tracking
Retrieve the simple class name of the currently running AI goal.
Method | Returns | Use |
|---|---|---|
|
| Simple class name of the running AI goal, or |
Move control and pathfinding
Replace the mob's movement controller or path navigation strategy.
Method | Parameter | Returns | Use |
|---|---|---|---|
| A MoveControl instance |
| Replace the mob's move controller. Blueprints use this to apply configured movement types. |
| A PathNavigation instance |
| Replace the mob's path navigation. |
| — |
| Hook queried by certain move controls (e.g., creaking-style freeze-on-observation). Defaults to |
Metadata spoofing
Mobs are Pigs on the server but render as a different type on the client. Use the metadata-override API to change client-side properties (pose, scale, etc.) without affecting the server's real entity state.
Method | Parameter | Returns | Use |
|---|---|---|---|
| EntityData with index and value |
| Register a client-side metadata override at the index in |
| Metadata index |
| Drop the override at this index, returning the client to the server's real value. |
| — |
| Every active override, keyed by metadata index. |
The PacketListener automatically sanitizes outgoing metadata packets: it strips type-specific fields that would crash the client, then forces in your overrides. Spoofing is bidirectional — the SpoofRegistry maps entity id → NMSMob so both SPAWN_ENTITY (type rewrite) and ENTITY_METADATA (field rewrite) packets are handled transparently.
Passenger handling
When a mob is a vehicle carrying a configured passenger, access the passenger through the NMSMob.
Method | Parameter | Returns | Use |
|---|---|---|---|
| — |
| Retrieve the passenger mob, if configured and alive. |
| A mob or null |
| Update the stored passenger reference. Used internally by |
The PassengerFollowMoveControl uses this field to steer the vehicle toward the passenger's movement target when the blueprint enables passenger control.
Spoof registry
The SpoofRegistry is an internal static map that tracks entity id ↔ NMSMob associations so the PacketListener can rewrite outgoing packets to show clients the spoofed type instead of the Pig. You generally do not call this directly — it is managed automatically by NMSMob constructor and destruction.
Events and listeners
The plugin fires no custom events. Instead, it listens to Bukkit events and applies custom logic:
MobListener
Handles Bukkit entity events for spawned mobs:
EntityDamageEvent: Cancels self-inflicted damage (mobs damaging themselves with their own projectiles or AoE), updates health displays on hit, and redirects damage to passengers when configured viaredirect-damageblueprint field.EntityDeathEvent: Runs configured death actions, suppresses drops/XP if configured, cleans up passenger references, and unregisters the mob from tracking.EntityPotionEffectEvent: Cancels Wither effect applications on players (prevents mobs from being able to apply Wither).
PacketListener
Intercepts outgoing packets to implement type spoofing:
SPAWN_ENTITY: Rewrites the entity type from Pig to the spoofed type.ENTITY_METADATA: Strips type-specific metadata fields that would crash the client, then forces in the mob's configured metadata overrides.
External plugins can rely on these listeners running automatically.
Extension points
Actions
Register custom mob actions via plugin.registerAction(...). The built-in actions are:
Action | Use |
|---|---|
| Global action; spawn a mob at a location (e.g., in a custom menu). |
| Per-mob action; store a key-value pair in the mob's memory. |
| Per-mob action; start a named timer on the mob. |
| Per-mob action; send a client-visible status effect (e.g., thorns, hurt). |
| Per-mob action; override a metadata field and immediately broadcast to tracking players. |
Completions and context resolvers
The plugin registers:
mobBlueprintscompletion handler: auto-complete mob blueprint ids in commands.MobBlueprintcontext resolver: convert a string argument to a resolvedMobBlueprintin ACF commands.
Type serializers
The plugin registers a custom type serializer for EquipmentSlot (Bukkit enum) so blueprints can reference slots like HEAD, CHEST, LEGS, FEET, HAND, OFF_HAND in YAML.
AstralSkill integration
AstralMobs integrates with AstralSkill via the CastSkillGoal AI goal. When a mob is configured to cast skills, the goal calls SkillService.castThroughPos(...) with the mob as the executor. This is a soft dependency — if AstralSkill is not present, skill-based goals fail gracefully at load time, and everything below is simply not registered (the interfaces live in AstralSkill).
See Casting Skills for how to configure skills on mobs.
Owned mobs as skill casters
A skill fired by an owned mob is cast with the owner as the caster, so the damage, the kill credit and the retaliation land on them rather than on the pet — the same rule the melee goal follows.
Pets and hit detection
Two mirrored rules keep pets from ruining a fight, registered through AstralSkill's target service:
Class | Registered as | Effect |
|---|---|---|
|
| An owned AstralMobs entity is never a valid skill target, whoever casts — owner, another player, or a mob. |
|
| A pet's own skill damage only ever lands on ownerless AstralMobs entities — never on players, never on anyone's pet. |
|
| Hands AstralSkill the mobs AstralMobs has spawned, so its hitbox cache can track them instead of searching the world. |
The filter exists because a pet stands exactly where its owner is fighting: without it, it soaks every area impact its owner throws, and a projectile spends a pierce on it instead of reaching what was aimed at. AstralSkill's targets: cannot express this — it compares entity types, and every AstralMobs entity shares one server-side type. The check is read straight off the entity's NMS handle, a type check and a null test, so the vanilla entities making up almost all of the per-tick sweep cost nothing.
Only skills are affected. Ordinary melee, arrows and every other vanilla damage source still hit a pet exactly as before. Pets are deliberately included in the target source — the filter is what hides them, and it runs over everything the source returns, which keeps a pet reachable by its owner's own self-targeted skills.
With caches.entities.registered-targets-only on, spawnedMobEntities() plus the players is the entire population AstralSkill tracks.
Type resolution
Mob blueprints specify a type: field (e.g., type: ZOMBIE). The NMSMob constructor resolves this Bukkit EntityType to the corresponding NMS EntityType for hitbox calculations and rendering. If a type cannot be resolved, it falls back to Pig (the server-side base class).
The spoofed type is stored in two forms:
NMS type (
EntityType<?>) — used for hitbox dimensions and pathfinding.PacketEvents type (
EntityType) — used in theSPAWN_ENTITYpacket for client-side rendering.
Lifecycle and persistence
Mobs are non-persistent. They exist only while the server is running and the plugin is enabled. On server shutdown or plugin reload:
All spawned mobs are removed by
MobService.shutdown().The display loop, gear loop, and metadata-reconciliation loop are cancelled.
All mobs are removed from tracking.
All health display entities (boss bars and overhead text displays) are cleaned up.
Restarting the server does not respawn mobs. To respawn them, execute the spawn command or call MobsAPI.spawnMob() again from a plugin.