-
Notifications
You must be signed in to change notification settings - Fork 0
soulpower template.java
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
- Soul Powers are Java classes compiled at runtime from the plugin data folder: plugins/RareSpawns/soulpowers/.
- Each power must implement the
valorless.rarespawns.soulpower.SoulPowerinterface and be annotated withvalorless.rarespawns.soulpower.SoulPowerInfo. - Powers are referenced by string id (filename without .java) from Soul Harvester upgrade definitions (the
soul-powerfield). - When a Soul Harvester upgrade of type
POWERis 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.
- 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
- File:
- Important: Do NOT place a
packagedeclaration 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).
- Implement the interface:
-
valorless.rarespawns.soulpower.SoulPower- Method:
void execute(ItemData data, Player player)-
datais theItemDatafor the item that granted the power (useful for reading config values). -
playeris the Player context for the execution.
-
- Method:
-
- 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.
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"
)Signature:
void execute(ItemData data, Player player)-
ItemDatacontains the item's configuration and can be used to read anysoul-harvestersubkeys or other item properties. -
playeris 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.
- The runtime compiler is implemented in
valorless.rarespawns.compilers.Compiler(shared), and the soul-power specific loader isvalorless.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 atemplate.javaif missing. - Writes a temporary source file with additional imports (so your file can be in the default package and not import everything).
- Compiles the
.javafile using the system JDK compiler (ToolProvider.getSystemJavaCompiler()) — server must run on a JDK. - Loads the
.classfromplugins/RareSpawns/soulpowers/compiled/using a dynamic classloader and registers it in an in-memory registry.
- Ensures
- 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.
- In your item config (
items/<id>.yml) insidesoul-harvester.upgradesadd an upgrade of typePOWERand setsoul-power: <yourPowerId>. - Example snippet:
upgrades:
darkcall_upgrade:
uniqueid: 5d8e1f4a
type: POWER
souls-required: 80
soul-power: darkcallPower- When this upgrade applies,
SoulHarvesterUpgradewill set a PDC boolean tag for the power id on the item, andSoulPowerManager.getSoulPowers(...)will return it for the owning player when enumerating powers. - Triggers and execution:
- The
SoulHarvesterListenerresponds 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(fromSoulPowerInfo), - Calls
SoulPowerCompiler.usePower(id, itemData, player)which instantiates the power class and invokesexecute(data, player).
- The
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
knockupPowermust match fileknockupPower.java. - No package declaration.
- The
ItemDataparameter is useful to read custom fields from the item config if you want to make your power configurable.
- Place
knockupPower.javainplugins/RareSpawns/soulpowers/. - Restart the server, or run the RareSpawns reload that compiles soul powers.
- Ensure
SoulPowerCompilerlogs show the power was compiled and loaded (look for "Loaded X powers"). - Create an item with a Soul Harvester upgrade that grants
knockupPower(type: POWER) and give it to a test player. - Unlock the upgrade by accumulating souls (or temporarily lower
souls-requiredto test). - Trigger the configured event (e.g., kill a mob if the power is
onKill) and observe the effect. - 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-powerspecified in your upgrade and that the item actually has the PDC tag (applied upgrade).
- 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
ItemDataparameter 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.