Skip to content

Mob Definitions ​

Every field in a mobs/*.yml mob definition file is explained below, covering type override, attributes, threat, boss bars, target selectors, and the model section. Mob definition files live in plugins/EmakiMobs/mobs/*.yml. Each file defines one custom mob. Every .yml in the directory is loaded; a file that fails to parse only affects itself (an issue is recorded) while the other files keep loading. The definition released on first start is mobs/example_zombie.yml (controlled by release_default_data); the example below mirrors the bundled mobs/elite_zombie.yml

Top-level fields ​

FieldTypeRequiredDefaultAccepted valuesDescription
idstringYesnonenon-blank stringUnique mob ID. A blank or missing value makes the file be discarded with a recorded issue. Matching a vanilla EntityType name (case-insensitive) activates type override. Commands and the API match it case-sensitively
typestringNosame as ida valid vanilla EntityType name (e.g. zombie, skeleton, creeper, case-insensitive)Underlying vanilla entity type; an unresolvable value discards the file with a recorded issue
display_namestringNonullany stringDefinition metadata exposed to the API only (MobDefinition.displayName()). It does not set the entity name tag and does not appear in command output. Use components.custom_name to show a name in game
experienceintNo0—Experience override on kill; a value above 0 replaces the vanilla amount
componentssectionNoemptykeys must appear in ComponentsMaps to entity attributes and data components. Unknown keys are skipped silently
ea_attributessectionNoemptynumeric values; keys are EA attribute IDsEmakiAttribute value map. Only effective with EmakiAttribute installed; otherwise the whole section is ignored and nothing else is affected. The legacy attributes key is read as a fallback with a WARN; migrating is recommended
actionssectionNoemptyvalues are action-line string lists; keys are trigger namesTrigger → CoreLib action lines. Executed by the CoreLib action pipeline; EmakiSkills is not required. Empty lists are ignored; the legacy skills key is read as a fallback with a WARN. See Triggers
threatsectionNononesee the table belowThreat table configuration; omitting the whole section disables the threat system (and does not affect target_selector)
boss_barsectionNononesee the table belowBoss bar configuration; omitting the whole section registers no bar
modelsectionNononesub-keys: blueprint (required), api, scale, animations.<action>, keyframes.<action>.{duration_ticks,loop,priority,conflict,frames[]}, lod.{near,mid,far}Model mounting and animation; fields and defaults under the "Mob definition model: section" of Entity Models & Animations. A missing blueprint makes the section ignored with a load-time warning
target_selectorstringNonulla selectors id defined in target_selectors.ymlTarget selector id (normalised to lower case when read). When set, the mob picks targets through that selector, taking precedence over the threat table; when unset, the threat table logic runs. An unknown id simply selects nothing and does not change the target
lock_targetsectionNonone (treated as disabled)enabled, interval_ticksTarget lock configuration. Only effective when target_selector is also set and enabled: true: it re-selects the target every interval_ticks and writes it onto the entity

Type override ​

When id exactly matches a valid vanilla EntityType name (case-insensitive), EmakiMobs marks the entity as managed on CreatureSpawnEvent and applies this definition's components (including filling max_health). Because that mark is what the attribute contribution provider keys on, ea_attributes also reaches that entity

yaml
# Buff all vanilla zombies
id: zombie
type: zombie
components:
  max_health: 22.0
  attack_damage: 3.5

Type override does not fire EmakiMobSpawnEvent and does not run on_spawn action lines (both belong to entities created through the mob factory). It also ignores spawn_rules/, so spawn rules never constrain it

CAUTION

⚠ Type override affects all naturally spawned entities of that type, including those created by other plugins. Use a separate id with a type: natural spawn rule instead when you only want custom mobs in specific areas

ea_attributes section (optional) ​

yaml
ea_attributes:
  STR: 15   # key matches the attribute ID defined in EmakiAttribute
  VIT: 10
  AGI: 5

The ea_attributes section is fully optional: it only takes effect when the EmakiAttribute plugin is installed. Without EmakiAttribute, EmakiMobs ignores the entire ea_attributes section — no errors, and no impact on any other part of the mob definition

FieldTypeRequiredDefaultAccepted valuesDescription
<attribute ID>doubleNononea number; entries whose absolute value is ≤ 1e-9 are skippedAttribute ID as key, number as value. Only numeric values are read; non-numeric ones are ignored silently

RESOURCE-class attributes do not work on mobs

The current value of health / mana-style RESOURCE attributes is owned by the player-side resource system and has no effect on non-player entities. Raise a mob's health ceiling with components.max_health or a VANILLA-mapped attribute such as max_health_vanilla. Configuring both components.max_health and ea_attributes.max_health_vanilla triggers a precheck WARN pointing out that the two stack

threat section ​

FieldTypeRequiredDefaultAccepted valuesDescription
enabledbooleanNotruetrue / falseWhether the threat system is active. When false, threat is not accumulated and targets are not rewritten
max_rangedoubleNo64.0— (blocks)Threat eviction distance. A player can keep accumulating threat beyond it (a ranged hit, for example), but the next decay cycle (every 20 ticks) moves out-of-range players out of the table
weights.damagedoubleNo1.0—Threat added per point of damage the player deals to the mob
weights.healingdoubleNo0.5—Every time a player regains health (including natural regeneration), the healed amount times this weight is added to managed mobs within 32 blocks
decay.ratedoubleNo0.05—Each decay cycle (20 ticks) multiplies threat by 1 - rate; 0.05 is roughly a 5% decay per second
decay.out_of_rangebooleanNotruetrue / falseWhether to evict players beyond max_range. When the whole decay section is missing, this behaves as true

Entries below 0.001 are cleaned up, and picking the highest-threat target requires threat to be strictly greater than 0, so once a mob's threat has decayed to near zero it will not re-acquire a target (it simply stops chasing players)

boss_bar section ​

FieldTypeRequiredDefaultAccepted valuesDescription
titlestringNo""any stringBar title. Supports MiniMessage format
colorstringNoPURPLEPINK / BLUE / RED / GREEN / YELLOW / PURPLE / WHITE (case-insensitive)Bar colour; an invalid value falls back to PURPLE silently
stylestringNoSOLIDSOLID / SEGMENTED_6 / SEGMENTED_10 / SEGMENTED_12 / SEGMENTED_20 (case-insensitive)Bar style; an invalid value falls back to SOLID silently
rangedoubleNo64.0— (blocks)Visibility range. The viewer set is recomputed every 20 ticks: players in the same world within that distance see the bar, everyone else is removed. Progress updates on damage and heal events

Invalid values fall back silently

color and style are resolved with valueOf. When resolution fails there is no error and no log line — the value falls back to the default (color → PURPLE, style → SOLID)

BarStyle has no NOTCHED_6 / NOTCHED_10 / NOTCHED_12 / NOTCHED_20 constants. Writing NOTCHED_10 gives no warning and silently produces a solid (SOLID) bar. Use SEGMENTED_* for a segmented bar

lock_target section ​

FieldTypeRequiredDefaultAccepted valuesDescription
enabledbooleanNofalsetrue / falseWhether periodic locking is active. It only participates when target_selector is also set
interval_ticksintNo20— (ticks)Re-lock period. The lock loop itself runs every 20 ticks and the configured value is rounded up to a multiple of 20 ticks (anything below 20 counts as one round)

Target selectors (target_selectors.yml) ​

target_selectors.yml is a static plugin file (released only when missing, never merged on upgrade) shared by all mobs. In a mob definition you reference an id under selectors through target_selector

FieldTypeRequiredDefaultAccepted valuesDescription
snapshot_interval_ticksintNo20≥ 0; 0 disables snapshotsScheduling interval (ticks) for the player score snapshot. Once disabled, equipment, expression and health are permanently 0 and selectors with a filter have no eligible candidate
snapshot_players_per_tickintNo20≥ 1How many online players are dispatched to their own thread per round; the remainder is deferred to later rounds
equipment_tables.<table id>sectionNoempty—Equipment weight tables referenced by score.type: equipment
equipment_tables.<table id>.slotsstring listNo[]slot names head / chest / legs / feet / main_hand / off_hand (also mainhand / offhand); anything else is parsed as an EquipmentSlot enum nameSlots that contribute to the score; an unrecognised slot logs a WARN and is skipped
equipment_tables.<table id>.default_weightdoubleNo0—Default weight for items not listed in the table
equipment_tables.<table id>.weights.<item source>doubleNononeitem source shorthand such as minecraft:iron_sword or emakiitem:<id>Item → weight. Entries that cannot be parsed, or whose item source is unavailable, log a WARN and are skipped
selectors.<selector id>sectionNoempty—Selector definitions. A missing section counts as a blocking configuration error (precheck ERROR). The id is normalised to lower case when read and is what target_selector references
selectors.<selector id>.modestringNohighesthighest / lowest / random / weighted_random / first_damager / last_damager (case-insensitive)Target picking strategy; an invalid value logs a WARN and discards the selector. With an empty score, highest/lowest/weighted_random cannot pick anyone
selectors.<selector id>.rangedoubleNounset≥ 0 (blocks)Candidate search radius. When unset it falls back to the mob's threat.max_range, then to 16
selectors.<selector id>.filtersectionNononea CoreLib condition blockCandidate filter; evaluated per player against the snapshot with the player as context, and failing candidates never enter the pool
selectors.<selector id>.scorelistNo[]term type: threat / distance / health / equipment / expressionScore terms; the total is the sum of each term's value times its factor. An unknown type or a non-finite factor logs a WARN and skips that term
selectors.<selector id>.score[].factordoubleNo1.0a finite numberWeight multiplier of that term
selectors.<selector id>.score[].tablestringrequired for type: equipmentnonea defined equipment table idReferenced weight table; a missing one logs a WARN and skips that term
selectors.<selector id>.score[].valuestringrequired for type: expressionnonelength ≤ 256, parenthesis nesting ≤ 10, no `/$/\Expression string (e.g. %vault_eco_balance% / 1000); a failed validation logs a WARN and skips that term.

NOTE

The condition and expression syntax used by filter and score comes from EmakiCoreLib — see CoreLib expressions. With snapshots disabled (snapshot_interval_ticks: 0), every snapshot-backed term is permanently 0

Full example ​

yaml
id: elite_zombie
type: zombie
display_name: "<gradient:#ff4444:#ffaa00>Elite Zombie</gradient>"

components:
  max_health: 80.0
  movement_speed: 0.28
  attack_damage: 7.0
  follow_range: 40.0
  knockback_resistance: 0.3
  custom_name: "<gradient:#ff4444:#ffaa00>Elite Zombie</gradient>"
  custom_name_visible: true
  persistent: true

experience: 80

ea_attributes:
  STR: 15
  VIT: 10

actions:
  on_spawn:
    - "nearby radius=20 include_players=true | send_message text='<red>Elite Zombie has arrived!'"
  on_death:
    - "killer | give_exp amount=80"

threat:
  enabled: true
  max_range: 48.0

boss_bar:
  title: "<gradient:#ff4444:#ffaa00>Elite Zombie</gradient>"
  color: RED
  style: SEGMENTED_10
  range: 60.0

A custom loot table and the loot_table component are independent

loot_tables/<mob_id>.yml applies as soon as a same-named file exists, whether or not components writes a loot_table key; once it applies, every vanilla drop is cleared first (experience is kept). The loot_table component only sets the vanilla/datapack loot table: writing loot_table: "minecraft:entities/zombie" sets a vanilla table, but with a same-named YAML table present the vanilla drops are still replaced. See the "Loot fields" section of Components