Repository navigation
API and Events
RunelessRPG has a small API for other mods and scripts: one class with static methods (RunelessApi) and two events on
the NeoForge event bus. Everything is in the package com.drehverschluss.runelessrpg.api.
Reading works on both sides (on the client: the values of the local player last sent by the server). Changing mana only
works on the logical server; every change is clamped to 0 … max mana, sent to the client and reported as a
ManaChangeEvent with reason API.
| Method | Side | Returns / effect |
|---|---|---|
getMana(Player) |
both | Current mana (may be negative after casting in a debt mode) |
getMaxMana(Player) |
both | Value of runelessrpg:max_mana (never negative) |
getManaRegen(Player) |
both | Value of runelessrpg:mana_regen in mana per second (may be negative) |
setMana(ServerPlayer, double) |
server | Sets the mana |
addMana(ServerPlayer, double) |
server | Adds mana (negative amounts remove it) |
trySpend(ServerPlayer, double) |
server | Removes the amount if the player has at least that much; true if spent (always true for amounts ≤ 0), false and no change otherwise |
getCategory(Player, Holder<Spell>) |
both |
ManaCategory of the spell (NONE = Spell Engine costs apply) |
getBaseCost(Player, Holder<Spell>) |
both |
OptionalDouble: base cost (tier table × multiplier, or the datapack value); empty for NONE and FREE
|
getCost(Player, Holder<Spell>) |
both |
OptionalDouble: final cost for this player after ManaCostEvent (total for a full channel); creative players get the regular value |
getOverchargeBonus(Player, Holder<Spell>) |
both | Damage / healing multiplier from Overcharge for this spell right now (1.0 = none) |
isChanneled(Holder<Spell>) |
both |
true for channeled spells |
getCostPerChannelTick(Player, Holder<Spell>) |
both |
OptionalDouble: cost of one channel tick; empty if not channeled or free |
ManaCategory: NONE, FREE, SPELL, CLASS_SKILL, WEAPON_SKILL, ITEM_ABILITY.
Fired every time RunelessRPG calculates the mana cost of a spell for a player, after base cost, Mana Cost (with its floor) and Overcharge. Listeners can change the final cost.
| Method | Meaning |
|---|---|
getPlayer() |
The casting player (client or server instance) |
getSpell() |
The spell (Holder<Spell>) |
getCategory() |
The resolved ManaCategory
|
getBaseCost() |
Base cost before player attributes |
getCost() / setCost(double)
|
Final cost; negative values become 0 |
- Fired on both logical sides. The client calculates costs itself for the cast check, the "missing mana" message and the tooltip (every frame while a tooltip is open). A listener must return the same result on client and server and should be cheap.
- Only fired for spells that cost mana (not for
NONEandFREE). - For channeled spells the cost is the total for the full channel.
Fired on the logical server after a player's mana actually changed. Informational, not cancelable.
| Method | Meaning |
|---|---|
getPlayer() |
The player |
getOldMana() |
Mana before the change |
getNewMana() |
Mana after the change (may be negative in a debt mode or with Borrowed Power) |
getReason() |
Why it changed |
| Reason | Cause |
|---|---|
REGEN |
Regeneration (also negative). Reported in steps of at least 0.05 mana, or when the pool becomes full or empty; getOldMana() is then the value of the previous report |
COMMAND |
/runelessrpg mana |
API |
Another mod through RunelessApi
|
RESPAWN |
Refill after respawning |
CLAMP |
Lowered to a smaller maximum (gear taken off) |
SPELL |
Paid for a spell, also every tick of a channeled spell |
LEECH |
Mana Leech |
SPELL_LEECH |
Spell Mana Leech |
POTION |
Mana Restoration (potion, splash, lingering cloud, tipped arrow) |
Declare RunelessRPG as an optional dependency and compile against its jar (compileOnly).
import com.drehverschluss.runelessrpg.api.ManaChangeEvent;
import com.drehverschluss.runelessrpg.api.ManaCostEvent;
import com.drehverschluss.runelessrpg.api.RunelessApi;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.neoforge.common.NeoForge;
public final class MyManaCompat {
private static final ResourceLocation FIREBALL = ResourceLocation.parse("wizards:fireball");
public static void init() {
// Fireball costs half. Runs on client and server: only use data both sides know.
NeoForge.EVENT_BUS.addListener((ManaCostEvent event) -> {
if (event.getSpell().is(FIREBALL)) {
event.setCost(event.getCost() * 0.5);
}
});
// Server only
NeoForge.EVENT_BUS.addListener((ManaChangeEvent event) -> {
if (event.getReason() == ManaChangeEvent.Reason.SPELL && event.getNewMana() < 0) {
// the player is in debt now
}
});
}
// Somewhere on the server
static void reward(net.minecraft.server.level.ServerPlayer player) {
RunelessApi.addMana(player, 5.0);
}
}KubeJS for 1.21.1 (2101) listens to NeoForge events with NativeEvents.onEvent(Class, handler). ManaCostEvent
must run on both sides, so it belongs into startup_scripts; ManaChangeEvent only fires on the server.
kubejs/startup_scripts/runelessrpg.js
const ManaCostEvent = Java.loadClass('com.drehverschluss.runelessrpg.api.ManaCostEvent')
NativeEvents.onEvent(ManaCostEvent, event => {
// Weapon skills cost nothing while the player is in the Nether
if (event.getCategory().name() == 'WEAPON_SKILL'
&& String(event.getPlayer().getLevel().getDimension()) == 'minecraft:the_nether') {
event.setCost(0)
}
})kubejs/server_scripts/runelessrpg.js
const ManaChangeEvent = Java.loadClass('com.drehverschluss.runelessrpg.api.ManaChangeEvent')
const RunelessApi = Java.loadClass('com.drehverschluss.runelessrpg.api.RunelessApi')
NativeEvents.onEvent(ManaChangeEvent, event => {
if (event.getReason().name() == 'POTION') {
event.getPlayer().tell(`Mana: ${event.getNewMana().toFixed(1)} / ${RunelessApi.getMaxMana(event.getPlayer())}`)
}
})Both examples were tested with KubeJS 2101.7.2 (Rhino 2101.2.8):
- Use KubeJS's own helpers on Minecraft objects, e.g.
getLevel().getDimension(). In KubeJSlevelis a property, so the vanilla callplayer.level()fails with "It is not a function". - An error inside a
ManaCostEventhandler is thrown into the cost calculation, so the spell cast or the/runelessrpg costcommand fails with it. Test new handlers with/runelessrpg cost <spell>. - The
ManaChangeEventhandler inserver_scriptssurvives/reloadand fires once afterwards (not twice). Changes tostartup_scriptsneed a game restart.
RunelessRPG for NeoForge 1.21.1 · CurseForge · Source · Report a bug
Start
For players
For pack makers
Reference