Configuration
EmakiLevel configuration is split into the main config, requirement curves, level types, experience sources, GUI templates, and language files.
Server owners usually edit:
config.yml: global switches.requirements.yml: required exp curves.types/*.yml: level types, upgrade behavior, rewards, costs, and attributes.sources/*.yml: which events grant exp to which level types.
Run /elv reload after editing most EmakiLevel files to reload configuration and synchronize online players.
config.yml
Default main config:
version: "1.4.0"
language: "zh_CN"
release_default_data: true
primary_type: "main"
level:
default_start_level: 1
default_max_level: 100
max_auto_upgrade_steps: 10
keep_total_exp_at_max_level: true
multipliers:
enabled: true
global: 1.0
types:
main: 1.0
combat: 1.0
cooking: 1.0
forging: 1.0
reasons:
action: 1.0
mythic_drop: 1.0
event_bonus: 1.0
daily_caps:
enabled: true
default_limit: -1
types:
main: -1
combat: -1
cooking: -1
forging: -1
storage:
type: "yaml"
save_on_quit: true
save_on_shutdown: true
pdc:
enabled: true
namespace: "emakilevel"
sync_on_join: true
sync_on_exp_change: true
sync_on_level_change: true
sync_on_reload: true
attribute:
enabled: true
provider_id: "emakilevel"
mythicmobs:
enabled: true
kill_sources: true
drops:
enabled: true
names:
- "emakilevel_exp"
- "elv_exp"
anti_abuse:
placed_block_tracking: true
placed_block_exp: false
placed_block_record_ttl_ticks: 864000
last_damager_tracking:
enabled: true
expire_ticks: 200
gui:
enabled: true
default_template: "level_gui"| Field | Type | Default | Description |
|---|---|---|---|
version | string | 1.4.0 | Default resource version marker. |
language | string | zh_CN | Language file under lang/<language>.yml. |
release_default_data | boolean | true | Whether missing bundled data files should be released. |
primary_type | string | main | Default level type for /elv levelup without type and some actions without type. |
level.default_start_level | int | 1 | Fallback start level when a type omits start_level. |
level.default_max_level | int | 100 | Fallback max level when a type omits max_level. |
level.max_auto_upgrade_steps | int | 10 | Maximum auto-level-up steps from one exp operation. |
level.keep_total_exp_at_max_level | boolean | true | Keep increasing total_exp after a player reaches max level. Current-level exp stops increasing. |
multipliers.enabled | boolean | true | Enable the experience multiplier stage. |
multipliers.global | double | 1.0 | Global experience multiplier. |
multipliers.types.<type> | double | 1.0 | Per level type multiplier. Keys are normalized to lower case. |
multipliers.reasons.<reason> | double | 1.0 | Per experience reason multiplier. Keys are normalized to lower case. |
daily_caps.enabled | boolean | true | Enable the daily experience cap stage. |
daily_caps.default_limit | double | -1 | Daily cap used when a type has no explicit entry. -1 means unlimited. |
daily_caps.types.<type> | double | -1 | Per level type daily cap. -1 means unlimited. |
storage.type | string | yaml | Key kept in the default config. The current implementation always uses YAML files and does not read this key. |
storage.save_on_quit | boolean | true | Key kept in the default config. Not read by the current implementation: quitting or being kicked always saves and unloads the cache asynchronously. |
storage.save_on_shutdown | boolean | true | Key kept in the default config. Not read by the current implementation: disabling always flushes and seals the data store. |
pdc.enabled | boolean | true | Write level data to online player PDC. |
pdc.namespace | string | emakilevel | PDC namespace. |
pdc.sync_on_join / sync_on_exp_change / sync_on_level_change / sync_on_reload | boolean | true | Keys kept in the default config. Not read by the current implementation: while pdc.enabled is true, join, exp change, level change, and reload all synchronize. |
attribute.enabled | boolean | true | Try to connect to EmakiAttribute contributions. |
attribute.provider_id | string | emakilevel | Contribution provider ID registered into EmakiAttribute. |
mythicmobs.enabled | boolean | true | Global MythicMobs switch. |
mythicmobs.kill_sources | boolean | true | Enable mythic_mob_kill sources. |
mythicmobs.drops.enabled | boolean | true | Register MythicMobs intangible exp drops. |
mythicmobs.drops.names | list | emakilevel_exp, elv_exp | Recognized drop names. Empty list falls back to defaults. |
anti_abuse.placed_block_tracking | boolean | true | Track player-placed blocks. |
anti_abuse.placed_block_exp | boolean | false | Whether player-placed blocks can grant break exp. |
anti_abuse.placed_block_record_ttl_ticks | int | 864000 | Lifetime of placed-block records in ticks. Expired records are pruned on the next read/write. |
anti_abuse.last_damager_tracking.enabled | boolean | true | Whether indirect kills (attributed through the recent damager) are accepted. When false, only direct Bukkit-killer kills are processed. |
anti_abuse.last_damager_tracking.expire_ticks | int | 200 | Key kept in the default config. Not read by the current implementation: the recent damager window is controlled by CoreLib config.yml > gameplay_events.last_damager_expire_ticks (also 200 by default). |
gui.enabled | boolean | true | Enables the level GUI template entry. |
gui.default_template | string | level_gui | Default GUI template ID. |
Multipliers and daily caps
multipliers and daily_caps run before experience is written to the player, in this order: multiplier → JavaScript exp rules → daily cap.
Multiplier calculation:
multiplier = multipliers.global × multipliers.types.<type> × multipliers.reasons.<reason>- Keys not listed under
typesorreasonsare skipped instead of being treated as0. - With
multipliers.enabled: falsethe multiplier is fixed at1.0. - The result is clamped to be non-negative.
<reason>is the reason passed by the exp source, for example the source rule trigger ID, an actionreasonargument, or a MythicMobs dropreason.
Daily caps:
- With
daily_caps.enabled: falsethere is no cap. - A type uses
daily_caps.types.<type>when present, otherwisedaily_caps.default_limit. -1means unlimited.- When the remaining daily budget is smaller than the incoming amount, the gain is clamped to the remaining budget. When the budget is exhausted the operation fails with reason
daily_cap_reached. - Counters are bucketed by date in the system default time zone, kept in memory only, and reset when the server restarts.
requirements.yml
requirements.yml controls required exp:
global:
formula: "floor(100 + 25 * %target_level% + 8 * pow(%target_level%, 2))"
values: {}
groups:
main:
formula: "floor(150 + 40 * %target_level% + 14 * pow(%target_level%, 2))"
values:
2: 150
3: 350
4: 750
5: 1200
combat:
formula: "floor(60 + 18 * %target_level% + 5 * pow(%target_level%, 2))"
values:
2: 80
3: 160
4: 300
# mining / logging / farming / fishing / gathering / taming use the same default curve as combat
crafting:
formula: "floor(80 + 22 * %target_level% + 6 * pow(%target_level%, 2))"
values: {}
# brewing / cooking / forging / smelting use the same default curve as craftingThe bundled requirements.yml defines one group per built-in level type: main, combat, mining, logging, farming, fishing, gathering, taming, crafting, brewing, cooking, forging, smelting. Each types/<type>.yml > requirement.group points at the group with the same name by default.
Resolution order
Required exp for a target level resolves in this order:
types/<type>.yml > requirement.values.<target_level>types/<type>.yml > requirement.formularequirements.yml > groups.<group>.values.<target_level>requirements.yml > groups.<group>.formularequirements.yml > global.values.<target_level>requirements.yml > global.formula
Exact values greater than zero take priority over formulas.
Formula variables
| Variable | Description |
|---|---|
%current_level% | Player's current level, or type start level when no player entry exists. |
%target_level% | Target level. |
%max_level% | Type max level. |
%exp% | Current-level exp. |
%total_exp% | Total exp. |
Use /elv debug requirement <type> <level> to inspect the final value and source.
types/*.yml
Each types/*.yml file defines one level type. File name is only a fallback; the internal id field is authoritative.
id: "combat"
enabled: true
display_name: "<red>Combat Level</red>"
description:
- "<gray>Gain exp from vanilla or MythicMobs kills.</gray>"
primary: false
start_level: 1
max_level: 80
requirement:
group: "combat"
formula: ""
values: {}
upgrade:
enabled: true
auto_upgrade: true
manual_upgrade: true
cost:
enabled: false
economy:
enabled: false
currencies: []
materials: []
rewards:
items: []
actions:
gain: []
success: []
failure: []
pdc:
enabled: true
attributes:
enabled: true
values:
physical_attack: "%level% * 0.25"| Field | Description |
|---|---|
id | Unique level type ID referenced by commands, placeholders, sources, and actions. |
enabled | Disabled types cannot gain exp or level up. |
display_name | MiniMessage display name. |
description | Description lines for configuration maintenance and GUI display. |
primary | Marks a type as primary metadata. The active default is still config.yml > primary_type. |
start_level | Initial and reset level. |
max_level | Maximum level. Direct level edits are clamped to this range. |
requirement.group | Requirement group in requirements.yml. |
requirement.formula | Type-specific formula overriding group/global formulas. |
requirement.values | Type-specific exact target-level values. Highest priority. |
upgrade.enabled | Whether this type can level up at all. |
upgrade.auto_upgrade | Whether exp gain triggers automatic level-up. |
upgrade.manual_upgrade | Whether players can use /elv levelup. |
upgrade.cost | Money/material level-up costs. |
upgrade.rewards.items | Item rewards on successful level-up. |
upgrade.actions.gain | CoreLib actions after exp gain. |
upgrade.actions.success | CoreLib actions after successful level-up. |
upgrade.actions.failure | CoreLib actions after failed level-up. |
pdc.enabled | Whether this type syncs PDC. Requires global pdc.enabled: true. |
attributes.enabled | Whether this type contributes EmakiAttribute attributes. |
attributes.values | Map of attribute ID to formula. |
Level-up costs
Costs only apply when upgrade.cost.enabled: true.
Economy cost
upgrade:
cost:
enabled: true
economy:
enabled: true
currencies:
- provider: "auto"
currency_id: ""
base_cost: 100
cost_formula: "%base_cost% * %target_level%"
display_name: "<gold>Coins</gold>"| Field | Description |
|---|---|
provider | CoreLib economy provider, usually auto, vault, or excellenteconomy. |
currency_id | Currency ID. Usually empty for Vault. |
base_cost | Base amount exposed as %base_cost%. |
cost_formula | Final cost formula. |
display_name | Display label for readability and future UI. |
Economy variables: %target_level%, %type%, %base_cost%.
Material cost
upgrade:
cost:
enabled: true
materials:
- item_sources:
- "minecraft-diamond"
base_amount: 1
amount_formula: "%base_amount% + floor(%target_level% / 10)"| Field | Description |
|---|---|
item_sources | CoreLib ItemSource values to consume, processed in order. |
base_amount | Base amount exposed as %base_amount%. New configs should use this field. |
amount_formula | Final amount formula, rounded to an integer. |
Material variables: %target_level%, %type%, %base_amount%.
Rewards
upgrade:
rewards:
items:
- levels: "*"
item_sources:
- "minecraft-experience_bottle"
amount: 1
- levels: "10,20,30"
item_sources:
- "minecraft-diamond"
amount: 2
- levels: "50-60"
item_sources:
- "minecraft-nether_star"
amount: 1| Field | Description |
|---|---|
levels | Level pattern: *, single level, comma list, or min-max range. |
item_sources | Reward item sources. The first creatable source is used. |
amount | Reward amount, minimum 1. |
Rewards are created through CoreLib ItemSource and delivered with give-or-drop behavior.
Upgrade action variables
upgrade.actions.gain, success, and failure are CoreLib action line lists. They receive these variables:
| Variable | Description |
|---|---|
%type% | Level type ID. |
%type_display_name% | Type display name. |
%level% | Current level. |
%old_level% | Level before operation. |
%new_level% | Level after operation. |
%exp% | Current-level exp, formatted. |
%old_exp% | Exp before operation, formatted. |
%new_exp% | Exp after operation, formatted. |
%total_exp% | Total exp, formatted. |
%required_exp% | Required exp for next level, formatted. |
%progress% | Progress from 0 to 1. |
%progress_percent% | Progress from 0 to 100, formatted. |
%amount% | Operation amount, formatted. |
%reason% | Operation reason. |
%failure_reason% | Failure reason, especially useful in failure actions. |
Example:
upgrade:
actions:
gain:
- '@chance=10 sendactionbar text="<gray>%type_display_name% exp +%amount%</gray>"'
success:
- 'sendmessage text="<green>%type_display_name% reached <yellow>%new_level%</yellow>!</green>"'
failure:
- 'sendmessage text="<red>Level-up failed: %failure_reason%</red>"'Attribute contributions
When EmakiAttribute is installed and enabled, EmakiLevel registers level-based contributions. The default provider ID is config.yml > attribute.provider_id, usually emakilevel.
attributes:
enabled: true
values:
physical_attack: "%level% * 0.25"
physical_crit_rate: "%level% * 0.02"Attribute formula variables: %level%, %exp%, %total_exp%.
If EmakiAttribute is not installed, this bridge is skipped automatically.
PDC sync
When global pdc.enabled: true and type-level pdc.enabled: true, online players receive these logical PDC fields under the configured namespace, default emakilevel:
| Field | Type | Description |
|---|---|---|
player/<type>_level | int | Current level. |
player/<type>_exp | double | Current-level exp. |
player/<type>_total_exp | double | Total exp. |
player/<type>_required_exp | double | Required exp for next level. |
player/<type>_progress | double | Progress from 0 to 1. |
PDC sync happens on join, exp changes, level changes, reload, and explicit debug sync.
Player data files
Player data is stored in data/<uuid>.yml:
schema_version: 1
uuid: "00000000-0000-0000-0000-000000000000"
name: "PlayerName"
levels:
main:
level: 1
exp: 0.0
total_exp: 0.0
updated_at: 1730000000000Prefer commands such as /elv setexp, /elv setlevel, and /elv reset over editing data files while the server is running.