English
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
| Field | Type | Required | Default | Accepted values | Description |
|---|---|---|---|---|---|
id | string | Yes | none | non-blank string | Unique 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 |
type | string | No | same as id | a 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_name | string | No | null | any string | Definition 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 |
experience | int | No | 0 | — | Experience override on kill; a value above 0 replaces the vanilla amount |
components | section | No | empty | keys must appear in Components | Maps to entity attributes and data components. Unknown keys are skipped silently |
ea_attributes | section | No | empty | numeric values; keys are EA attribute IDs | EmakiAttribute 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 |
actions | section | No | empty | values are action-line string lists; keys are trigger names | Trigger → 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 |
threat | section | No | none | see the table below | Threat table configuration; omitting the whole section disables the threat system (and does not affect target_selector) |
boss_bar | section | No | none | see the table below | Boss bar configuration; omitting the whole section registers no bar |
model | section | No | none | sub-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_selector | string | No | null | a selectors id defined in target_selectors.yml | Target 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_target | section | No | none (treated as disabled) | enabled, interval_ticks | Target 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.5Type 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: 5The 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
| Field | Type | Required | Default | Accepted values | Description |
|---|---|---|---|---|---|
<attribute ID> | double | No | none | a number; entries whose absolute value is ≤ 1e-9 are skipped | Attribute 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
| Field | Type | Required | Default | Accepted values | Description |
|---|---|---|---|---|---|
enabled | boolean | No | true | true / false | Whether the threat system is active. When false, threat is not accumulated and targets are not rewritten |
max_range | double | No | 64.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.damage | double | No | 1.0 | — | Threat added per point of damage the player deals to the mob |
weights.healing | double | No | 0.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.rate | double | No | 0.05 | — | Each decay cycle (20 ticks) multiplies threat by 1 - rate; 0.05 is roughly a 5% decay per second |
decay.out_of_range | boolean | No | true | true / false | Whether 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
| Field | Type | Required | Default | Accepted values | Description |
|---|---|---|---|---|---|
title | string | No | "" | any string | Bar title. Supports MiniMessage format |
color | string | No | PURPLE | PINK / BLUE / RED / GREEN / YELLOW / PURPLE / WHITE (case-insensitive) | Bar colour; an invalid value falls back to PURPLE silently |
style | string | No | SOLID | SOLID / SEGMENTED_6 / SEGMENTED_10 / SEGMENTED_12 / SEGMENTED_20 (case-insensitive) | Bar style; an invalid value falls back to SOLID silently |
range | double | No | 64.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
| Field | Type | Required | Default | Accepted values | Description |
|---|---|---|---|---|---|
enabled | boolean | No | false | true / false | Whether periodic locking is active. It only participates when target_selector is also set |
interval_ticks | int | No | 20 | — (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
| Field | Type | Required | Default | Accepted values | Description |
|---|---|---|---|---|---|
snapshot_interval_ticks | int | No | 20 | ≥ 0; 0 disables snapshots | Scheduling 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_tick | int | No | 20 | ≥ 1 | How many online players are dispatched to their own thread per round; the remainder is deferred to later rounds |
equipment_tables.<table id> | section | No | empty | — | Equipment weight tables referenced by score.type: equipment |
equipment_tables.<table id>.slots | string list | No | [] | slot names head / chest / legs / feet / main_hand / off_hand (also mainhand / offhand); anything else is parsed as an EquipmentSlot enum name | Slots that contribute to the score; an unrecognised slot logs a WARN and is skipped |
equipment_tables.<table id>.default_weight | double | No | 0 | — | Default weight for items not listed in the table |
equipment_tables.<table id>.weights.<item source> | double | No | none | item 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> | section | No | empty | — | 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>.mode | string | No | highest | highest / 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>.range | double | No | unset | ≥ 0 (blocks) | Candidate search radius. When unset it falls back to the mob's threat.max_range, then to 16 |
selectors.<selector id>.filter | section | No | none | a CoreLib condition block | Candidate filter; evaluated per player against the snapshot with the player as context, and failing candidates never enter the pool |
selectors.<selector id>.score | list | No | [] | term type: threat / distance / health / equipment / expression | Score 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[].factor | double | No | 1.0 | a finite number | Weight multiplier of that term |
selectors.<selector id>.score[].table | string | required for type: equipment | none | a defined equipment table id | Referenced weight table; a missing one logs a WARN and skips that term |
selectors.<selector id>.score[].value | string | required for type: expression | none | length ≤ 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.0A 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