Developer API
AstralSkill exposes its casting and lifecycle API through the SkillAPI static façade and the SkillService. Consumers (AstralClasses, AstralMobs, and other plugins) call cast methods with a skill id, a caster entity, and optionally a PlaceholderContainer for custom level/attribute bindings. The skill DSL and configuration are covered in Skill Files and Configuration; this page documents the entry points for programmatic skill casting.
Maven coordinates
Repository: https://maven.astralrealms.fr/repository/maven-public/.
Entry point
SkillAPI.service() returns the SkillService singleton, which gates access to all casting and lookup methods. If called before the AstralSkill plugin has enabled, it throws IllegalStateException. Callers should guard with a soft dependency (check if AstralSkill is loaded via Bukkit.getPluginManager().getPlugin("AstralSkill")) or defer initialization to a later event.
Casting methods
The three primary cast methods differ in how the target is specified:
castAtPos(…) — direct position cast
Casts a skill at an explicit location and direction. The direction vector is typically normalized (e.g. from a player's eye direction, or a computed path). If container is null and the caster is a Player, a player-aware placeholder container is auto-created via AstralPaperAPI.createPlaceholderContainer(player); otherwise a blank PlaceholderContainer() is used. If the skill id is unknown, a warning is logged and the cast is abandoned.
Before the cast initializes, the skill's PaperRequirementList (if present and the caster is a Player) is evaluated; if requirements fail, the cast is aborted.
Parameters:
caster: The entity triggering the skill (may be a Player, Mob, ArmorStand, etc.).casterUUID: The UUID of the caster; carried through to caster effects and targeting.skillId: The id of the skill file (must match a file underskills/).location: The center/spawn point of the skill (interpreted in the location's world).direction: A velocity/heading vector (typically normalized). For impact skills, points along the terrain normal; for projectiles, defines the launch direction.container: Custom placeholder bindings (e.g.level, custom stats). Ifnulland caster is a Player, a container is auto-built.
castThroughPos(…) — projectile auto-aim
Solves the launch pitch so a projectile skill's simulated arc passes through passLocation. Unlike castAtPos, the caller does not supply a direction; instead the projectile's full trajectory is simulated using its configured velocity, drag, gravity, and range, and the launch pitch is computed. The horizontal heading always points from startLocation toward passLocation.
This only works for projectile skills (see Cast Types). If the skill is not a projectile, or the target cannot be reached (out of range, too much drag, etc.), the cast is aborted with a warning.
When both a direct arc and a lobbed arc can reach the point, the flatter path is preferred.
Skills that enforce a fixed pitch cannot be aimed vertically, so arbitrary heights may not be reachable; in such cases the cast is aborted.
Variant without forceCast: If the target is unreachable, the cast is abandoned.
Variant with forceCast = true: If the target is unreachable, the projectile is still fired along the straight line from startLocation toward passLocation (it simply will not reach the point). This is useful for "best-effort" aiming (e.g. chase/homing skills that should always activate even if the geometry is challenging).
Parameters:
startLocation: Where the projectile spawns; defines the world the cast happens in. IfpassLocationis in a different world, it is re-interpreted in the start location's world and a warning is logged.passLocation: The location the projectile should pass through.container: Custom placeholder bindings. Null-handling is the same ascastAtPos.forceCast: Whentrue, fire along a direct heading if the target is unreachable; whenfalse, abort.
castAtTarget(…) — entity targeting
Resolves an entity on the main thread (via world.getEntity(entityUUID)) and casts at its location. If the entity no longer exists, a warning is logged and the cast is abandoned. Otherwise, delegates to castAtPos(caster, casterUUID, skillId, target.getLocation().clone(), new Vector3d(0.0), container).
Lookup methods
Method | Returns | Use |
|---|---|---|
|
| Resolve a skill by id. Returns a defensive copy. |
|
| Every loaded skill (unmodifiable snapshot). |
findById() returns a defensive copy of the skill, so modifications do not affect the shared state.
Lifecycle control
Active skills are tracked per caster and automatically updated each tick. Consumers rarely call these directly; most lifecycle management happens automatically:
Method | Returns | Use |
|---|---|---|
|
| Register a skill as active (queues it for update). Called internally by cast methods. |
|
| Unregister one active skill instance. |
|
| Unregister a set of skills. |
|
| Deactivate all active skills for a single entity. |
|
| Deactivate all active skills across all casters. Returns a future that completes when all shards have cleared. |
The deactivateAllSkills() variant (no argument) is called during plugin shutdown and reload.
Performance monitoring
metricsSummary() returns a human-readable snapshot of every shard's update-loop performance, including tick counts, overruns, peak timing, and active skill counts. Safe to call from any thread. The output looks like:
Requirement gating
Before a skill cast initializes, if the caster is a Player and the skill has a PaperRequirementList defined in its configuration, the requirements are evaluated. If any requirement fails (e.g. not enough money, cooldown active, level too low), the cast is aborted silently and no effects fire.
See Skill Files for how to define requirements on a skill.
Threading model
AstralSkill uses a fixed pool of shards (update threads) to isolate skill state and avoid lock contention. Each caster is routed to the same shard via hash, so all of its active skills are updated on a single thread.
Utility scheduling
getExecutor() exposes shard 0's scheduled executor for callers that need to schedule utility work (e.g. delayed casts, cooldown timers). Callers must not touch shard state or access active skills from this thread. Only use it for work that does not depend on the skill update loop or shared caster state.
Cast dispatch
Casts are dispatched to the caster's assigned shard. The cast initializes and the skill is queued for updates. Each update tick (1ms budget per shard, across all active skills), the skill's update() method is called; when it returns true, the skill is marked finished and removed from the active set.
Automatic cleanup
The EntityListener deactivates all of a caster's active skills when the entity dies (EntityDeathEvent). The PlayerListener manages chunk snapshots and player-specific caches when players join, change worlds, or quit. As a consumer, you do not need to call cleanup methods when an entity disappears; it happens automatically.
Integration pattern
AstralClasses and AstralMobs call the cast methods directly with a skill id and optional custom PlaceholderContainer. They do not re-implement the skill DSL — they rely on this API to execute skills.
Example from a class ability:
For skill DSL details (cast types, targeting, effects, displays, hitbox shapes), see:
Skill Files — the overall structure and config schema.
Cast Types —
projectile,impact,laser,auto-cast,n-cast.Targeting — collision detection and entity selection.
Effects — caster/target effect pipeline.
Displays — visual rendering (particles, sounds).