🚥 Events¶
KaMenu supports executing predefined action lists at specific moments in the menu lifecycle, configured via the Events key. The event system allows you to run specific logic when the menu opens, closes, and at other key moments.
Supported Events¶
| Event Name | Trigger | Supported Variables |
|---|---|---|
Open |
Before the menu opens | {data:*}, {gdata:*}, {meta:*}, %papi_var% |
Close |
After the menu closes | {data:*}, {gdata:*}, {meta:*}, %papi_var%, $(input_key) |
Click |
Pending action list to trigger | {data:*}, {gdata:*}, {meta:*}, %papi_var% |
Tasks |
Repeating task groups while the menu is open | {data:*}, {gdata:*}, {meta:*}, %papi_var%, {js:*} |
Important notes:
- The
Openevent fires before the menu opens, so it does not support$(input_key)input variables (the input fields haven't been displayed yet) - The
Openevent waits for the full action chain to complete before opening the menu; ifreturnis encountered, the menu will not open - The
Closeevent fires after the menu closes and supports all variable formats, including$(input_key) Tasksdo not receive live input responses, so they do not support real-time$(input_key)values; if a task must stop exactly when the menu closes, make sure every menu-closing path executesclose/force-close
Basic Syntax¶
Simple Event (Unconditional)¶
Conditional Event¶
Events:
Open:
- condition: "condition expression" # Optional
allow:
- 'action when condition is met 1'
- 'action when condition is met 2'
deny:
- 'action when condition is not met 1'
- 'action when condition is not met 2'
Periodic Tasks (Events.Tasks)¶
Events.Tasks runs action lists repeatedly at a fixed tick interval while the menu is open. Each task has its own execution state and can be used for status refreshes, timed checks, timeout handling, sounds, and similar workflows.
Events:
Tasks:
refresh:
mode: auto
interval: 20
repeat: -1
run_immediately: true
skip_if_running: true
actions:
- 'tell: &7Periodic menu refresh'
- condition: '{data:warning} == true'
allow:
- 'sound: block.note_block.pling 1 1'
deny: []
on_end:
- 'tell: &7Refresh task stopped'
Options¶
| Field | Type | Default | Description |
|---|---|---|---|
mode |
String |
auto |
Trigger mode. auto starts when the menu opens, manual starts only through the run-task action |
interval |
Long |
20 |
Repeat interval in ticks. Minimum value is 1 |
repeat |
Int |
-1 |
Number of rounds. Missing, 0, or -1 means keep running until the menu lifecycle ends or the task is stopped |
run_immediately |
Boolean |
false |
Whether to run once immediately after the menu opens |
skip_if_running |
Boolean |
true |
Whether to skip a round if the previous action chain is still running |
actions |
List |
Required | The action list to execute. Supports conditions, wait, and nested actions |
on_end / end_actions |
List |
[] |
Action list executed after the task lifecycle ends. Supports normal actions syntax |
Execution Rules¶
- Periodic tasks start only after the menu is successfully shown. If
Events.Openusesreturnto prevent opening, tasks do not start. - A player has only one task lifecycle for the same
contextId; reopening the same menu does not create duplicate running tasks with the same task ID. - Each task ID under
Events.Tasksis an independent running key. If that task is already running, anotherrun-taskcall will not create a duplicate. mode: autotasks start when the menu opens.mode: manualtasks start only whenrun-taskis executed.- The current menu tasks are cancelled when the player opens another menu, uses
open/force-open/resetto another menu, usesclose/force-close, leaves the server, or the plugin reloads. returninside a periodic task only stops the current round. It does not stop the repeating task. Usestop-current-taskto stop the current task loop and interrupt the rest of the current round.- If a task contains
wait, keepingskip_if_running: trueis recommended to prevent overlapping rounds. - With
Settings.can_escape: true, ESC triggers the corresponding bottom button action:noticetriggers the only button,confirmationtriggers thedenybutton, andmultitriggers theexitbutton when it is configured. For strict lifecycle control, make sure those actions includeclose/force-close, or setSettings.can_escape: falseand provide a close button.
Task Control Actions¶
run-task: <taskId>: Starts the specified task.run-task: <taskId> <count>: Starts the specified task and overrides the round count for this run, for examplerun-task: refresh 10.run-task: *: Starts all defined tasks in the current menu that are not already running.run-task: * <count>: Starts all tasks in the current menu and overrides the round count for this run.stop-task: <taskId>: Stops the specified task and runs itson_end/end_actions.stop-task: *: Stops all running periodic tasks in the current menu and runs each task'son_end/end_actions.stop-current-task: Only valid inside a periodic task. Stops the current task loop and immediately interrupts the rest of the current round.
Example: Timeout Close¶
Settings:
can_escape: false
Events:
Open:
- 'set-meta: menu_seconds 0'
Tasks:
timeout:
mode: auto
interval: 20
repeat: 30
run_immediately: false
actions:
- 'meta: menu_seconds + 1'
- condition: '{meta:menu_seconds} >= 30'
allow:
- 'tell: &cMenu timed out'
- 'close'
- 'stop-current-task'
on_end:
- 'tell: &7Timeout task ended'
Example: Manually Started Task¶
Events:
Tasks:
countdown:
mode: manual
interval: 20
run_immediately: true
actions:
- 'tell: &eCountdown running'
on_end:
- 'tell: &aCountdown finished'
Bottom:
type: multi
buttons:
start:
text: '&a[ Start 10 ]'
actions:
- 'run-task: countdown 10'
stop:
text: '&c[ Stop ]'
actions:
- 'stop-task: countdown'
stop_all:
text: '&4[ Stop All ]'
actions:
- 'stop-task: *'
How to Trigger a Click Action List¶
First, define the action list:
Events:
Click:
hello:
- 'tell: &aHello! Welcome to the server.'
- 'tell: &aHope you enjoy your time here!'
Activate with the actions action:
Bottom:
type: 'notice'
confirm:
text: '&a[ OK ]'
actions:
- 'actions: hello' # Executes the `hello` action list defined above
Action List Arguments¶
actions: can append arguments after the action list name. Arguments are separated by commas:
Events:
Click:
greet:
- 'tell: &aHello, {arg:0}! Welcome to &e{arg:1}&a.'
Bottom:
type: 'notice'
confirm:
text: '&a[ Greet ]'
actions:
- 'actions: greet,player,survival server'
Inside the action list, use {arg:0}, {arg:1} to read arguments. Use single quotes, double quotes, or backticks around an argument when it needs to contain a comma.
Activate with a clickable text:
Body:
text:
type: 'message'
text: 'Please <text="click to greet";actions=hello,player,survival server;hover=Click to run the hello action> to see the welcome message'
Bottom:
type: 'notice'
confirm:
text: '&a[ OK ]'
actions:
- 'hovertext: Please <text="[Click to Greet]";actions=hello,player,survival server;hover=Click to run the hello action> to see the welcome message'
¶
Bottom:
type: 'notice'
confirm:
text: '&a[ OK ]'
actions:
- 'hovertext: Please <text="[Click to Greet]";actions=hello,player,survival server;hover=Click to run the hello action> to see the welcome message'
Special Actions¶
Return Action¶
The return action can be used in an event's action list to interrupt the execution of subsequent actions:
Events:
Open:
- condition: 'hasPerm.kamenu.admin'
allow:
- 'tell: &aWelcome, admin!'
deny:
- 'tell: &cYou do not have permission!'
- 'return' # Interrupt subsequent actions
- 'tell: You will never see this message'
Notes:
returnin theOpenevent prevents the menu from openingreturnin theCloseevent only interrupts the remaining actions (the menu is already closed)returnis effective in both theallowanddenybranches of a condition check
Use Cases¶
1. Permission Checks¶
Unconditional:
Conditional:
Events:
Open:
- condition: '%player_is_op% == true'
allow:
- 'tell: &aYou opened the admin menu'
deny:
- 'tell: &cYou do not have permission to open this menu'
- 'return' # Non-OP players cannot see the menu
2. Compound Condition Checks¶
Events:
Open:
- condition: '%player_level% >= 10 && %player_health% >= 15'
allow:
- 'tell: &aConditions met: level >= 10 and health >= 15'
- 'title: title=&6Welcome;subtitle=&fVIP Player;in=5;keep=40;out=10'
deny:
- 'tell: &7Requirements not met: need level >= 10 and health >= 15'
3. Data Initialisation¶
First-visit detection:
Events:
Open:
- condition: '{data:first_visit} == null'
allow:
- 'tell: &eWelcome for the first time! Data initialised'
- 'set-data: first_visit %timestamp%'
- 'set-data: visit_count 1'
- 'title: title=&6Welcome;subtitle=&fThis is your first visit;in=10;keep=60;out=20'
deny:
- 'tell: &7Welcome back! This is your {data:visit_count} visit'
- 'set-data: visit_count {data:visit_count} + 1'
4. Status Checks¶
Events:
Open:
- condition: '{meta:temp_banned} == true'
allow:
- 'tell: &cYou are temporarily banned and cannot access this menu'
- 'return'
- condition: '%player_health% <= 5'
allow:
- 'tell: &eYour health is very low. Be careful!'
5. Greeting System¶
Events:
Open:
- condition: '%player_health% >= 20'
allow:
- 'tell: &aYour health is great!'
deny:
- 'tell: &7You should keep an eye on your health'
- condition: '%player_level% >= 30'
allow:
- 'tell: &6You have reached level 30!'
6. Close Event Handling¶
Events:
Close:
- 'tell: &aThanks for using this menu'
- 'set-meta: last_visit %timestamp%'
- 'set-data: total_visits {data:total_visits} + 1'
- 'sound: entity.experience_orb.pickup'
Complete Examples¶
Example 1: Admin Panel with Permission Control¶
Title: '&8» &4&lAdmin Panel &8«'
Settings:
can_escape: false
Events:
Open:
- condition: 'hasPerm.kamenu.admin'
allow:
- 'tell: &aWelcome to the admin panel'
deny:
- 'tell: &cYou do not have permission to access this menu!'
- 'sound: block.note_block.bass'
- 'return'
Body:
welcome:
type: 'message'
text: '&7Admin Control Panel - Proceed with caution'
Bottom:
type: 'notice'
confirm:
text: '&c[ Close ]'
actions:
- 'close'
Example 2: Shop Menu with Welcome System¶
Title: '&8» &6&lServer Shop &8«'
Settings:
after_action: CLOSE
Events:
Open:
# First-visit detection
- condition: '{data:shop_first_visit} == null'
allow:
- 'tell: &aWelcome to the server shop! This is your first visit'
- 'set-data: shop_first_visit true'
- 'title: title=&6Welcome;subtitle=&fFirst Visit Bonus Granted;in=5;keep=60;out=20'
deny:
- 'tell: &7Welcome back! Keep browsing'
# VIP player welcome
- condition: 'hasPerm.vip.gold'
allow:
- 'tell: &6Esteemed Gold Member, welcome!'
# Show balance
- 'tell: &fCurrent balance: &e%player_balance%'
Body:
welcome:
type: 'message'
text: '&7Please select the items you need'
Bottom:
type: 'notice'
confirm:
text: '&a[ Browse Items ]'
actions:
- 'tell: &aBrowsing items...'
Example 3: Survey Menu with Data Tracking¶
Title: '&8» &b&lPlayer Survey &8«'
Settings:
can_escape: false
after_action: WAIT_FOR_RESPONSE
Events:
Open:
# Check if already completed
- condition: '{data:questionnaire_completed} == true'
allow:
- 'tell: &aYou have already completed the survey. Thank you!'
- 'return'
- 'tell: &ePlease fill out the survey below'
Close:
# Mark as completed
- 'set-data: questionnaire_completed true'
- 'set-data: questionnaire_date %timestamp%'
- 'tell: &aThank you for completing the survey!'
- 'title: title=&aCompleted;subtitle=&fThank you for your participation;in=5;keep=40;out=10'
Inputs:
rating:
type: 'slider'
text: 'Server Rating (1-10)'
min: 1
max: 10
default: 5
feedback:
type: 'input'
text: 'Comments or Suggestions'
multiline:
max_lines: 5
height: 100
max_length: 500
Bottom:
type: 'confirmation'
confirm:
text: '&a[ Submit ]'
actions:
- 'tell: &aSubmitted successfully!'
- 'close'
deny:
text: '&c[ Cancel ]'
actions:
- 'tell: &cSubmission cancelled'
- 'close'
Example 4: Multi-Condition Check Menu¶
Title: '&8» &5&lVIP Exclusive Features &8«'
Settings:
can_escape: false
Events:
Open:
# Multiple checks
- condition: '%player_level% < 30'
allow:
- 'tell: &cYour level is below 30'
- 'return'
- condition: '!hasPerm.vip.basic'
allow:
- 'tell: &cYou need VIP permission to access this menu'
- 'return'
- condition: '%player_health% < 10'
allow:
- 'tell: &eYour health is low. Stay safe!'
# Passed all checks
- 'tell: &aWelcome to VIP Exclusive Features'
- 'sound: entity.player.levelup'
Body:
welcome:
type: 'message'
text: '&6VIP Exclusive Feature Area'
Bottom:
type: 'notice'
confirm:
text: '&a[ OK ]'
actions:
- 'tell: &aStarting VIP features'
Notes¶
-
Execution Order
- The
Openevent runs before the menu is parsed - The
Closeevent runs after the menu is closed - Event action lists are executed in order
- The
-
Scope of Return
returnin theOpenevent prevents the entire menu from openingreturnin theCloseevent only interrupts the remaining actionsreturnis effective inside nested condition checks
-
Variable Limitations
- The
Openevent does not support$(input_key)(input fields not yet displayed) - The
Closeevent supports all variable formats - Condition checks support all built-in methods and operators
- The
-
Performance Considerations
- Avoid executing large numbers of time-consuming operations in events
- Use
returnto short-circuit unnecessary logic - Use parentheses to clarify priority for complex condition checks
-
Error Handling
- A failed condition check does not prevent the menu from opening (unless
returnis used) - A failed action does not prevent subsequent actions from executing
- Use the
tellaction to provide feedback messages
- A failed condition check does not prevent the menu from opening (unless
Related Documentation¶
- 🔍 Conditions — Learn the detailed syntax for condition expressions
- 🤖 Actions (Actions) — Learn about all available action types
- 💾 Data Storage — Learn about data storage and variable usage