Skip to content

Experience Sources ​

Experience source files are written under sources/*.yml: which triggers they provide, which conditions each rule can match on, which formula variables are available, and how anti-abuse is handled

Experience source files are stored under plugins/EmakiLevel/sources/*.yml. Each file can contain multiple source rules. You bind a rule to a Bukkit or MythicMobs event through trigger, then use match conditions to pick the exp formula

Default source files:

FileDefault sourceDescription
combat.ymlvanilla_entity_killVanilla entity kill exp
mythicmobs.ymlmythic_mob_killMythicMob kill exp
block_actions.ymlmining, logging, gathering, farmingBlock break, gathering, and mature crop harvest
fishing.ymlplayer_fishFishing event exp
crafting.ymlcraft_itemCraft result exp
brewing.ymlbrew_completeBrewing completion exp
smelting.ymlfurnace_extractFurnace extraction exp
taming.ymlentity_tameTaming exp

File structure ​

yaml
id: "combat_sources"
enabled: true
sources:
  vanilla_entity_kill:
    enabled: true
    type: "combat"
    trigger: "entity_kill"
    include_players: false
    anti_abuse:
      exp_cooldown_ticks: 5
      ignore_near_spawner: true
      spawner_scan_radius: 8
    rules:
      - entity_types: ["ZOMBIE", "SKELETON"]
        exp_formula: "10"
      - entity_types: ["WITHER", "ENDER_DRAGON"]
        exp_formula: "500"

Top-level fields:

FieldTypeRequiredDefaultRangeDescription
idstringnofile name without .yml—Source file identifier, mainly for readability
enabledbooleannotruetrue / falseFile switch. When false, the whole file is skipped
sourcesmappingno{}—Source rule map keyed by source ID

Single source fields:

FieldTypeRequiredDefaultRangeDescription
enabledbooleannotruetrue / falseRule switch
typestringnomaina loaded level type idTarget level type ID
triggerstringno""see "Triggers"Trigger ID. A blank value never matches an event
include_playersbooleannofalsetrue / falseUsed by entity_kill; whether killing players can grant exp
count_result_amountbooleannofalsetrue / falseParsed by the current implementation but not used in exp calculation; result counts are consumed through the %result_amount% formula variable
anti_abuse.ignore_player_placed_blocksbooleannofalsetrue / falseUsed by block_break / crop_harvest; whether player-placed blocks are ignored
anti_abuse.exp_cooldown_ticksintno0negative values are treated as 0Per-player, per-source exp cooldown in ticks. The timer starts only after a successful grant
anti_abuse.ignore_near_spawnerbooleannofalsetrue / falseUsed by entity_kill / mythic_mob_kill; skips the source when a spawner is found near the kill location
anti_abuse.spawner_scan_radiusintno8negative values are treated as 0, effective scan capped at 16Scan radius used together with ignore_near_spawner
attribution.expire_ticksintno1200—Used by brew_complete only; the source is skipped when the brewing completion is older than this many ticks since the player's last interaction with the stand
rules[]list<mapping>no[]see "Rule matching"Match rule list. One source uses the first matching rule
actions.gainlist<string>no[]CoreLib action lineReserved config entry. The current implementation does not execute this list; the type-level upgrade.actions.gain is the action path that actually runs

Triggers ​

For the complete shared event ID reference, see CoreLib Gameplay Event IDs. The table below lists the fields commonly used by EmakiLevel experience sources

triggerEvent sourceMatch fieldsFormula variablesDefault target type
entity_killCoreLib shared event; killer or recent damagerentity_types%entity_type%combat
mythic_mob_killCoreLib shared event; MythicMobs mob detected in the same deathmob_ids%mythic_id%, %mythic_level%combat
block_breakCoreLib shared event; player breaks a blockblocks%block_type%mining / logging / gathering
crop_harvestDerived from block_break; the broken block is a mature Ageable cropblocks%block_type%farming
player_fishCoreLib shared event; player fishingstates%fish_state%fishing
craft_itemCoreLib shared event; player crafts an itemitem_sources + matcher%result_amount%, %result_type%crafting
brew_completeCoreLib shared event; attributed to the most recent brewing stand userpotion_types%potion_type%brewing
furnace_extractCoreLib shared event; player extracts a furnace resultitem_sources + matcher%result_amount%, %result_type%smelting
entity_tameCoreLib shared event; player tames an entityentity_types%entity_type%taming

CoreLib also publishes a block_place shared event, but EmakiLevel only uses it to record player-placed block locations. Writing block_place as a source trigger never grants exp

Rule matching ​

Supported match fields:

FieldTypeRequiredDefaultRangeDescription
entity_typeslist<string>no[] (unrestricted)Bukkit EntityType name, e.g. ZOMBIE, WOLF, ENDER_DRAGONMatches the entity type
blockslist<string>no[] (unrestricted)Bukkit Material name, e.g. STONE, WHEAT, OAK_LOGMatches the block
stateslist<string>no[] (unrestricted)event state name, e.g. CAUGHT_FISHMatches the event state
potion_typeslist<string>no[] (unrestricted)potion base type, e.g. AWKWARD, SPEED, STRENGTHMatches the potion base type
mob_idslist<string>no[] (unrestricted)MythicMobs internal ID, e.g. SkeletonKingMatches the MythicMob ID; matching is case-normalized
item_sourceslist<string>no[] (unrestricted)valid CoreLib ItemSourceAllowed item sources for the item involved in the event (crafting and smelting results, and so on)
matchermappingno—see Item MatcherNon-item-source conditions (component, PDC, lore) for the same item, ANDed with the sibling item_sources
exp_formulastringno0expressionExp formula. Values less than or equal to 0 do not grant exp

Behavior:

  • Multiple sources can share the same trigger; all matching sources are processed
  • Inside one source, rules are checked in order and the first matching rule is used
  • An empty match field means no restriction for that field
  • entity_types, blocks, states, and potion_types are normalized to uppercase for matching
  • item_sources uses CoreLib ItemSource matching, not only vanilla materials
  • The old per-rule result_item_sources key is now spelled item_sources. /emakilevel convert-legacy still handles that rename; run it without arguments for a dry run, then with confirm to write the change out with a backup

DANGER

A rule that declares neither item_sources nor matcher matches every item, making it an unconditional catch-all. Rules use the first match in declaration order, so once such a rule appears, no rule below it is ever reached

Keep catch-all rules last, and declare at least one of item_sources and matcher whenever a rule should be restricted to specific items

Granting exp by item data ​

item_sources selects the item and matcher adds data conditions on top; both must hold. For example, granting extra exp only for crafting an enchanted result:

yaml
rules:
  - item_sources:
      - minecraft-diamond_sword
    matcher:
      type: component
      component: enchantments
      operator: exists
    exp_formula: "50"
  # Fallback: a plain diamond sword
  - item_sources: ["minecraft-diamond_sword"]
    exp_formula: "10"

Keep the matching order in one sentence: rules use the first match in declaration order, so narrow conditions must be declared before the fallback. Full syntax is in Item Matcher

Exp formulas ​

Exp formulas use the CoreLib expression engine and %key% variables, and are filled in under the rule's exp_formula

yaml
rules:
  - blocks: ["DIAMOND_ORE", "DEEPSLATE_DIAMOND_ORE"]
    exp_formula: "25"
  - item_sources: ["minecraft-diamond_pickaxe"]
    exp_formula: "40 * %result_amount%"
  - mob_ids: ["ForestBoss"]
    exp_formula: "300 + %mythic_level% * 20"

If the formula returns 0 or less, the exp grant is skipped

Vanilla kills ​

yaml
sources:
  vanilla_entity_kill:
    enabled: true
    type: "combat"
    trigger: "entity_kill"
    include_players: false
    anti_abuse:
      exp_cooldown_ticks: 5
      ignore_near_spawner: true
      spawner_scan_radius: 8
    rules:
      - entity_types: ["ZOMBIE", "SKELETON", "SPIDER", "CREEPER"]
        exp_formula: "10"
      - entity_types: ["ENDERMAN", "BLAZE", "WITHER_SKELETON"]
        exp_formula: "25"
      - entity_types: ["WITHER", "ENDER_DRAGON"]
        exp_formula: "500"

Notes:

  • Kill attribution is resolved by the CoreLib shared event, which prefers the Bukkit killer
  • When the kill was not direct and anti_abuse.last_damager_tracking.enabled: false, EmakiLevel skips the event
  • The recent damager window is controlled by CoreLib config.yml > gameplay_events.last_damager_expire_ticks, default 200 ticks
  • include_players: false prevents player kills from granting exp
  • With ignore_near_spawner: true, blocks within spawner_scan_radius (clamped to 0–16) around the kill location are scanned, and the source is skipped when a spawner is found. Larger radii scan many more blocks; keeping the default 8 is recommended

Block break and crop harvest ​

yaml
sources:
  mining:
    enabled: true
    type: "mining"
    trigger: "block_break"
    anti_abuse:
      ignore_player_placed_blocks: true
      exp_cooldown_ticks: 2
    rules:
      - blocks: ["STONE", "DEEPSLATE"]
        exp_formula: "1"
      - blocks: ["COAL_ORE", "DEEPSLATE_COAL_ORE", "IRON_ORE", "DEEPSLATE_IRON_ORE"]
        exp_formula: "5"

Anti-abuse behavior:

  • anti_abuse.placed_block_tracking: true records player-placed block locations
  • If a source sets ignore_player_placed_blocks: true, that source ignores player-placed blocks
  • Even without source-level ignore_player_placed_blocks, anti_abuse.placed_block_exp: false prevents player-placed blocks from granting break exp
  • The placed-block record is removed when the block is broken; records older than anti_abuse.placed_block_record_ttl_ticks are pruned on the next read/write

Mature crops use the same break event, but only trigger when block data is Ageable and fully grown:

yaml
sources:
  farming:
    enabled: true
    type: "farming"
    trigger: "crop_harvest"
    anti_abuse:
      ignore_player_placed_blocks: true
      exp_cooldown_ticks: 2
    rules:
      - blocks: ["WHEAT", "CARROTS", "POTATOES", "BEETROOTS", "NETHER_WART"]
        exp_formula: "4"

Breaking a mature crop fires both block_break and crop_harvest, so sources bound to either trigger can each grant exp

Fishing ​

yaml
sources:
  player_fish:
    enabled: true
    type: "fishing"
    trigger: "player_fish"
    rules:
      - states: ["CAUGHT_FISH"]
        exp_formula: "10"
      - states: ["CAUGHT_ENTITY"]
        exp_formula: "5"

%fish_state% is the PlayerFishEvent.State name. Common states include CAUGHT_FISH, CAUGHT_ENTITY, FISHING, BITE, and FAILED_ATTEMPT; by default exp is granted only when an item or entity is actually caught

Crafting ​

yaml
sources:
  craft_item:
    enabled: true
    type: "crafting"
    trigger: "craft_item"
    count_result_amount: true
    rules:
      - item_sources:
          - "minecraft-crafting_table"
          - "minecraft-furnace"
        exp_formula: "5 * %result_amount%"
      - item_sources:
          - "minecraft-diamond_pickaxe"
          - "minecraft-diamond_sword"
        exp_formula: "40 * %result_amount%"

Formula variables:

VariableDescription
%result_amount%Recipe result stack amount, minimum 1
%result_type%Bukkit Material name

Brewing ​

yaml
sources:
  brew_complete:
    enabled: true
    type: "brewing"
    trigger: "brew_complete"
    attribution:
      expire_ticks: 1200
    rules:
      - potion_types: ["AWKWARD", "SPEED", "STRENGTH"]
        exp_formula: "15"

Brewing events do not directly include a player. CoreLib records the most recent player who interacted with the brewing stand and attributes the completed brew to that player. Each source can set its own window through attribution.expire_ticks (default 1200 ticks); brews older than that window are skipped by the source

VariableDescription
%potion_type%First recognized potion base type in the brewing inventory, or UNKNOWN

Smelting ​

yaml
sources:
  furnace_extract:
    enabled: true
    type: "smelting"
    trigger: "furnace_extract"
    rules:
      - item_sources:
          - "minecraft-iron_ingot"
          - "minecraft-copper_ingot"
          - "minecraft-gold_ingot"
        exp_formula: "3 * %result_amount%"
      - item_sources: ["minecraft-netherite_scrap"]
        exp_formula: "20 * %result_amount%"

Formula variables:

VariableDescription
%result_amount%Amount extracted from the furnace
%result_type%Bukkit Material name

Taming ​

yaml
sources:
  entity_tame:
    enabled: true
    type: "taming"
    trigger: "entity_tame"
    rules:
      - entity_types: ["WOLF", "CAT", "HORSE", "PARROT"]
        exp_formula: "20"

Only player owners receive exp

VariableDescription
%entity_type%Bukkit EntityType of the tamed entity

Custom examples ​

Main exp for fishing events:

yaml
id: "treasure_sources"
enabled: true
sources:
  fishing_treasure_main:
    enabled: true
    type: "main"
    trigger: "player_fish"
    rules:
      - states: ["CAUGHT_FISH"]
        exp_formula: "2"

All-log logging exp:

yaml
id: "custom_logging"
enabled: true
sources:
  all_logs:
    enabled: true
    type: "logging"
    trigger: "block_break"
    anti_abuse:
      ignore_player_placed_blocks: true
    rules:
      - blocks:
          - "OAK_LOG"
          - "BIRCH_LOG"
          - "SPRUCE_LOG"
          - "JUNGLE_LOG"
          - "ACACIA_LOG"
          - "DARK_OAK_LOG"
          - "MANGROVE_LOG"
          - "CHERRY_LOG"
        exp_formula: "5"

Small main exp for all non-player kills:

yaml
id: "main_kill_bonus"
enabled: true
sources:
  main_entity_kill_bonus:
    enabled: true
    type: "main"
    trigger: "entity_kill"
    include_players: false
    rules:
      - exp_formula: "1"

The last rule has no entity_types, so it matches all entities