JavaScript Scripting
EmakiLevel registers a scripting module through the CoreLib scripting system. The module ID is level. Inside a script you obtain the module facade with emaki.module("level") to query level types and player levels and to register exp rules and level-up hooks.
This page covers only the EmakiLevel-specific script methods, registration fields, context and examples. For the generic scripting mechanism see CoreLib JavaScript Scripting.
Always guard with
available()before calling any business method. EmakiLevel is a CoreLib softdepend.
Obtaining the module
function main(ctx) {
const level = emaki.module("level");
if (!level.available()) {
return { skipped: true, message: "EmakiLevel unavailable" };
}
// ...
return true;
}Probe methods
| Method | Returns | Description |
|---|---|---|
available() | boolean | Whether the module is available. |
The EmakiLevel module facade only exposes
available().
Query methods
| Method | Returns | Description |
|---|---|---|
typeIds() | list | Return all level type ids, sorted. |
type(typeId) | map | Return details of a single type; empty Map when not found. |
level(playerUuid, typeId) | int | The player's current level for a type; 0 when the UUID is invalid. |
exp(playerUuid, typeId) | double | Current exp; 0 when the UUID is invalid. |
totalExp(playerUuid, typeId) | double | Cumulative total exp; 0 when the UUID is invalid. |
requiredExp(playerUuid, typeId, targetLevel) | double | Exp required to reach a target level; 0 when the UUID is invalid. |
playerUuidmust be a valid UUID string, parsed internally withUUID.fromString; on failure the method returns 0.
The Map returned by type(typeId) has fields: id, displayName, description, primary, enabled, startLevel, maxLevel, autoUpgrade, manualUpgrade, attributes.
Exp rules
Exp rules run when a player gains exp. They can read the context and adjust the final exp or cancel the gain.
| Method | Returns | Description |
|---|---|---|
registerExpRule(definition) | boolean | Register an exp rule. |
registerExpRule(id, definition) | boolean | Overload: merge id into the definition, then register. |
unregisterExpRule(id) | void | Unregister a rule by id. |
registeredExpRules() | list | Return the list of registered exp rule ids. |
Rule definition fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | yes | none | Unique rule id (normalized); registration fails when blank. |
priority | int | no | 0 | Priority; lower runs first, ties broken by id. |
typeIds | string / list | no | empty (all types) | Level types the rule applies to; types also works. |
reasons | string / list | no | empty (all reasons) | Exp reasons the rule applies to. |
function | string | no | modifyExp | Rule callback function name; execute also works. |
timeoutMillis | long | no | engine default | Per-call script timeout. |
Rule callback ctx fields
| Field | Type | Description |
|---|---|---|
ruleId | string | Current rule id. |
playerUuid | string | Player UUID. |
typeId | string | Level type id. |
reason | string | Exp reason. |
originalAmount | double | Original exp amount. |
currentAmount | double | Current accumulated exp amount. |
multiplier | double | Current multiplier. |
multipliedAmount | double | Exp amount after the multiplier. |
dailyLimit | double | Daily exp cap. |
gainedToday | double | Exp already gained today. |
Rule callback return fields
| Return field | Type | Description |
|---|---|---|
cancel | boolean | When true, sets this exp gain to 0. |
actualAmount or amount | number | Set the resulting exp explicitly (clamped non-negative, takes priority over multiplier). |
multiplier | number | Otherwise use current × multiplier (clamped non-negative). |
message | string | Message written to the trace. |
A non-object return or an execution failure keeps the original value and records a trace.
Level-up hooks
Level-up hooks fire after a player levels up, for side effects such as rewards and broadcasts.
| Method | Returns | Description |
|---|---|---|
onLevelUp(definition) | boolean | Register a level-up hook. |
onLevelUp(id, definition) | boolean | Overload: merge id into the definition, then register. |
unregisterLevelUpHook(id) | void | Unregister a level-up hook by id. |
registeredLevelUpHooks() | list | Return the list of registered level-up hook ids. |
Hook definition fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | yes | none | Unique hook id; registration fails when blank. |
typeIds | string / list | no | empty (all types) | Level types that trigger the hook; type also works. |
function | string | no | onLevelUp | Callback function name; execute also works. |
timeoutMillis | long | no | engine default | Per-call script timeout. |
Level-up hooks have no priority field; multiple hooks fire in id lexical order.
Hook callback event fields
| Field | Type | Description |
|---|---|---|
hookId | string | Hook id. |
playerUuid | string | Player UUID. |
playerName | string | Player name. |
typeId | string | Level type id. |
oldLevel | int | Level before the level-up. |
newLevel | int | Level after the level-up. |
oldExp | double | Exp before the level-up. |
newExp | double | Exp after the level-up. |
cause | string | Level-up cause. |
requiredExp | double | Required exp. |
Query example
EmakiLevel ships the trigger-style example script scripts/examples/level_status.js:
function main(ctx) {
const level = emaki.module("level");
const typeIds = level.typeIds();
const typeId = typeIds.size() > 0 ? typeIds.get(0) : "main";
let currentLevel = 0;
let currentExp = 0;
if (emaki.player.exists() && typeId) {
currentLevel = level.level(emaki.player.uuid(), typeId);
currentExp = level.exp(emaki.player.uuid(), typeId);
emaki.player.sendMessage("[EmakiJS] Level state: type=" + typeId + " level=" + currentLevel + " exp=" + currentExp);
}
return {
success: true,
output: {
level_available: level.available(),
type_count: typeIds.size(),
sample_type: String(typeId || ""),
current_level: currentLevel,
current_exp: currentExp
}
};
}Registration example
EmakiLevel ships the extension-style example script scripts/examples/level_exp_rule.js:
function register() {
const level = emaki.module("level");
level.registerExpRule({
id: "js_weekend_bonus",
priority: 10,
function: "modifyExp"
});
level.onLevelUp({
id: "js_levelup_message",
function: "onLevelUp"
});
}
function modifyExp(ctx) {
const day = new Date().getDay();
if (day === 0 || day === 6) {
return {
multiplier: 2.0,
message: "weekend bonus"
};
}
return {};
}
function onLevelUp(event) {
emaki.logger.info("Level up hook: " + event.playerName + " " + event.typeId + " " + event.oldLevel + " -> " + event.newLevel);
return true;
}Enabling extension scripts
Put the script into CoreLib's global extension directory and reload:
plugins/EmakiCoreLib/scripts/extensions/global/level_exp_rule.js/corelib script reloadThe example file is released to
plugins/EmakiCoreLib/scripts/examples/by default and is not auto-enabled.
Script debugging
When you enable the debug submodule named script, EmakiLevel writes the per-rule execution trace to the server console every time its JS rules run, which helps server administrators debug script rules.
Enable command:
/elv debug module scriptTrace fields: rule id, before (value before execution), after (value after execution) and message. This output goes to the server console for server administrators to debug; it is not shown to players.
Notes
- Every registration method requires the CoreLib scripting system to be enabled; otherwise registration returns
falseor is silently skipped. - When CoreLib is missing the module degrades gracefully: rules and hooks have no effect but raise no error.
- Exp rules run in ascending priority order (lower first).