Triggers & Casting
Active Triggers
EmakiSkills provides 14 built-in active triggers. Active triggers require the player to press keys in cast mode:
| Trigger ID | Display Name | Event Source | Conflict Rule |
|---|---|---|---|
left_click | [Left Click] | InteractTriggerSource | Conflicts with shift_left_click |
right_click | [Right Click] | InteractTriggerSource | Conflicts with shift_right_click |
shift_left_click | [Shift + Left Click] | InteractTriggerSource | Conflicts with left_click |
shift_right_click | [Shift + Right Click] | InteractTriggerSource | Conflicts with right_click |
drop_q | [Q Key] | DropTriggerSource | No conflicts |
hotbar_1 | [Number Key 1] | HotbarTriggerSource | No conflicts |
hotbar_2 | [Number Key 2] | HotbarTriggerSource | No conflicts |
hotbar_3 | [Number Key 3] | HotbarTriggerSource | No conflicts |
hotbar_4 | [Number Key 4] | HotbarTriggerSource | No conflicts |
hotbar_5 | [Number Key 5] | HotbarTriggerSource | No conflicts |
hotbar_6 | [Number Key 6] | HotbarTriggerSource | No conflicts |
hotbar_7 | [Number Key 7] | HotbarTriggerSource | No conflicts |
hotbar_8 | [Number Key 8] | HotbarTriggerSource | No conflicts |
hotbar_9 | [Number Key 9] | HotbarTriggerSource | No conflicts |
Conflict Rules
Conflict rules are configured via incompatible_with. When two triggers conflict with each other, the same player cannot bind them to different slots simultaneously.
Typical conflict: left_click ↔ shift_left_click, because the Shift+Left-click event in Bukkit also triggers the left-click event simultaneously, causing ambiguity.
Event Sources
| Source Class | Listened Event | Description |
|---|---|---|
InteractTriggerSource | PlayerInteractEvent | Left/right click and Shift combinations |
DropTriggerSource | PlayerDropItemEvent | Q key item drop |
HotbarTriggerSource | PlayerItemHeldEvent | Number key hotbar switching |
Passive Triggers
Passive triggers are automatically fired by game events without requiring cast mode. Passive skills declare which passive triggers they respond to via the passive_triggers list in their definition files.
EmakiSkills provides 22 built-in passive triggers:
| Trigger ID | Display Name | Trigger Event | Target Passing |
|---|---|---|---|
attack | [Attack Hit] | Player attacks entity | Attacked entity |
damaged_by_entity | [Damaged by Entity] | Player damaged by entity | Attacker |
damaged | [Damaged] | Any damage received | None |
death | [Death] | Player death | None |
kill_entity | [Kill Entity] | Kill non-player entity | Killed entity |
kill_player | [Kill Player] | Kill player | Killed player |
shoot_bow | [Shoot Bow] | Shoot bow | None |
arrow_hit | [Arrow Hit Entity] | Arrow hits entity | Hit entity |
arrow_land | [Arrow Land] | Arrow hits block | None (passes landing point) |
shoot_trident | [Throw Trident] | Throw trident | None |
trident_hit | [Trident Hit Entity] | Trident hits entity | Hit entity |
trident_land | [Trident Land] | Trident hits block | None (passes landing point) |
break_block | [Break Block] | Break block | None (passes block location) |
place_block | [Place Block] | Place block | None (passes block location) |
drop_item | [Drop Item] | Drop item (not sneaking) | Dropped item entity |
shift_drop_item | [Shift+Drop Item] | Drop item (sneaking) | Dropped item entity |
swap_items | [Swap Items] | Swap hand items (not sneaking) | None |
shift_swap_items | [Shift+Swap Items] | Swap hand items (sneaking) | None |
login | [Login] | Player joins server | None |
sneak | [Sneak] | Start sneaking | None |
teleport | [Teleport] | Player teleport | None (passes target location) |
timer | [Timer] | Periodic check | None |
The timer trigger interval is configured via passive_trigger_settings.timer_interval_ticks, default 20 ticks (1 second).
Passive Casting Flow
The passive skill casting flow is simpler than active skills — it skips cast mode check and slot binding lookup:
Game event → PassiveTriggerDispatcher.dispatch(invocation)
│
├─ 1. Check trigger exists and is enabled
│
├─ 2. Iterate all unlocked skills
│ Filter: trigger_type == passive && passive_triggers contains current trigger
│
├─ 3. Check forced delay / global cooldown / skill cooldown
│
├─ 4. Check resource costs
│
├─ 5. MythicMobs cast (passes event target info)
│
└─ Post-success: consume resources, record cooldownsTarget Passing
When a passive skill triggers, the event's target entity and location are passed to MythicMobs @target. For example, the attack trigger passes the attacked entity as target. Triggers without a target entity use the player as caster without passing additional targets.
Cast Mode Entry
Cast mode uses the F key (PlayerSwapHandItemsEvent) to toggle. The F key's original swap-hand function is intercepted by cast mode.
Active skills require the player to enter cast mode first. Outside cast mode, active trigger events are ignored. Passive skills are not affected by cast mode and are always listening.
Active Skill Casting Flow
When an active trigger event reaches CastAttemptService, the following 10-step check is executed:
Trigger event → CastAttemptService.attemptCast(player, triggerId)
│
├─ 1. Validate input
│ player non-null, triggerId non-null
│
├─ 2. Check cast mode
│ CastModeService.isCastModeEnabled(player) == true
│ ✗ → Failure: NOT_IN_CAST_MODE
│
├─ 3. Find binding
│ Iterate PlayerSkillProfile.bindings, find SkillSlotBinding matching triggerId
│ ✗ → Failure: NO_BINDING
│
├─ 4. Find skill definition
│ SkillRegistryService.getDefinition(binding.skillId)
│ ✗ → Failure: SKILL_NOT_FOUND
│
├─ 5. Verify skill is still in unlock pool
│ PlayerSkillStateService.getUnlockedSkills(player) contains binding.skillId
│ ✗ → Failure: SOURCE_LOST (equipment unequipped)
│
├─ 6. Check forced delay
│ PlayerCastTimingState.isForcedDelayActive() == false
│ ✗ → Failure: FORCED_DELAY_ACTIVE
│
├─ 7. Check global cooldown
│ PlayerCastTimingState.isGlobalCooldownActive() == false
│ ✗ → Failure: GLOBAL_COOLDOWN_ACTIVE
│
├─ 8. Check skill cooldown
│ PlayerCastTimingState.isSkillOnCooldown(skillId) == false
│ ✗ → Failure: SKILL_COOLDOWN_ACTIVE
│
├─ 9. Check resource costs
│ Iterate SkillDefinition.resourceCosts:
│ ├─ local-resource → Check PlayerLocalResourceState
│ ├─ ea-resource → Check EA resource via EaBridge
│ └─ ea-attribute-check → Check EA attribute via EaBridge
│ ✗ → Failure: RESOURCE_INSUFFICIENT
│
├─ 10. MythicMobs cast
│ MythicSkillCastService.cast(player, mythicSkillId)
│ ✗ → Failure: MYTHIC_CAST_FAILED
│
└─ Post-success handling:
├─ Consume resources (resources with operation = CONSUME)
├─ Record skill cooldown (cooldown_ticks)
├─ Record global cooldown (global_cooldown_ticks)
└─ Record forced delay (forced_global_cast_delay_ticks)Failure Reason Enum
| Failure Reason | Description |
|---|---|
NOT_IN_CAST_MODE | Not in cast mode |
NO_BINDING | Trigger has no skill bound |
SKILL_NOT_FOUND | Skill definition does not exist |
SOURCE_LOST | Skill source lost (equipment unequipped) |
FORCED_DELAY_ACTIVE | Forced delay active |
GLOBAL_COOLDOWN_ACTIVE | Global cooldown active |
SKILL_COOLDOWN_ACTIVE | Skill cooldown active |
RESOURCE_INSUFFICIENT | Insufficient resources |
MYTHIC_SKILL_NOT_FOUND | MythicMobs skill does not exist |
MYTHIC_CAST_FAILED | MythicMobs cast failed |
ActionBar Service
ActionBarService periodically refreshes the player's ActionBar during cast mode, displaying the current skill slot status.
Template Variables
| Variable | Description |
|---|---|
{slot_1} ~ {slot_N} | Skill name for each slot (empty if unbound) |
{slot_display} | Formatted display of all slots |
{forced_delay} | Current forced delay remaining time |
Configuration Example
actionbar:
enabled: true
refresh_interval_ticks: 10
template_cast_mode: "&aCast Mode &7| {slot_display}"
template_idle: "&7Idle"EaBridge & MythicBridge
EaBridge
EaBridge obtains the EmakiAttributeBridge service via Bukkit's ServicesManager:
| Method | Description |
|---|---|
isAvailable() | Whether the EA bridge is available |
readResourceCurrent() | Read the current value of an EA resource |
consumeResource() | Consume an EA resource |
readAttributeValue() | Read an EA attribute value |
providerMode() | Current provider mode |
MythicBridge
MythicBridge wraps the MythicMobs API:
| Method | Description |
|---|---|
isAvailable() | Whether MythicMobs is available |
skillExists() | Check if a MythicMobs skill exists |
cast() | Execute a MythicMobs skill cast (active skills, no target) |
cast(target, location) | Execute a MythicMobs skill cast (passive skills, passes target entity and location) |
GUI Layout
skills_gui — Skills GUI (6 rows)
Row 1: [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border]
Row 2: [Border] [Skill 1] [Skill 2] [Skill 3] [Skill 4] [Skill 5] [Skill 6] [Skill 7] [Border]
Row 3: [Border] [Skill 8] [Skill 9] [Skill 10] [...] [...] [...] [...] [Border]
Row 4: [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border]
Row 5: [Border] [Slot 1] [Slot 2] [Slot 3] [Border] [Cast Mode] [Border] [Border] [Border]
Row 6: [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border]- Skill area (rows 2-3): Displays all unlocked skills, click to select
- Slot area (row 5): Displays currently bound skill slots
- Cast mode button: Toggle cast mode on/off
trigger_select_gui — Trigger Selection GUI (4 rows)
Row 1: [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border] [Border]
Row 2: [Border] [Trigger 1] [Trigger 2] [Trigger 3] [Trigger 4] [Trigger 5] [Border] [Border] [Border]
Row 3: [Border] [Trigger 6] [Trigger 7] [...] [...] [...] [Border] [Border] [Border]
Row 4: [Border] [Border] [Border] [Border] [Back] [Border] [Border] [Border] [Border]- Trigger area (rows 2-3): Displays all available triggers; conflicting triggers are shown in gray
- Back button (row 4): Return to the skills GUI