Skip to content

soulpower template.java

Valor edited this page Nov 9, 2025 · 2 revisions

Custom Soul Powers

Soul Powers are small, runtime‑compiled Java scripts that can be granted to players via Soul Harvester upgrades. They work similarly to the Custom Entity Ability system (which targets mobs), but Soul Powers execute in a player context and are intended to provide player-facing effects (buffs, temporary actions, triggers on player events like onKill/onAttack/onDefence).

This page explains how to write Soul Powers, where to place them, how they're compiled/loaded, how they are triggered by the Soul Harvester system, and how to test them safely.

Table of Contents

Overview

  • Soul Powers are Java classes compiled at runtime from the plugin data folder: plugins/RareSpawns/soulpowers/.
  • Each power must implement the valorless.rarespawns.soulpower.SoulPower interface and be annotated with valorless.rarespawns.soulpower.SoulPowerInfo.
  • Powers are referenced by string id (filename without .java) from Soul Harvester upgrade definitions (the soul-power field).
  • When a Soul Harvester upgrade of type POWER is applied to an item, the upgrade writes a PDC boolean tag on the item for the power id; the SoulPowerManager/SoulHarvesterListener will then include that power in per-player power lookups and may execute it when the configured trigger occurs.

Where soul powers live (paths & names)

  • Put your source files here on the server:
    • plugins/RareSpawns/soulpowers/<YourPowerId>.java
  • The ability id == filename without .java. Example:
    • File: plugins/RareSpawns/soulpowers/darkcallPower.java
    • Power id: darkcallPower
  • Important: Do NOT place a package declaration in the source file. The runtime compiler prepends useful imports automatically and expects the class to be in the default package.
  • Class name must exactly match the filename (case-sensitive).

Creating a Soul Power (requirements)

  • Implement the interface:
    • valorless.rarespawns.soulpower.SoulPower
      • Method: void execute(ItemData data, Player player)
        • data is the ItemData for the item that granted the power (useful for reading config values).
        • player is the Player context for the execution.
  • Annotate the class with @SoulPowerInfo(...) and provide required metadata (see below).
  • Provide a public no-argument constructor (default constructor is fine).
  • Keep logic non-blocking. If you need long-running tasks, schedule them with Bukkit's scheduler.

Annotation: @SoulPowerInfo fields

The annotation is defined in valorless.rarespawns.soulpower.SoulPowerInfo and its fields are used at runtime:

  • type (String) — trigger type. Valid values: onAttack, onDefence, onKill (case-insensitive). These determine when the SoulHarvesterListener or other code will attempt to execute the power.
  • cooldown (String) — cooldown in seconds between attempts (the code parses this to a double and enforces cooldowns per player/power).
  • chance (String) — percent chance (0..100) that the power will activate when its trigger occurs.
  • failCooldown (String) — "true" or "false": if true, a failed activation roll still applies the cooldown.

Example annotation:

@SoulPowerInfo(
    type = "onAttack",
    cooldown = "5",
    chance = "30",
    failCooldown = "true"
)

Class contract: SoulPower.execute

Signature:

void execute(ItemData data, Player player)
  • ItemData contains the item's configuration and can be used to read any soul-harvester subkeys or other item properties.
  • player is the Bukkit Player instance who triggered the power.

Keep execution fast and safe. For example, do not perform blocking network I/O inside execute() — use Bukkit.getScheduler().runTaskAsynchronously(...) if you must.

Compilation & loading (how the plugin runs them)

  • The runtime compiler is implemented in valorless.rarespawns.compilers.Compiler (shared), and the soul-power specific loader is valorless.rarespawns.compilers.SoulPowerCompiler.
  • On startup or when you call the plugin's reload for soulpowers, the SoulPowerCompiler.reload() method:
    • Ensures plugins/RareSpawns/soulpowers/ exists and contains a template.java if missing.
    • Writes a temporary source file with additional imports (so your file can be in the default package and not import everything).
    • Compiles the .java file using the system JDK compiler (ToolProvider.getSystemJavaCompiler()) — server must run on a JDK.
    • Loads the .class from plugins/RareSpawns/soulpowers/compiled/ using a dynamic classloader and registers it in an in-memory registry.
  • Use the plugin's provided reload command or restart the server to rebuild the power registry.
  • If compilation fails you will see diagnostic output in the server console.

Using Soul Powers in Soul Harvester upgrades

  • In your item config (items/<id>.yml) inside soul-harvester.upgrades add an upgrade of type POWER and set soul-power: <yourPowerId>.
  • Example snippet:
upgrades:
  darkcall_upgrade:
    uniqueid: 5d8e1f4a
    type: POWER
    souls-required: 80
    soul-power: darkcallPower
  • When this upgrade applies, SoulHarvesterUpgrade will set a PDC boolean tag for the power id on the item, and SoulPowerManager.getSoulPowers(...) will return it for the owning player when enumerating powers.
  • Triggers and execution:
    • The SoulHarvesterListener responds to events (onAttack, onDefence, onKill, etc.). When a configured trigger occurs and the power is unlocked, the listener:
      • Checks world whitelist,
      • Checks that the power is unlocked on the player's item,
      • Checks per-player cooldown (managed by SoulPowerManager),
      • Rolls chance (from SoulPowerInfo),
      • Calls SoulPowerCompiler.usePower(id, itemData, player) which instantiates the power class and invokes execute(data, player).

Example power (copy/paste)

Below is a minimal working example (this file is already included in the plugin resources as soulpowers/template.java — use it as a starting point). Drop it into plugins/RareSpawns/soulpowers/knockupPower.java:

// Class name must be the same as the file name
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import valorless.rarespawns.datamodels.ItemData;
import valorless.rarespawns.soulpower.SoulPower;
import valorless.rarespawns.soulpower.SoulPowerInfo;

@SoulPowerInfo(
    type = "onKill",
    cooldown = "8",
    chance = "50",
    failCooldown = "true"
)
public class knockupPower implements SoulPower {
    @Override
    public void execute(ItemData data, Player player) {
        // Simple: launch the player slightly upward as a "reward" on their kill
        Vector vel = player.getVelocity();
        vel.setY(Math.max(0.8, vel.getY() + 0.8));
        player.setVelocity(vel);
    }
}

Notes:

  • Class name knockupPower must match file knockupPower.java.
  • No package declaration.
  • The ItemData parameter is useful to read custom fields from the item config if you want to make your power configurable.

Testing & debug steps

  1. Place knockupPower.java in plugins/RareSpawns/soulpowers/.
  2. Restart the server, or run the RareSpawns reload that compiles soul powers.
  3. Ensure SoulPowerCompiler logs show the power was compiled and loaded (look for "Loaded X powers").
  4. Create an item with a Soul Harvester upgrade that grants knockupPower (type: POWER) and give it to a test player.
  5. Unlock the upgrade by accumulating souls (or temporarily lower souls-required to test).
  6. Trigger the configured event (e.g., kill a mob if the power is onKill) and observe the effect.
  7. If the power does not run:
    • Check server console for compilation or runtime exceptions.
    • Confirm SoulPowerCompiler.isReady() returned true after reload.
    • Verify the power id (filename) matches the soul-power specified in your upgrade and that the item actually has the PDC tag (applied upgrade).

Security & best practices

  • Soul Powers execute arbitrary Java code on your server. DO NOT run untrusted code on production servers.
  • Always test powers on a staging environment first.
  • Avoid blocking operations inside execute() — use Bukkit async scheduler for I/O or heavy computation.
  • Use the ItemData parameter to keep behaviour configurable, reducing the need to edit/recompile code for minor tweaks.
  • Keep cooldowns and chances reasonable to avoid server spam or exploitative behaviour.

🐲 RareSpawns Wiki

✅ Getting Started

⚙️ Configuration

🍳 Resources

🔌⚡ Supported Plugins (And why 🤔💭)

👑 Premium Features

</> For Developers


🔎 Tips

  • Use the search box above to quickly jump to a page.

Clone this wiki locally