Astral Realms Documentation Help

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

<dependency> <groupId>com.astralrealms</groupId> <artifactId>mobs</artifactId> <version>1.1-SNAPSHOT</version> <scope>provided</scope> </dependency>

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.

import com.astralrealms.mobs.MobsAPI; import org.bukkit.Location; import org.bukkit.entity.Entity; // Blueprint lookups MobsAPI.findBlueprintById("zombie-warrior"); // Optional<MobBlueprint> MobsAPI.getBlueprint(entityUniqueId); // Optional<MobBlueprint> // Spawning Entity mob = MobsAPI.spawnMob("zombie-warrior", location); // Throws IllegalArgumentException on unknown id Entity mob = MobsAPI.spawnMob(blueprint, location); // Entity

Method

Returns

Use

findBlueprintById(String id)

Optional<MobBlueprint>

Resolve a blueprint by id.

spawnMob(String blueprintId, Location)

Entity

Spawn a mob by blueprint id. Throws IllegalArgumentException if the id is not found.

spawnMob(MobBlueprint, Location)

Entity

Spawn a mob from an existing blueprint object.

getBlueprint(UUID entityUniqueId)

Optional<MobBlueprint>

Retrieve the blueprint of a spawned mob by its entity UUID.

Plugin handle

import com.astralrealms.mobs.AstralMobsPlugin; AstralMobsPlugin plugin = AstralMobsPlugin.getInstance();

Services

BlueprintServiceplugin.blueprints()

Manages blueprint loading and resolution.

plugin.blueprints().load(); // Re-scan blueprints/ from disk plugin.blueprints().findById("zombie-warrior"); // Optional<MobBlueprint> plugin.blueprints().all(); // Unmodifiable Map<String, MobBlueprint>

Method

Returns

Use

load()

void

Re-scan blueprints/ folder from disk and reload all blueprints.

findById(String id)

Optional<MobBlueprint>

Resolve a blueprint by id.

all()

Map<String, MobBlueprint>

Every loaded blueprint (read-only).

MobServiceplugin.mobs()

Manages the lifecycle of spawned mobs, including the repeating display/gear/metadata loops.

// Summoning Entity mob = plugin.mobs().summon(blueprint, location); // Entity // Lookups plugin.mobs().findByUniqueId(entityUUID); // Optional<AstralEntity> plugin.mobs().findByEntityId(entityId); // Optional<AstralEntity> plugin.mobs().entities(); // Map<UUID, AstralEntity> // Removal plugin.mobs().remove(astralEntity); // void

Method

Returns

Use

summon(MobBlueprint, Location)

Entity

Spawn a mob and return its Bukkit entity handle. Automatically spawns configured passengers and wires move control.

findByUniqueId(UUID)

Optional<AstralEntity>

Retrieve a spawned mob's wrapper by its entity UUID.

findByEntityId(int)

Optional<AstralEntity>

Retrieve a spawned mob's wrapper by its entity id (network id).

entities()

Map<UUID, AstralEntity>

Every currently spawned mob (read-only map of UUID → AstralEntity).

remove(AstralEntity)

void

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.yml force-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.yml requirement-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).

AstralEntity astralEntity = plugin.mobs().findByUniqueId(entityUUID).orElseThrow(); // Identity UUID uuid = astralEntity.uniqueId(); int entityId = astralEntity.entityId(); MobBlueprint blueprint = astralEntity.blueprint(); // Entity handle (the NMSMob instance) NMSMob nms = astralEntity.entity(); org.bukkit.entity.Entity bukkit = astralEntity.entity().getBukkitEntity(); // State boolean alive = astralEntity.alive(); astralEntity.updateHealthDisplay(); // Force a refresh of the health display astralEntity.remove(); // Despawn and untrack the mob

Method

Returns

Use

uniqueId()

UUID

The entity's UUID.

entityId()

int

The entity's network id.

blueprint()

MobBlueprint

The blueprint this mob is spawned from.

entity()

NMSMob

The underlying NMS mob (extends Pig).

alive()

boolean

Whether the mob is still spawned and alive.

updateHealthDisplay()

void

Force an immediate refresh of the health bar / overhead display.

remove()

void

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.

NMSMob mob = astralEntity.entity(); // Memory: arbitrary key-value storage mob.setMemory("aggression-level", 5); Object value = mob.getMemory("aggression-level"); // Returns "0" if key not found // Timers: track elapsed milliseconds since a start point mob.startTimer("attack-cooldown"); long elapsedMs = mob.getTimer("attack-cooldown"); // Milliseconds since startTimer was called

Method

Parameters

Returns

Use

setMemory(String key, Object value)

key, value

void

Store an arbitrary value in the mob's memory.

getMemory(String key)

key

Object

Retrieve a memory value, or "0" if not found.

startTimer(String key)

key

void

Mark the current time for a named timer.

getTimer(String key)

key

long

Return elapsed milliseconds since the timer was started, or 0 if not found.

Active goal tracking

Retrieve the simple class name of the currently running AI goal.

String goalName = mob.activeGoalName(); // e.g., "CastSkillGoal", or "none" if idle

Method

Returns

Use

activeGoalName()

String

Simple class name of the running AI goal, or "none" if no goal is active.

Move control and pathfinding

Replace the mob's movement controller or path navigation strategy.

mob.applyMoveControl(new CustomMoveControl(mob)); mob.applyNavigation(new FlyingPathNavigation(mob, level));

Method

Parameter

Returns

Use

applyMoveControl(MoveControl)

A MoveControl instance

void

Replace the mob's move controller. Blueprints use this to apply configured movement types.

applyNavigation(PathNavigation)

A PathNavigation instance

void

Replace the mob's path navigation.

canMove()

boolean

Hook queried by certain move controls (e.g., creaking-style freeze-on-observation). Defaults to true. Override in a subclass to gate movement.

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.

// Metadata index 6 is the Pose field EntityData<?> roaringPose = new EntityData<>(6, EntityDataTypes.POSE, net.minecraft.world.entity.Pose.ROARING); mob.putMetadataOverride(roaringPose); // Later, restore the real value mob.removeMetadataOverride(6); // Check what overrides are active Map<Integer, EntityData<?>> overrides = mob.metadataOverrides();

Method

Parameter

Returns

Use

putMetadataOverride(EntityData<?> data)

EntityData with index and value

void

Register a client-side metadata override at the index in data. Overwrites any existing override at that index.

removeMetadataOverride(int index)

Metadata index

void

Drop the override at this index, returning the client to the server's real value.

metadataOverrides()

Map<Integer, EntityData<?>>

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.

NMSMob passenger = mob.passengerMob(); // The passenger mob, or null mob.passengerMob(otherMob); // Set the passenger (or null)

Method

Parameter

Returns

Use

passengerMob()

NMSMob or null

Retrieve the passenger mob, if configured and alive.

passengerMob(NMSMob)

A mob or null

void

Update the stored passenger reference. Used internally by MobService during spawning and by listeners during passenger death.

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.

// Internal — called automatically SpoofRegistry.register(entityId, nmsMob); SpoofRegistry.unregister(entityId); NMSMob mob = SpoofRegistry.get(entityId);

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 via redirect-damage blueprint 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

spawn-mob-location

Global action; spawn a mob at a location (e.g., in a custom menu).

store-memory

Per-mob action; store a key-value pair in the mob's memory.

start-timer

Per-mob action; start a named timer on the mob.

send-entity-status

Per-mob action; send a client-visible status effect (e.g., thorns, hurt).

edit-entity-metadata

Per-mob action; override a metadata field and immediately broadcast to tracking players.

Completions and context resolvers

The plugin registers:

  • mobBlueprints completion handler: auto-complete mob blueprint ids in commands.

  • MobBlueprint context resolver: convert a string argument to a resolved MobBlueprint in 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.

See Casting Skills for how to configure skills on mobs.

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 the SPAWN_ENTITY packet 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:

  1. All spawned mobs are removed by MobService.shutdown().

  2. The display loop, gear loop, and metadata-reconciliation loop are cancelled.

  3. All mobs are removed from tracking.

  4. 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.

Last modified: 25 July 2026