Config.yml
Main configuration file reference
The config.yml file is the main configuration file for zMenu. It controls global plugin settings, storage and multi-server synchronisation, menus, clicks, security, caches, dialogs and the website integration.
File Location
plugins/zMenu/config.yml
File Structure
The file is split into 10 sections, in this order:
| # | Section | Content |
|---|---|---|
| 1 | General | Features, console messages, update check, default files, MiniMessage |
| 2 | Debug & logs | Debug modes, performance debug, error log cooldown |
| 3 | Storage | Storage type, SQL / MongoDB / Redis settings, saving, migration |
| 4 | Multi-server | Server id, messaging between servers, session handoff |
| 5 | Menus | Main menu, menus to load, close actions, animations, hot reload |
| 6 | Clicks | Click types, double-click, click cooldown, packet click limiter |
| 7 | Security & anti-dupe | Anti-dupe, ghost GUI protection, OP commands |
| 8 | Performance & caches | FastEvent, ItemStack / MiniMessage / PlaceholderAPI / OfflinePlayer caches |
| 9 | Dialogs | Nested dialog lists, dialog canvas resource pack |
| 10 | Website | Download command, live-sync, API URL |
Complete Configuration Reference
This is the default config.yml generated by zMenu:
# ==================================================================================================
# zMenu - Main configuration
# ==================================================================================================
#
# Documentation : https://docs.groupez.dev/zmenu/getting-started
# Online editor : https://minecraft-inventory-builder.com/
#
# Get 23.5% off at MineStrator with: https://cashback.groupez.dev/
#
#
# Sections of this file:
# 1. General
# 2. Debug & logs
# 3. Storage
# 4. Multi-server
# 5. Menus
# 6. Clicks
# 7. Security & anti-dupe
# 8. Performance & caches
# 9. Dialogs
# 10. Website (inventory builder)
#
# ==================================================================================================
# 1. GENERAL
# ==================================================================================================
# Turn off the parts of zMenu you do not use.
# A disabled feature registers nothing (no listener, no command, no default file).
#
# Features are read when the server starts:
# restart the server after changing them, /zm reload does not apply them.
features:
# Custom items of the items folder, their mechanics (itemjoin, on-click),
# the item update on join and /zm giveitem.
custom-items: true
# Show information messages in the console,
# for example when an inventory or a command has been loaded successfully.
enable-information-message: true
# Skip the update check at startup.
skip-update-check: false
# Create the default files (inventories, commands, patterns...) when they don't exist.
generate-default-file: true
# Enable MiniMessage format.
# Enables Dialogs support (Paper 1.21.7+). MiniMessage formatting itself is always enabled.
# More info: https://docs.advntr.dev/minimessage/index.html
enable-mini-message-format: true
# ==================================================================================================
# 2. DEBUG & LOGS
# ==================================================================================================
# Show detailed information in the console.
# If you encounter an issue, enable this option and send the errors to support.
enable-debug: false
# Measure the execution time of the plugin.
# Useful to identify bottlenecks and optimize performance.
enable-debug-time: false
# Measure and log the execution time of each step when an inventory opens
# (button building, item rendering, etc.).
enable-performance-debug: false
performance-debug:
# Minimum execution time (in ms) for an operation to appear in the output.
# Set to 0 to see every operation.
threshold-ms: 10
filter:
# DISABLED - Show all operations above threshold-ms
# WHITELIST - Only show the operations matching the list below
# BLACKLIST - Hide the operations matching the list below
#
# Supports wildcards: "buildButton.*" matches all buildButton operations.
mode: DISABLED
operations: []
# Print a message in the console when files are saved or loaded.
enable-log-storage-file: false
# How long, in seconds, to wait before logging the same failing button again.
#
# When the actions of a button throw an error, zMenu logs it once with the full stack trace,
# then stays quiet about that same button for this long. Without it, a player clicking a broken
# button produced one full stack trace per click, filling the console and the log file and
# slowing the server down.
#
# Set to 0 to log every single occurrence.
click-error-log-cooldown-seconds: 30
# ==================================================================================================
# 3. STORAGE
# ==================================================================================================
# Where zMenu stores its data.
#
# SQLITE - For the first start and for tests only.
# MYSQL - RECOMMENDED
# MARIADB - RECOMMENDED
# POSTGRESQL - Uses database-configuration below (set port to 5432).
# zMenu downloads the driver on the next start.
# MONGODB - Keeps everything in MongoDB (see the mongodb section below).
# zMenu downloads the driver on the next start.
# REDIS - Keeps everything in Redis (see the redis section below).
# Make sure Redis writes its data to disk (appendonly yes in redis.conf),
# or a restart of Redis loses it.
# NONE - No database at all.
#
# We advise you to use MARIADB or MYSQL. SQLITE is only there to install the plugin and run some
# tests: the plugin works, but not all features are available with SQLITE yet.
# This will be fixed in future plugin updates.
storage-type: SQLITE
# --- SQL database (MYSQL, MARIADB, POSTGRESQL) ----------------------------------------------------
database-configuration:
# The prefix applied to every table.
# If several plugins share the same database, each one must have its own prefix.
# It is advisable not to change this value.
table-prefix: "zmenu_"
# IP address of the machine hosting the database.
host: 192.168.10.10
# Port of the database (MySQL / MariaDB: 3306, PostgreSQL: 5432).
port: 3306
# Database credentials.
user: homestead
password: 'secret'
# Name of the database.
database: zmenu
# Enable or not the SQL debug mode.
debug: false
# Maximum lifetime of a pooled MySQL or MariaDB connection, in seconds.
# A connection older than this is retired and replaced. 0 keeps connections until the pool closes.
# Hikari requires at least 30 seconds. 1800 (30 minutes) is also the default when omitted.
max-lifetime: 1800
# Extra driver properties sent with every MySQL, MariaDB or PostgreSQL connection. Examples:
# useSSL: "true" - MySQL / MariaDB over TLS
# allowPublicKeyRetrieval: "true" - MySQL 8 without TLS ("Public Key Retrieval is not allowed")
# sslmode: "disable" - PostgreSQL without TLS, or "require" to force it
properties: {}
# --- MongoDB (storage-type MONGODB) ---------------------------------------------------------------
mongodb:
# mongodb://[user:password@]host:port, or a mongodb+srv:// connection string.
uri: "mongodb://localhost:27017"
database: "zmenu"
# The start of every collection name.
collection-prefix: "zmenu_"
# --- Redis (storage-type REDIS and messaging-type REDIS) ------------------------------------------
# zMenu downloads the Redis client on the next start after you choose one of them.
redis:
# redis://[user:password@]host:port/database, or rediss:// for TLS.
uri: "redis://localhost:6379/0"
# true for a Redis Cluster, uri then names one of its nodes.
cluster: false
# The start of every key zMenu writes. Change it when several networks share one Redis.
key-prefix: "zmenu"
# Refuse to start when Redis does not write its data to disk (appendonly no).
require-aof: false
# --- Saving -----------------------------------------------------------------------------------------
# Time in seconds between two batch saves.
# Instead of running an SQL query for each update, a single query is executed every 10 seconds.
batch-task: 10
# Write the buffered data of a player to the database as soon as they disconnect,
# instead of waiting for the next batch-task cycle.
#
# Buffered data is always written when the server stops, so this only changes how much an outright
# crash can lose: enabled, a crash only loses what arrived since the last disconnect, instead of
# up to a full batch-task interval for every player.
#
# Set to false if the extra write on each quit is too much for your database.
# Several players leaving at the same time are already grouped into a single write.
flush-storage-on-quit: true
# Currently not used: player data is saved through batch-task and flush-storage-on-quit.
seconds-save-player-data: 600
seconds-save-player-inventories: 600
# Save in the database the inventories opened by the players.
enable-player-open-inventory-logs: true
# --- Migration ------------------------------------------------------------------------------------
# To move to another storage-type:
# 1. Copy the data with /zm storage migrate <type>
# 2. Change storage-type
# 3. Restart
#
# When the new type needs a driver zMenu does not have yet (POSTGRESQL, MONGODB, REDIS), set it here and
# restart once before running the command, so zMenu downloads it.
migration-target: ""
# The database /zm storage migrate copies to, when it is not the one of database-configuration,
# for example MariaDB to PostgreSQL. Each value set here replaces the same value of
# database-configuration for the copy only.
#
# After the copy, move these values into database-configuration, change storage-type and restart.
#migration-database-configuration:
# host: 127.0.0.1
# port: 5432
# user: zmenu
# password: 'secret'
# database: zmenu
# ==================================================================================================
# 4. MULTI-SERVER
# Only useful when several servers share the same database.
# ==================================================================================================
# Name of this server, used for the variables of the "server" scope
# (data action with scope: server, %zmenu_server_value_<key>%, /zm variables ... server ...).
#
# Servers sharing one database must each have their own name.
# Leave empty to use a name generated once and kept in plugins/zMenu/server-id.txt.
server-id: ""
# How servers sharing a database tell each other about changes to player and global variables,
# so a value changed on one server is updated on the others.
#
# AUTO - With MySQL, MariaDB, PostgreSQL or MongoDB: through a table (collection) of the
# database, read every messaging-poll-interval seconds.
# With storage-type REDIS: through Redis pub/sub.
# SQLite is never shared, so it does nothing there.
# SQL - Always through the table of the SQL database, read every messaging-poll-interval
# seconds, even on SQLite (several servers on one SQLite file).
# REDIS - Through Redis pub/sub (see the redis section), even with MySQL or MariaDB as storage:
# changes reach the other servers at once.
# NONE - Nothing is sent: a server only sees the changes of the others when it reads them again
# (a player joining it, a restart).
messaging-type: NONE
# Time in seconds between two reads of the database, used by messaging-type AUTO and SQL.
# Decimals are allowed, minimum 0.25.
messaging-poll-interval: 2
# When a player moves from one server to another, the new server waits up to this many
# milliseconds for the old one to save the data of the player before reading it.
# Only used with a shared database.
session-handoff-timeout: 3000
# ==================================================================================================
# 5. MENUS
# ==================================================================================================
# Name of the default menu, opened when no specific one is defined.
main-menu: "example"
# Open the main menu when the player presses the swap offhand key (F).
use-swap-item-off-hand-key-to-open-main-menu: false
# Only open the main menu when the player presses shift + the swap offhand key together.
use-swap-item-off-hand-key-to-open-main-menu-needs-shift: false
# Specific inventories to load at plugin start.
# Add the paths of the menus you want to load manually.
specify-path-menus: [ ]
# Show a message to the player when the command "/zm open <inventory> <player> <display>" is used.
enable-open-message: true
# Action types that are NOT run as close actions when a player switches to another zMenu inventory.
# This prevents actions like "open another inventory" or "go back" from reopening old menus.
skip-close-actions-on-inventory-switch:
- inventory
- inv
- back
# Longest an opening or closing animation may last, in milliseconds.
# A longer one still plays, but is reported in the console and never freezes the menu,
# so a mistyped interval cannot lock a player out of their menu.
max-animation-duration: 10000
# From how many idle-animation buttons a menu drives them all from one shared timer.
#
# Below this : each idle button gets its own task, which keeps every frame exact to the tick.
# At or above : the menu uses a single task per viewer, however many buttons cycle, and frames
# land on the next tick (only noticeable for durations that are not a multiple of 50 ms).
#
# Lower it on a busy server with many idle buttons. 0 always shares, a very large value never does.
shared-idle-timer-threshold: 8
# --- Hot reload -----------------------------------------------------------------------------------
# You must have zMenu+ on your server to use this feature:
# https://minecraft-inventory-builder.com/resources/zmenu.4
#
# zMenu watches the inventories folder (and its subfolders) and automatically:
# - reloads an inventory when its file is modified,
# - loads it when a file is added,
# - unloads it when the file is deleted.
#
# Players viewing a reloaded inventory see the new version reopened on the same page,
# an unloaded inventory is closed.
# A file that cannot be loaded (YAML error, invalid button, etc.) is not applied: the previous
# version stays loaded until the error is fixed.
#
# Files listed in specify-path-menus are not watched.
# The folder is also scanned every 2 seconds, for file systems that do not send change events
# (Docker, WSL, network shares).
# Changes are logged in the console with a [HotReload] prefix, enable-debug shows more details.
hot-reload:
enable: false
# Time in milliseconds to wait after the last change of a file before reloading it.
# Text editors often write a file in several steps, this avoids reloading it several times.
delay-milliseconds: 500
# ==================================================================================================
# 6. CLICKS
# ==================================================================================================
# Only run a button for a click type listed in all-clicks-type below,
# or one that a click-requirement of that button explicitly asks for.
#
# Keep this enabled! When it is off, exotic click types reach the button while every requirement
# scoped to a normal click type is skipped: pressing the drop key (Q), ctrl + Q or a number key
# on a button runs its actions and commands without checking any requirement at all.
#
# Only disable this if enforcing it breaks a menu you cannot change.
enforce-click-types: true
# Click types supported.
# Any click type not listed here is ignored, unless a click-requirement of the button names it
# explicitly. Requires enforce-click-types to be true.
#
# This is also the default list of click types used by a requirement that does not specify one.
all-clicks-type:
- MIDDLE
- RIGHT
- LEFT
- SHIFT_RIGHT
- SHIFT_LEFT
# Ignore double-clicks, so they don't trigger interactions.
disable-double-click-event: true
# --- Click cooldown -------------------------------------------------------------------------------
# Prevent players from spamming clicks too quickly. Useful to reduce abuse or bugs.
enable-cooldown-click: true
# Cooldown duration in milliseconds between two clicks.
# Also acts as a rate limit against automated click macros. Values below ~150 make it realistic
# for a scripted client to fire several purchases before an asynchronous economy has committed
# the first one.
cooldown-click-milliseconds: 250
# --- Packet click limiter (requires PacketEvents) -------------------------------------------------
# Limit all the click packets received from players (only for zMenu inventories).
# Prevents players from sending excessive click packets, reducing packet spam and potential exploits.
#
# STRONGLY RECOMMENDED on public servers: this is the only limit that applies before the click
# reaches the server tick, and it is the layer that stops packet injection clients from bursting
# clicks.
#
# Requires the PacketEvents plugin to be installed, it does nothing without it.
enable-packet-event-click-limiter: false
# Minimum time in milliseconds between two click packets. Lower values are more permissive.
packet-event-click-limiter-milliseconds: 150
# ==================================================================================================
# 7. SECURITY & ANTI-DUPE
# ==================================================================================================
# --- Anti-dupe ------------------------------------------------------------------------------------
# Automatically detect and prevent item duplication exploits.
enable-anti-dupe: true
# Send a message to a Discord webhook when a dupe attempt is detected.
enable-anti-dupe-discord-notification: false
# Discord webhook URL used for the anti-dupe notifications.
anti-dupe-discord-webhook-url: "https://discord.com/api/webhooks/<your discord webhook url>"
# Message sent to Discord when a dupe is detected.
# Placeholders: %player%, %amount%, %itemname%
anti-dupe-message: "**%player%** used %amount% %itemname% from zMenu. It has been removed!"
# --- Ghost GUI protection -------------------------------------------------------------------------
# Close the menu when the player moves away from where it was opened.
#
# Protects against "ghost GUI" abuse: a modified client can hide the inventory screen locally
# without sending a close packet, then keep clicking the still-open container while running,
# fighting or teleporting.
#
# Set to false only if you rely on menus staying open while walking.
close-on-move: true
# Maximum distance (in blocks) a player may move from the opening location before the menu
# is closed. Only used when close-on-move is true.
max-move-distance: 2.0
# Close the menu as soon as the player takes or deals damage.
# Prevents using menus (kits, shops, heals) during combat through a ghost GUI.
close-on-damage: true
# --- Commands -------------------------------------------------------------------------------------
# Send the player commands of the buttons through the chat (as if the player typed them),
# instead of executing them directly. Useful for "fake" commands not registered in Spigot.
enable-player-command-in-chat: false
# Allow buttons to execute player commands with elevated permissions (OP or permission *).
#
# WARNING: This is a security-sensitive feature. Only enable it if you understand the risks.
# Disabled by default for security reasons. Requires a server restart to take effect.
enable-player-commands-as-op-action: false
# Method used to grant the temporary elevated permissions.
# Only used when enable-player-commands-as-op-action is true.
#
# ATTACHMENT - Grants permission * temporarily (safer, recommended)
# SET_OP - Temporarily sets the player as OP (use with caution)
# BOTH - Combines both methods (maximum compatibility, use with extreme caution)
op-grant-method: ATTACHMENT
# ==================================================================================================
# 8. PERFORMANCE & CACHES
# ==================================================================================================
# Enable the FastEvent system.
# Replaces some Bukkit events with a faster alternative: better performance, at the cost of
# API changes. Read the documentation before enabling this.
enable-fast-event: false
# Cache the ItemStacks, to reduce object creation.
enable-cache-item-stack: true
# --- MiniMessage component cache ------------------------------------------------------------------
# Cache used for the parsed MiniMessage components (item names, lore, inventory titles, messages).
#
# This cache used to be unbounded: once a player placeholder was resolved into a name or a lore
# line, every distinct result stayed in memory for the whole uptime, which on a busy server grew
# until the JVM ran out of heap.
component-cache:
# Maximum number of parsed components kept in memory. Set to 0 for no limit (old behaviour).
max-size: 10000
# Drop an entry that has not been used for this many minutes. Set to 0 to never expire
# (old behaviour). This matters more than the size limit, because a component built from a
# player placeholder is usually used once and never again.
expire-minutes: 10
# Keep item names, lore and plain messages in separate cache namespaces.
# Item names and lore are cached with a formatting reset in front of them, plain messages are
# not. So when an item name and a message shared the same text, they also shared one cache entry:
# whichever was parsed first won and the other one rendered wrong, most visibly as an item name
# that appeared italic. Set to false to restore that old, colliding behaviour.
fix-key-collisions: true
# --- PlaceholderAPI cache -------------------------------------------------------------------------
# Cache the PlaceholderAPI values for a short period, to reduce the number of calls to PlaceholderAPI.
enable-cache-placeholder-api: false
# How long a cached placeholder value is kept, in milliseconds (1000 = 1 second).
cache-placeholder-api: 20
# --- Offline players cache ------------------------------------------------------------------------
# Time in seconds before the OfflinePlayer cache is cleaned.
cache-offline-player: 300
# ==================================================================================================
# 9. DIALOGS (Paper 1.21.7+, requires enable-mini-message-format)
# ==================================================================================================
# How many dialog_list dialogs can be nested inside each other (a list inside a list inside a list...).
#
# This does not limit how many dialogs a list contains. A list sends every dialog it contains,
# including the content of nested lists, in the packet that opens it, so deep nesting makes that
# packet bigger and can disconnect the player. Lists nested deeper than this are left out.
dialog-list-max-depth: 4
# --- Dialog canvas --------------------------------------------------------------------------------
# Dialog canvases draw images and text at pixel positions inside dialogs (body type dialog-canvas).
# zMenu generates the fonts they need into plugins/zMenu/resource-pack/output,
# from the dialogs that use them.
dialog-canvas:
resource-pack:
# Who adds the files of zMenu to the resource pack players download:
#
# auto - The pack plugin installed on the server (Nexo, ItemsAdder or CraftEngine).
# With several of them, nothing is done until one is chosen here.
# Without any, standalone when its url is set, else none.
# nexo - Nexo
# itemsadder - ItemsAdder
# craftengine - CraftEngine
# standalone - zMenu sends plugins/zMenu/resource-pack/zmenu-pack.zip from the url below.
# none - You add plugins/zMenu/resource-pack/zmenu-pack.zip (or the output folder)
# to your pack yourself.
target: auto
# Run the rebuild command of the pack plugin (/nexo reload pack, /iazip, /ce reload pack)
# when the files of zMenu changed after /zm reload.
# When false, zMenu only tells you which command to run.
auto-rebuild: false
standalone:
# Where you upload zmenu-pack.zip. zMenu does not host it, and sends it with its SHA-1,
# so upload it again each time zMenu says the pack changed.
url: ""
# Kick players who decline the pack.
required: false
# Shown when the pack is offered (MiniMessage), empty for none.
prompt: "<gray>Interface of the server menus"
# When players see the fallback text of a canvas instead of the canvas:
#
# auto - With the standalone pack: until the player loaded it.
# With Nexo, ItemsAdder, CraftEngine or a pack of server.properties: only after the
# player declined it or it failed, including packs sent while the player joins.
# true - Until a resource pack is reported loaded.
# false - Never.
require-pack: auto
# How long, in seconds, the buttons of an opened canvas keep working.
# Opening the dialog again resets it.
click-lifetime-seconds: 600
# Download the font and textures of the vanilla client from Mojang once per Minecraft version,
# to measure text in the default font and to draw vanilla textures (glyph: minecraft:item/diamond).
#
# zMenu only downloads them once a loaded dialog has a canvas that needs them.
# They are kept in plugins/zMenu/cache/vanilla and are never added to the resource pack
# (except the shader of hide-focus-outline).
download-vanilla-assets: true
# Experimental: a click on a canvas makes the client draw a white outline around the dialog body.
# The client draws it in code, so no texture can change it. This adds the gui shaders of the
# client to the pack, changed to skip white 1 pixel lines exactly as long as the outline of one
# of your canvases. Other white of the client's screens stays.
#
# It replaces the gui shaders of any other pack and needs download-vanilla-assets.
#
# debug paints instead of hiding: red = hidden, green = another white 1 pixel line, blue = other white.
hide-focus-outline: false
# ==================================================================================================
# 10. WEBSITE (inventory builder)
# https://minecraft-inventory-builder.com/
# ==================================================================================================
# Allow the use of the download command of the plugin.
enable-download-command: false
# Reopen the website live-sync link automatically at startup (a few seconds after the plugin
# enables), when this server is already linked to an account.
# Set to false if you prefer to open it by hand with /zmenu website connect after every restart.
enable-website-auto-connect: true
# API URL of the inventory builder.
# Do not change this value, leave the default URL, otherwise the link with the site will not work.
api-url: "https://minecraft-inventory-builder.com/api/v2/"
# Web editor inventories sync.
# Do not enable this, for now it is only for development purposes.
DEV-ONLY-DONT-ENABLE-THIS: falseConfiguration Options Explained
1. General
features
Turns off the parts of zMenu you do not use. A disabled feature registers nothing: no listener, no command and no default file.
features:
custom-items: true| Feature | Description |
|---|---|
custom-items | Custom items of the items/ folder, their mechanics (itemjoin, on-click), the item update on join and /zm giveitem. See Custom Items. |
Features are read when the server starts. Restart the server after changing them: /zm reload does not apply them (a warning is shown in the console).
enable-information-message
Shows informational messages in the console, for example when an inventory or a command has been loaded successfully.
enable-information-message: trueskip-update-check
Skips the automatic update check on startup.
skip-update-check: falsegenerate-default-file
Creates the default files (inventories, commands, patterns...) when they do not exist.
generate-default-file: trueenable-mini-message-format
Enables the Dialogs support (Paper 1.21.7+). MiniMessage formatting itself is always enabled.
enable-mini-message-format: trueYou can use MiniMessage in names, lore, titles and messages:
name: "<gradient:red:blue>Gradient Text</gradient>"
lore:
- "<rainbow>Rainbow!</rainbow>"
- "<bold><gold>Bold gold</gold></bold>"More info: MiniMessage documentation.
2. Debug & logs
enable-debug
Shows detailed debug messages in the console.
enable-debug: falseWhen to enable:
- Troubleshooting inventory loading issues
- Debugging placeholder problems
- Reporting bugs to support (send the errors shown in the console)
enable-debug-time
Measures the execution time of the plugin, to identify bottlenecks.
enable-debug-time: falseenable-performance-debug
Measures and logs the execution time of each step when an inventory opens (button building, item rendering, etc.).
enable-performance-debug: false
performance-debug:
threshold-ms: 10
filter:
mode: DISABLED
operations: []| Option | Description |
|---|---|
threshold-ms | Minimum execution time (in ms) for an operation to appear in the output. 0 shows every operation. |
filter.mode | DISABLED shows all operations above the threshold, WHITELIST only shows the operations of the list, BLACKLIST hides them. |
filter.operations | Operations used by the filter. Supports wildcards: "buildButton.*" matches all buildButton operations. |
enable-log-storage-file
Prints a message in the console when files are saved or loaded.
enable-log-storage-file: falseclick-error-log-cooldown-seconds
How long, in seconds, zMenu waits before logging the same failing button again.
click-error-log-cooldown-seconds: 30When the actions of a button throw an error, zMenu logs it once with the full stack trace, then stays quiet about that same button for this long. Without it, a player clicking a broken button produced one full stack trace per click, filling the console and the log file and slowing the server down.
Set to 0 to log every single occurrence.
3. Storage
storage-type
Where zMenu stores its data (player data, variables, inventory logs).
| Type | Description |
|---|---|
SQLITE | Local file-based database (default). For the first start and for tests only. |
MYSQL | MySQL server. Recommended. |
MARIADB | MariaDB server. Recommended. |
POSTGRESQL | PostgreSQL server, uses database-configuration (set port to 5432). zMenu downloads the driver on the next start. |
MONGODB | Keeps everything in MongoDB, see mongodb. zMenu downloads the driver on the next start. |
REDIS | Keeps everything in Redis, see redis. Make sure Redis writes its data to disk (appendonly yes in redis.conf), or a restart of Redis loses it. |
NONE | No database at all. |
storage-type: SQLITEWe advise you to use MARIADB or MYSQL. SQLITE is only there to install the plugin and run some tests: the plugin works, but not all features are available with SQLite yet.
Recommendations:
- Testing:
SQLITE - Production / network:
MYSQLorMARIADB(orPOSTGRESQL) - No player data needed:
NONE
database-configuration
Connection settings for MYSQL, MARIADB and POSTGRESQL.
database-configuration:
table-prefix: "zmenu_"
host: 192.168.10.10
port: 3306
user: homestead
password: 'secret'
database: zmenu
debug: false
max-lifetime: 1800
properties: {}| Option | Description |
|---|---|
table-prefix | Prefix applied to every table. If several plugins share the same database, each one must have its own prefix. It is advisable not to change it. |
host | IP address of the machine hosting the database |
port | Database port (MySQL / MariaDB: 3306, PostgreSQL: 5432) |
user | Database username |
password | Database password |
database | Name of the database |
debug | Enables the SQL debug mode |
max-lifetime | Maximum lifetime of a pooled MySQL or MariaDB connection, in seconds (default: 1800, i.e. 30 minutes) |
properties | Extra driver properties sent with every MySQL, MariaDB or PostgreSQL connection |
The max-lifetime option controls how long a connection can stay in the HikariCP pool. A connection older than this value is retired and replaced by a new one.
0keeps connections until the pool closes.- A missing or negative value keeps the default of 30 minutes.
- HikariCP requires at least
30seconds.
Lower this value if your database server or a proxy in front of it closes idle connections before 30 minutes (for example a low MySQL wait_timeout).
Common properties:
properties:
useSSL: "true" # MySQL / MariaDB over TLS
allowPublicKeyRetrieval: "true" # MySQL 8 without TLS ("Public Key Retrieval is not allowed")
sslmode: "disable" # PostgreSQL without TLS, or "require" to force itIf a database-configuration.yml file exists in the server's root folder, zMenu reads the database-configuration section from it first (including max-lifetime) and falls back to config.yml for missing keys.
mongodb
Used by storage-type: MONGODB.
mongodb:
uri: "mongodb://localhost:27017"
database: "zmenu"
collection-prefix: "zmenu_"| Option | Description |
|---|---|
uri | mongodb://[user:password@]host:port, or a mongodb+srv:// connection string |
database | Name of the database |
collection-prefix | The start of every collection name |
redis
Used by storage-type: REDIS and messaging-type: REDIS. zMenu downloads the Redis client on the next start after you choose one of them.
redis:
uri: "redis://localhost:6379/0"
cluster: false
key-prefix: "zmenu"
require-aof: false| Option | Description |
|---|---|
uri | redis://[user:password@]host:port/database, or rediss:// for TLS |
cluster | true for a Redis Cluster, uri then names one of its nodes |
key-prefix | The start of every key zMenu writes. Change it when several networks share one Redis. |
require-aof | Refuse to start when Redis does not write its data to disk (appendonly no) |
batch-task
Time in seconds between two batch saves. Instead of running an SQL query for each update, a single query is executed every 10 seconds.
batch-task: 10flush-storage-on-quit
Writes the buffered data of a player to the database as soon as they disconnect, instead of waiting for the next batch-task cycle.
flush-storage-on-quit: trueBuffered data is always written when the server stops, so this only changes how much an outright crash can lose: enabled, a crash only loses what arrived since the last disconnect, instead of up to a full batch-task interval for every player.
Set to false if the extra write on each quit is too much for your database. Several players leaving at the same time are already grouped into a single write.
seconds-save-player-data / seconds-save-player-inventories
seconds-save-player-data: 600
seconds-save-player-inventories: 600These options are currently not used: player data is saved through batch-task and flush-storage-on-quit.
enable-player-open-inventory-logs
Saves in the database the inventories opened by the players.
enable-player-open-inventory-logs: truemigration-target
Used to move your data to another storage-type:
- Copy the data with
/zm storage migrate <type> - Change
storage-type - Restart the server
migration-target: ""When the new type needs a driver zMenu does not have yet (POSTGRESQL, MONGODB, REDIS), set it in migration-target and restart once before running the command, so zMenu downloads it.
migration-database-configuration
The database /zm storage migrate copies to, when it is not the one of database-configuration (for example MariaDB to PostgreSQL). Each value set here replaces the same value of database-configuration for the copy only.
migration-database-configuration:
host: 127.0.0.1
port: 5432
user: zmenu
password: 'secret'
database: zmenuThis section is commented out by default. After the copy, move these values into database-configuration, change storage-type and restart.
4. Multi-server
These options are only useful when several servers share the same database.
server-id
Name of this server, used for the variables of the server scope (data action with scope: server, %zmenu_server_value_<key>%, /zm variables ... server ...).
server-id: ""Servers sharing one database must each have their own name. Leave empty to use a name generated once and kept in plugins/zMenu/server-id.txt.
messaging-type
How servers sharing a database tell each other about changes to player and global variables, so a value changed on one server is updated on the others.
| Type | Description |
|---|---|
AUTO | With MySQL, MariaDB, PostgreSQL or MongoDB: through a table (collection) of the database, read every messaging-poll-interval seconds. With storage-type: REDIS: through Redis pub/sub. SQLite is never shared, so it does nothing there. |
SQL | Always through the table of the SQL database, read every messaging-poll-interval seconds, even on SQLite (several servers on one SQLite file). |
REDIS | Through Redis pub/sub (see redis), even with MySQL or MariaDB as storage: changes reach the other servers at once. |
NONE | Nothing is sent: a server only sees the changes of the others when it reads them again (a player joining it, a restart). |
messaging-type: NONEmessaging-poll-interval
Time in seconds between two reads of the database, used by messaging-type AUTO and SQL. Decimals are allowed, minimum 0.25.
messaging-poll-interval: 2session-handoff-timeout
When a player moves from one server to another, the new server waits up to this many milliseconds for the old one to save the data of the player before reading it. Only used with a shared database.
session-handoff-timeout: 30005. Menus
main-menu
The default inventory, opened by the MAIN_MENU button type and the F key shortcut.
main-menu: "example"This should match an inventory filename (without .yml) in your inventories/ folder.
use-swap-item-off-hand-key-to-open-main-menu
Opens the main menu when the player presses the swap offhand key (F).
use-swap-item-off-hand-key-to-open-main-menu: falseWhen to enable:
- You want easy menu access without commands
- Your server has a main hub menu
When to keep disabled:
- Players need the F key for actual item swapping
- You use custom resource packs with F key bindings
use-swap-item-off-hand-key-to-open-main-menu-needs-shift
When combined with use-swap-item-off-hand-key-to-open-main-menu: true, the player must also hold Shift to open the menu.
use-swap-item-off-hand-key-to-open-main-menu-needs-shift: falsespecify-path-menus
Specific inventories to load at plugin start. Add the paths of the menus you want to load manually.
specify-path-menus: []enable-open-message
When enabled, using /zm open <inventory> <player> <display> shows a message to the target player.
enable-open-message: trueskip-close-actions-on-inventory-switch
Action types that are not run as close actions when a player switches to another zMenu inventory. Prevents actions like inventory or back from reopening old menus.
skip-close-actions-on-inventory-switch:
- inventory
- inv
- backmax-animation-duration
Longest an opening or closing animation may last, in milliseconds.
max-animation-duration: 10000A longer animation still plays, but is reported in the console and never freezes the menu, so a mistyped interval cannot lock a player out of their menu.
shared-idle-timer-threshold
From how many idle-animation buttons a menu drives them all from one shared timer.
shared-idle-timer-threshold: 8- Below this value: each idle button gets its own task, which keeps every frame exact to the tick.
- At or above: the menu uses a single task per viewer, however many buttons cycle, and frames land on the next tick (only noticeable for durations that are not a multiple of 50 ms).
Lower it on a busy server with many idle buttons. 0 always shares, a very large value never does.
hot-reload
The hot reload has its own page with every detail: Hot Reload. You must have zMenu+ on your server to use this feature.
Watches the inventories/ folder (and all its subfolders) and applies your changes without any command:
- Modified file: the inventory is reloaded.
- New file: the inventory is loaded.
- Deleted file (or deleted folder): the inventory is unloaded.
hot-reload:
enable: false
delay-milliseconds: 500| Option | Description |
|---|---|
enable | Enables the hot reload. Disabled by default. |
delay-milliseconds | Time to wait after the last change of a file before reloading it. Text editors often save a file in several steps, this avoids reloading it several times. |
Good to know:
- Players viewing an inventory when it is reloaded see the new version open instantly, on the same page and with the same previous inventories (a back button opens the new version too). If the inventory is unloaded (file deleted,
enable: false), it is closed. - A file that cannot be loaded (YAML syntax error, unknown button type, invalid size...) is not applied: the previous version stays loaded and the error is shown in the console until you fix the file.
- Only the
inventories/folder is watched. Files listed inspecify-path-menus, patterns and commands still require/zm reload. - Enabling or disabling the option takes effect after
/zm reloador/zm reload config(or within two seconds when changed from the in-game configuration dialog). - On top of the file system events, the folder is scanned every two seconds. Changes are therefore detected even where the file system sends no event: Docker containers (Pterodactyl, bind mounts), WSL, network shares, files uploaded over SFTP.
- A file is reloaded when its content or its modification date changes. Saving a file again without any change still reloads it, but the same version is never reloaded twice.
Console logs:
Every action is logged in the console with a [HotReload] prefix:
[zMenu] [HotReload] Inventory hot reload enabled, watching .../plugins/zMenu/inventories (native recursive watch, 12 file(s), 12 loaded inventory(ies), scan every 2000ms, delay 500ms).
[zMenu] [HotReload] Change detected on example.yml, reloading the inventory...
[zMenu] [HotReload] Inventory example.yml reloaded in 14ms, reopened for 1 player(s).You will also see the YAML errors, the files that could not be loaded, the inventories unloaded after a deletion, and the files that are disabled (enable: false) or waiting for a load requirement. With enable-debug set to true, each file event, each change found by the scan and each ignored (unchanged) file is logged as well.
Troubleshooting: if nothing happens when you save a file, first check that the Inventory hot reload enabled line appears at startup or after /zm reload. Then enable enable-debug to see whether the changes are detected.
When to enable:
- While creating or editing menus, to see your changes instantly
- On a test/development server
6. Clicks
enforce-click-types
Only runs a button for a click type listed in all-clicks-type, or one that a click-requirement of that button explicitly asks for.
enforce-click-types: trueKeep this enabled
When it is off, exotic click types reach the button while every requirement scoped to a normal click type is skipped: pressing the drop key (Q), ctrl + Q or a number key on a button runs its actions and commands without checking any requirement at all. Only disable this if enforcing it breaks a menu you cannot change.
all-clicks-type
Click types supported by zMenu menus. Any click type not listed here is ignored, unless a click-requirement of the button names it explicitly. Requires enforce-click-types: true.
all-clicks-type:
- MIDDLE
- RIGHT
- LEFT
- SHIFT_RIGHT
- SHIFT_LEFTThis is also the default list of click types used by a requirement that does not specify one.
disable-double-click-event
Ignores double-clicks, so they don't trigger interactions.
disable-double-click-event: trueenable-cooldown-click / cooldown-click-milliseconds
Prevents players from spamming clicks too quickly, with a cooldown between two clicks.
enable-cooldown-click: true
cooldown-click-milliseconds: 250The cooldown also acts as a rate limit against automated click macros. Values below ~150 make it realistic for a scripted client to fire several purchases before an asynchronous economy has committed the first one.
Adjust based on your needs:
- Lower = more responsive, risk of accidental double-clicks and macros
- Higher = safer, might feel sluggish
enable-packet-event-click-limiter / packet-event-click-limiter-milliseconds
Limits all the click packets received from players (only for zMenu inventories). Requires the PacketEvents plugin, it does nothing without it.
enable-packet-event-click-limiter: false
packet-event-click-limiter-milliseconds: 150packet-event-click-limiter-milliseconds is the minimum time between two click packets. Lower values are more permissive.
Strongly recommended on public servers: this is the only limit that applies before the click reaches the server tick, and it is the layer that stops packet injection clients from bursting clicks.
7. Security & anti-dupe
enable-anti-dupe
Automatically detects and prevents item duplication exploits involving inventory GUIs.
enable-anti-dupe: trueenable-anti-dupe-discord-notification
Sends a message to a Discord webhook when a duplication attempt is detected.
enable-anti-dupe-discord-notification: false
anti-dupe-discord-webhook-url: "https://discord.com/api/webhooks/<your discord webhook url>"
anti-dupe-message: "**%player%** used %amount% %itemname% from zMenu. It has been removed!"| Option | Description |
|---|---|
anti-dupe-discord-webhook-url | Discord webhook URL used for the notifications |
anti-dupe-message | Message sent to Discord. Placeholders: %player%, %amount%, %itemname% |
close-on-move / max-move-distance
Closes the menu when the player moves away from where it was opened.
close-on-move: true
max-move-distance: 2.0Protects against "ghost GUI" abuse: a modified client can hide the inventory screen locally without sending a close packet, then keep clicking the still-open container while running, fighting or teleporting.
max-move-distance is the maximum distance (in blocks) a player may move from the opening location before the menu is closed. Set close-on-move to false only if you rely on menus staying open while walking.
close-on-damage
Closes the menu as soon as the player takes or deals damage. Prevents using menus (kits, shops, heals) during combat through a ghost GUI.
close-on-damage: trueenable-player-command-in-chat
Sends the player commands of the buttons through the chat (as if the player typed them), instead of executing them directly. Useful for "fake" commands not registered in Paper/Spigot.
enable-player-command-in-chat: falseenable-player-commands-as-op-action
Allows buttons to execute player commands with elevated permissions (OP or permission *). Requires a server restart to take effect.
enable-player-commands-as-op-action: falseSecurity Warning
Only enable this if you fully understand the security implications. Misuse can give players elevated permissions.
op-grant-method
The method used to grant the temporary elevated permissions (only when enable-player-commands-as-op-action: true).
| Method | Description |
|---|---|
ATTACHMENT | Grants * permission temporarily (safer, recommended) |
SET_OP | Temporarily sets the player as OP (use with caution) |
BOTH | Combines both methods (maximum compatibility, use with extreme caution) |
op-grant-method: ATTACHMENT8. Performance & caches
enable-fast-event
Replaces some Bukkit events with a faster alternative: better performance, at the cost of API changes. It changes the events seen by plugins using the zMenu API, so check your addons before enabling this.
enable-fast-event: falseenable-cache-item-stack
Caches the ItemStacks to reduce object creation.
enable-cache-item-stack: trueRecommendation: keep enabled unless you experience issues.
component-cache
Cache used for the parsed MiniMessage components (item names, lore, inventory titles, messages).
component-cache:
max-size: 10000
expire-minutes: 10
fix-key-collisions: true| Option | Description |
|---|---|
max-size | Maximum number of parsed components kept in memory. 0 for no limit (old behaviour). |
expire-minutes | Drop an entry that has not been used for this many minutes. 0 to never expire (old behaviour). This matters more than the size limit, because a component built from a player placeholder is usually used once and never again. |
fix-key-collisions | Keep item names, lore and plain messages in separate cache namespaces. Set to false to restore the old, colliding behaviour. |
This cache used to be unbounded: once a player placeholder was resolved into a name or a lore line, every distinct result stayed in memory for the whole uptime, which on a busy server grew until the JVM ran out of heap.
About fix-key-collisions: item names and lore are cached with a formatting reset in front of them, plain messages are not. When an item name and a message shared the same text, they also shared one cache entry: whichever was parsed first won and the other one rendered wrong, most visibly as an item name that appeared italic.
enable-cache-placeholder-api / cache-placeholder-api
Caches the PlaceholderAPI values for a short period, to reduce the number of calls to PlaceholderAPI.
enable-cache-placeholder-api: false
cache-placeholder-api: 20cache-placeholder-api is how long a cached value is kept, in milliseconds (1000 = 1 second).
The cache is bounded to 10,000 entries (one per placeholder and player), and each entry expires once the cache-placeholder-api duration has passed, so it no longer grows over time.
Enabling this means placeholders won't update instantly. Use with caution.
cache-offline-player
Time in seconds before the OfflinePlayer cache is cleaned.
cache-offline-player: 300 # 5 minutes9. Dialogs
These options concern the Dialogs (Paper 1.21.7+, requires enable-mini-message-format).
dialog-list-max-depth
How many dialog_list dialogs can be nested inside each other (a list inside a list inside a list...). Default: 4.
dialog-list-max-depth: 4This does not limit how many dialogs a list contains. A list sends every dialog it contains, including the content of nested lists, in the packet that opens it, so deep nesting makes that packet bigger and can disconnect the player. Lists nested deeper than this value are left out.
dialog-canvas
Dialog canvases draw images and text at pixel positions inside dialogs (body type dialog-canvas). zMenu generates the fonts they need into plugins/zMenu/resource-pack/output, from the dialogs that use them.
dialog-canvas:
resource-pack:
target: auto
auto-rebuild: false
standalone:
url: ""
required: false
prompt: "<gray>Interface of the server menus"
require-pack: auto
click-lifetime-seconds: 600
download-vanilla-assets: true
hide-focus-outline: falseresource-pack.target
Who adds the files of zMenu to the resource pack players download.
| Value | Description |
|---|---|
auto | The pack plugin installed on the server (Nexo, ItemsAdder or CraftEngine). With several of them, nothing is done until one is chosen here. Without any, standalone when its url is set, else none. |
nexo | Nexo |
itemsadder | ItemsAdder |
craftengine | CraftEngine |
standalone | zMenu sends plugins/zMenu/resource-pack/zmenu-pack.zip from standalone.url. |
none | You add plugins/zMenu/resource-pack/zmenu-pack.zip (or the output folder) to your pack yourself. |
resource-pack.auto-rebuild
Runs the rebuild command of the pack plugin (/nexo reload pack, /iazip, /ce reload pack) when the files of zMenu changed after /zm reload. When false, zMenu only tells you which command to run.
resource-pack.standalone
| Option | Description |
|---|---|
url | Where you upload zmenu-pack.zip. zMenu does not host it, and sends it with its SHA-1, so upload it again each time zMenu says the pack changed. |
required | Kick players who decline the pack. |
prompt | Shown when the pack is offered (MiniMessage), empty for none. |
require-pack
When players see the fallback text of a canvas instead of the canvas.
| Value | Description |
|---|---|
auto | With the standalone pack: until the player loaded it. With Nexo, ItemsAdder, CraftEngine or a pack of server.properties: only after the player declined it or it failed, including packs sent while the player joins. |
true | Until a resource pack is reported loaded. |
false | Never. |
click-lifetime-seconds
How long, in seconds, the buttons of an opened canvas keep working. Opening the dialog again resets it.
download-vanilla-assets
Downloads the font and textures of the vanilla client from Mojang once per Minecraft version, to measure text in the default font and to draw vanilla textures (glyph: minecraft:item/diamond).
zMenu only downloads them once a loaded dialog has a canvas that needs them. They are kept in plugins/zMenu/cache/vanilla and are never added to the resource pack (except the shader of hide-focus-outline).
hide-focus-outline
Experimental
It replaces the gui shaders of any other pack and needs download-vanilla-assets.
A click on a canvas makes the client draw a white outline around the dialog body. The client draws it in code, so no texture can change it. This option adds the gui shaders of the client to the pack, changed to skip white 1 pixel lines exactly as long as the outline of one of your canvases. Other white of the client's screens stays.
The debug value paints instead of hiding: red = hidden, green = another white 1 pixel line, blue = other white.
10. Website
Settings of the Minecraft Inventory Builder integration.
enable-download-command
Enables the /zm website download <url> [force] command to download inventories from a URL.
enable-download-command: falseThe command only runs when this option is set to true. With the default value false, the command is refused, the sender is told to enable it in config.yml, and the attempt is logged in the console.
enable-website-auto-connect
Reopens the website live-sync link automatically at startup (a few seconds after the plugin enables), when this server is already linked to an account.
enable-website-auto-connect: trueSet to false if you prefer to open it by hand with /zmenu website connect after every restart.
api-url
The API URL of the inventory builder. Do not change this value, otherwise the link with the site will not work.
api-url: "https://minecraft-inventory-builder.com/api/v2/"DEV-ONLY-DONT-ENABLE-THIS
Web editor inventories sync. Do not enable this, it is only for development purposes for now.
DEV-ONLY-DONT-ENABLE-THIS: falseExample Configurations
Basic Server (SQLite)
enable-debug: false
storage-type: SQLITE
enable-mini-message-format: true
enable-cache-item-stack: true
enable-anti-dupe: true
enable-cooldown-click: true
cooldown-click-milliseconds: 250
main-menu: "main"Network Server (MySQL)
enable-debug: false
storage-type: MYSQL
database-configuration:
table-prefix: "zmenu_"
host: "mysql.mynetwork.com"
port: 3306
user: "zmenu_user"
password: "secure_password_here"
database: "minecraft_network"
server-id: "lobby-1"
messaging-type: AUTO
enable-mini-message-format: true
enable-cache-item-stack: true
enable-cache-placeholder-api: true
cache-placeholder-api: 1000
enable-anti-dupe: true
main-menu: "hub_menu"Public Server (security-focused)
enforce-click-types: true
enable-cooldown-click: true
cooldown-click-milliseconds: 250
enable-packet-event-click-limiter: true # requires PacketEvents
packet-event-click-limiter-milliseconds: 150
enable-anti-dupe: true
close-on-move: true
close-on-damage: true
enable-player-commands-as-op-action: falsePerformance-Focused
enable-debug: false
enable-cache-item-stack: true
enable-cache-placeholder-api: true
cache-placeholder-api: 3000
cache-offline-player: 600
component-cache:
max-size: 10000
expire-minutes: 10
shared-idle-timer-threshold: 4Development/Testing
enable-debug: true
enable-debug-time: true
enable-performance-debug: true
performance-debug:
threshold-ms: 5
filter:
mode: DISABLED
operations: []
skip-update-check: true
hot-reload:
enable: true
storage-type: SQLITE
enable-cache-item-stack: false
enable-cache-placeholder-api: false
enable-cooldown-click: false
click-error-log-cooldown-seconds: 0Reloading Configuration
After making changes:
/zm reload configOr reload everything:
/zm reloadSome changes require a server restart to take effect: the storage and database settings, features and enable-player-commands-as-op-action.
Best Practices
- Start with defaults: only change what you need
- Use MySQL or MariaDB in production: SQLite is for tests, and a shared database allows data sharing across servers
- Give each server its own
server-idwhen several servers share one database - Keep anti-dupe and
enforce-click-typesenabled: protects your economy - Enable the packet click limiter on public servers (requires PacketEvents)
- Use debug mode when setting up, disable it in production
Troubleshooting
Database Connection Failed
- Verify credentials are correct
- Check database server is running
- Ensure the database exists
- Check firewall allows connections
- Verify user has proper permissions
- For MySQL 8 without TLS, add
allowPublicKeyRetrieval: "true"todatabase-configuration.properties
Variables Not Synchronised Between Servers
- Check that every server uses the same database and has its own
server-id - Check that
messaging-typeis notNONE - With
REDIS, check theredissection on every server
Placeholders Not Updating
- Disable placeholder caching temporarily
- Check if PlaceholderAPI is installed
- Verify the expansion is downloaded
Performance Issues
- Enable item stack caching
- Enable placeholder caching
- Use
enable-performance-debugto find the slow operations - Check for inventory loops (A opens B opens A)
Next Steps
- Set up Custom Commands
- Configure Player Data storage
- Learn about the Development API