Skip to content

Repository files navigation

version license MC Java Folia

Kotlin TabooLib Paper PAPI Vault

✨ Features  •  📦 Download  •  📥 Installation  •  📋 Commands  •  🚀 Quick Start  •  📁 Files  •  🌍 i18n  •  ⚙️ GUI  •  ⚡ Actions  •  ⌨️ Smart Mechanisms  •  ⌨️ Custom Commands  •  🎣 Catchers  •  🧩 API  •  📡 PAPI  •  🔨 Build



📖 中文文档请见 README_zh.md


✨ Features

🧱 Layout System — Define GUI layout with character art, intuitive and flexible
👥 Dynamic Player List — Online / offline player heads with pagination
Action System — 20+ action types: commands, messages, sounds, economy, cross-server
🔌 PlaceholderAPI — Full PAPI support in titles, item names, and lore
🎒 Third-party Items — ItemsAdder, Oraxen, CraftEngine custom items
⌨️ Custom Commands — Register commands to open GUIs via commands.yml

🔍 Smart Detection — PAPI expansion dependency check, placeholder scanning, config typo hints
💰 Vault Economy — Give, take, set, and check balances
💬 Chat Catcher — Click items to capture chat input for multi-step interactions
🍃 Folia Compatible — Works with both Paper and Folia
🌍 Multi-language — 10 languages: 中文, English, 日本語, 한국어, Français, Deutsch, Español, Português, Русский, 繁體中文


📦 Get JAR

You may obtain the JAR through non-paid methods, but please do not redistribute without permission, and do not obtain this resource through unauthorized channels.
Choose one of the following methods to obtain the plugin JAR:

📦 Expand

📦 Methods

Method Description
🧧 Paid Download the pre-built JAR directly
🔨 Free Clone the source and build yourself

💰 Paid Channel

Spend ¥1 RMB to get the latest pre-built JAR file:

Ifdian Link

🔗 https://www.ifdian.net/item/c88c27ca43e111f1915752540025c377

🔨 Free Method

Build from source:

GitHub Repository

🔗 https://github.com/XyLuoDYS/XPListGUI

💡 Requires Java 8+, Gradle, and an internet connection to download dependencies.


📥 Installation

📋 Expand

Dependencies

Plugin Required Description
TabooLib Core framework, bundled in releases
PlaceholderAPI 💡 Recommended Placeholder resolution
Vault ⚪ Optional Economy operations
ItemsAdder / Oraxen / CraftEngine ⚪ Optional Custom item materials

🎈 You can download and install this plugin directly without any dependencies.

Installation Steps

1. Place XPListGUI.jar in the plugins/ folder
2. Restart the server. If Plugman is installed, try /plugman load XPListGUI

Hot-reloading has risks. It is recommended to restart the server to load the plugin.


📋 Commands & Permissions

📋 Expand
Command Description Permission
/xplistgui help Display help xplistgui.admin.help
/xplistgui list List all GUIs (with hover details) xplistgui.admin.list
/xplistgui create <name> Create a new GUI from template xplistgui.admin.create
/xplistgui delete <name> Delete a GUI (with confirmation) xplistgui.admin.delete
/xplistgui open <name> [-s] Open a GUI xplistgui.admin.open
/xplistgui reload Reload all configs and commands xplistgui.admin.reload
/xplistgui papiinstall <exp> Install a PAPI expansion xplistgui.admin.papiinstall

💡 Aliases: /xplgui /plgui /xplg /xplistg /plistg

🔑 Master permission xplistgui.admin grants all sub-nodes. Each GUI's permission field controls access — leave empty for public.

The open command has two usages:

# When GUI config has errors, debug info will be displayed
/xplistgui open example
# When GUI config has errors, debug info will NOT be displayed
/xplistgui open example -s

🚀 Quick Start

📦 Expand to view steps
# 1. Create your first GUI
/xplistgui create example

# 2. Open the GUI
/xplistgui open example

Edit the GUI config file at: plugins/XPListGUI/lists/example.yml

💡 Tips
If the GUI config has errors, using /xplistgui open <GUI name> will display detailed debug info in chat for easy troubleshooting.
Add -s after /xplistgui open <GUI name> to skip smart detection (no debug info displayed).
For details, see Smart Mechanisms and Commands & Permissions.


📁 File Reference

Once the plugin loads, the plugins/XPListGUI/ directory contains the following files:

📁 Expand file reference

config.yml — Plugin Configuration

language: "zh_CN"          # Plugin display language (10 supported)
debug: false               # Console debug log toggle
debug-fake-players: 30     # Fake players for pagination testing (0 to disable)
catcher-timeout: 60000     # Chat catcher timeout in milliseconds

Changes take effect after /xplistgui reload — no restart needed.

lang/*.yml — Language Files

Stores all plugin messages in 10 languages. Auto-generated on first load. Edit any message freely and /xplistgui reload to apply.

zh_CN.yml zh_TW.yml en_US.yml ja_JP.yml ko_KR.yml fr_FR.yml de_DE.yml es_ES.yml pt_BR.yml ru_RU.yml

Falls back to Message.yml when the target language file does not exist.

lists/*.yml — GUI Configuration Files

Each GUI corresponds to a .yml file. Generate from template via /xplistgui create.

See GUI Configuration below.

commands.yml — Custom Commands

Map custom commands to GUIs. See Custom Commands.


🌍 Multi-language

Set the language in config.yml:

language: "zh_CN"  # Choose from 10 supported languages below

Language files are located in the plugins/XPListGUI/lang/ directory. All messages are configurable.

🌍 Supported Languages
Code Language
zh_CN 简体中文 (Simplified Chinese)
zh_TW 繁體中文 (Traditional Chinese)
en_US English
ja_JP 日本語 (Japanese)
ko_KR 한국어 (Korean)
fr_FR Français (French)
de_DE Deutsch (German)
es_ES Español (Spanish)
pt_BR Português (Portuguese)
ru_RU Русский (Russian)

⚙️ GUI Configuration

Each GUI is a .yml file under the lists/ directory. Create one with /xplistgui create <name> from the template.

📋 Field Reference
Field Type Description
title String GUI title, supports & color codes and PAPI placeholders
size Number GUI size, must be a multiple of 9 (9/18/27/36/45/54)
permission String Permission required to open this GUI, empty = public
open-actions List Actions executed when GUI is opened (sound, message, etc.)
show-online-players Bool Show online player heads
show-offline-players Bool Show offline player heads
show-self Bool Include the viewer in the player list
head-blacklist List Player names to exclude (case-sensitive)
player-slot-char Char Player head placeholder, Layout mode only
page-button-prev Char Previous page button char, Layout mode only
page-button-next Char Next page button char, Layout mode only
layout List Character grid layout, Layout mode only
items Map/List Item definitions: character keys (Layout) or slot list (Static)
catchers Map Chat catcher definitions, see Catchers
🧱 Layout Mode (Recommended)
Define item positions with a character grid — each char maps to a key in `items`:
player-slot-char: "P"
page-button-prev: "<"
page-button-next: ">"

layout:
  - "#########"
  - "#PPPPPPP#"
  - "#PPPPPPP#"
  - "###<#>###"

items:
  '#':                          # Border
    enabled:
      material: BLACK_STAINED_GLASS_PANE
      name: " "
  'P':                          # Player head
    player-head: true
    name: '{player}'
    lore:
      - "&7Click to view"
    actions:
      - 'tell: &aYou clicked &e{player}'
  '<':                          # Page button
    enabled:
      material: ARROW
      name: "&ePrevious"
    disabled:
      material: BARRIER
      name: "&cFirst page reached"

Setting material to "HEAD:<player-name>" displays the head of the specified player (supports online search for premium accounts).

{player} is auto-replaced with the head owner's name, only valid when player-head: true.

Page buttons require both enabled (usable) and disabled (boundary) materials. Key names must be exact (enabled/disabled, not enable/disable).

📍 Static Slot Mode

Without layout, use slot numbers directly:

items:
  - slot: 22
    material: DIAMOND
    name: "&bWelcome"
    amount: 1
    lore:
      - "&7Click to open shop"
    actions:
      - 'tell: &aHello!'
      - 'open: shop'
🎒 Third-party Item Materials

The material field can directly call ItemsAdder / Oraxen / CraftEngine custom items:

material: "itemsadder:namespace:item_id"   # ItemsAdder
material: "oraxen:item_id"                 # Oraxen
material: "craftengine:namespace:item_id"  # CraftEngine

⚡ Action System

Actions are behaviors triggered when clicking an item, executed top-to-bottom in order. Format: type:content.

📋 Action Table
Category Action Format Example
Command console console:<cmd> console:give {player} diamond 1
Command player / p player:<cmd> player:spawn
Command op op:<cmd> op:gamemode creative {player}
Message tell / msg tell:<msg> tell:&aHello {viewer}
Message tell-<player> tell-<player>:<msg> tell-{player}:&eSomeone viewed you
Message title title:<main>,<sub>,<fadeIn>,<stay>,<fadeOut> title:&6Congrats!,&eReward received,10,60,20
Message actionbar / ab actionbar:<msg> actionbar:&aBalance: 1000 coins
Sound sound / play sound:<sound> sound:ENTITY_PLAYER_LEVELUP
Flow delay / wait delay:<ticks> delay:60
Flow return return Stop all subsequent actions immediately
Flow close close Close the current GUI
Navigation open open:<GUI> open:shop
Navigation connect / server connect:<server> connect:lobby
Variable set set:<key>=<value> set:target={player}
Economy give-money give-money:<amount> give-money:100
Economy give-money-<player> give-money-<player>:<amount> give-money-{player}:100
Economy take-money take-money:<amount> take-money:50
Economy take-money-<player> take-money-<player>:<amount> take-money-{player}:100
Economy eco-set eco-set:<amount> eco-set:1000
Economy eco-set-<player> eco-set-<player>:<amount> eco-set-{player}:0
Economy eco-balance eco-balance Check current balance
Economy eco-balance-<player> eco-balance-<player> eco-balance-{player}
Capture catch catch:<catcher> catch:transfer-amount
🔄 Available Variables

Variables that can be embedded in action content:

Variable Description
{viewer} Name of the player who triggered the action
{player} Name of the clicked head's owner (same as {viewer} in regular GUIs)
{target} Same as {player}
{online} Current server online player count
{meta:key} Temporary variable value stored via set, can be passed across menus

📖 Full action reference: docs/actions-reference.md

🎯 Conditional Actions

Use condition for "only execute if", with unlimited nesting:

📋 Expand for example
actions:
  - 'tell: &bNormal action'
  - condition: 'perm *vip.use'
    actions:
      - 'tell: &aYou are VIP!'
      - condition: 'perm *admin.use'
        actions:
          - 'tell: &6Super admin'
        deny:
          - 'tell: &cNot an admin'
    deny:
      - 'tell: &cVIP required'
Syntax Meaning
perm *node Has permission → execute actions
!perm *node Lacks permission → execute actions
(empty) Always true (else fallback)

Condition met → actions. Not met → deny. deny is optional, skips if omitted.

🖱️ Left/Right Click Separation

📋 Expand for example
actions:
  left:
    - 'tell: &bLeft click'
  right:
    all:
      - 'tell: &eRight click'
      - 'open: detail-menu'

Without left/right, both clicks trigger. Fully backward compatible. All actions under left execute simultaneously. right supports all (right + shift-right) and shift (shift-right only) groups.


🔍 Smart Mechanisms

Mechanism 1: GUI PAPI Placeholder Detection

🧠 Expand
Blocking Type

Add the depend-expansions field in the GUI config, for example:

depend-expansions:
  - Vault
  - Player

If the Vault and Player PAPI expansions are not installed, the GUI cannot be opened.

Hint Type
Category Detection Logic Report Behavior
① Known PAPI Expansion Prefix matching against mapping table (20+) Hints missing expansion + provides [Install] button
② PAPI Built-in Expansion Matches built-in expansions like statistic Hints "no install needed, bundled with PAPI" but still fails to resolve
③ Registered but Unresolved Prefix exists in currently registered PAPI placeholders on the server Hints "registered but unresolved", may be a custom placeholder from another plugin, manual check recommended
④ Unrecognized Source Not in known mapping table, not registered in PAPI Hints "unrecognized", suggests checking spelling
⑤ PAPI Not Installed Hints to install PlaceholderAPI plugin

Mechanism 2: GUI Configuration Validation

🔍 Expand

When there are errors in the GUI config, using the open command without the -s flag will automatically detect and prompt error messages.

Category Check Level
Basic Fields GUI title is empty ⚠ Warning
Layout Validation Character used in layout but not defined in items ⚠ Warning
Character defined in items but not used in layout 💡 Hint
Layout exceeds 6 rows (max 54 slots) ⚠ Warning
A row exceeds 9 slots ⚠ Warning
Layout is entirely empty ⚠ Warning
Pagination Only prev page without next page (or vice versa) ⚠ Warning
Page button char configured but not defined in items ⚠ Warning
enable typo (should be enabled) ⚠ Warning
disable typo (should be disabled) ⚠ Warning
Has enabled sub-block but missing disabled sub-block ⚠ Warning
Has disabled sub-block but missing enabled sub-block ⚠ Warning
Missing both enabled and disabled sub-blocks ⚠ Warning
Page button char does not appear in layout ⚠ Warning
Prev and next page use the same character ⚠ Warning
Player Heads Both online and offline players are not displayed ⚠ Warning
Head char configured but not defined in items ⚠ Warning
Missing player-head flag ⚠ Warning
Head char does not appear in layout ⚠ Warning
Head char conflicts with page button char ⚠ Warning
Item Material enable/disable general typo ⚠ Warning
Item type is not a valid material name ⚠ Warning
Material in enabled/disabled sub-block is invalid ⚠ Warning
Permission Check No-permission message set but no permission node configured 💡 Hint
Action Check Target GUI file referenced by open action does not exist ⚠ Warning

Mechanism 3: Server Event Auto-refresh

🔔 Expand
  • When a player joins or leaves the server, all online players who have this plugin's GUI open will automatically refresh

While a player has the GUI open and another player joins or leaves, the player heads in the GUI will update accordingly.

  • When refreshing, the current page is preserved, open-actions (sounds/messages) are not triggered, and no detection hints pop up — only a silent re-render

If a player leaves the server while another player is in a catcher input state, the catcher operation is immediately cancelled.

  • When players join/leave frequently, multiple refresh requests within 500ms are merged into one to avoid performance waste

Mechanism 4: Head Skin Loading

⏳ Expand

Head skin loading uses a three-tier strategy:

Tier 1

Read from Online Player Directly

  • If the target player is currently on the server, read their character profile directly from the server internals to get skin texture data
  • Advantage: if the player changed their skin via SkinsRestorer, the latest skin is retrieved without additional queries
  • For cross-version compatibility, multiple read paths are prepared internally — trying the standard method first, then indirect methods, and even multiple possible field names
Tier 2

SkinsRestorer Local Query

  • If the player is offline but the server has SkinsRestorer installed, query SkinsRestorer's local storage
  • For compatibility with different SkinsRestorer versions (15.x, 14.x, older), three sets of API interfaces are attempted — whichever works is used
Tier 3

Mojang Official API Async Fetch

  • If the first two tiers fail (e.g., premium player on an offline server), fall back to the Mojang official API:
       1. Look up UUID by player name
       2. Look up skin data by UUID
  • This process requires network requests and may take hundreds of milliseconds to two seconds, so it runs fully async without blocking the main thread. The GUI displays a placeholder head first, and the skin is swapped in once retrieved
⚡ Cache Mechanism
  • All retrieved skins are cached, storing up to 500 entries with a 30-minute expiry. Uses an LRU (Least Recently Used) eviction policy — when the limit is exceeded, the least recently used cache entries are automatically cleared
  • This means the same player appearing repeatedly in the list doesn't require repeated queries — instant retrieval

⌨️ Custom Commands

Register custom commands in plugins/XPListGUI/commands.yml to open GUIs directly — players type your command and the corresponding menu opens instantly.

📋 Field Reference
Field Type Description
name String Required, command name (without /)
aliases List Command aliases, register multiple shortcuts
permission String Permission node required, empty = public
permission-message String Message shown when lacking permission, supports & color codes
gui String Required, GUI name (matches a file in lists/, without .yml)
subcommands Map Sub-commands for multi-level menus under one command
📋 Basic Example
commands:
  menu:
    name: "menu"
    aliases: ["cd", "gui"]
    gui: "example"          # /menu opens the example GUI

  vip:
    name: "vip"
    permission: "xplistgui.vip"
    permission-message: "&cVIP only"
    gui: "vip_menu"         # /vip opens the vip_menu GUI
📋 Subcommands (Multi-level Menus)

Use subcommands to extend one command into multiple child entries:

commands:
  servermenu:
    name: "server"
    aliases: ["sm"]
    gui: "server_main"      # /server → main menu
    subcommands:
      shop:                  # /server shop → shop GUI
        gui: "shop"
      pvp:                   # /server pvp → pvp GUI
        permission: "server.pvp"
        gui: "pvp"

💡 GUIs opened via custom commands automatically skip smart detection hints — no -s needed.


🎣 Catchers

Use catch:<catcher-name> in actions to close the GUI and wait for the player to type in chat — enabling multi-step "click → type → execute" workflows.

📋 How It Works
1. Player clicks item → triggers catch:xxx action
2. GUI closes → start phase executes (prompts the player)
3. Player types in chat → end phase triggers
4. Player types cancel keyword → cancel phase triggers
5. Timeout expires → auto-cancels to prevent getting stuck

The typed value is read via the {meta:input} variable and can be used in all subsequent actions.

📋 Configuration Example

Define the catcher (in the GUI config's catchers section):

catchers:
  transfer-amount:
    timeout: 60000           # Timeout in ms, default 60000 = 1 min
    start:                   # Executed when entering capture mode
      - 'close'
      - 'tell: &eEnter transfer amount (&7type C to cancel&e)'
    cancel:                  # Executed when player cancels
      - 'tell: &cCancelled'
    end:                     # Executed after player inputs
      condition: "input == C"   # Condition: input "C" → actions, else → deny
      actions:
        - 'tell: &cCancelled'
      deny:
        - 'tell: &aYou entered: {meta:input}'

Trigger in item actions:

actions:
  - 'catch:transfer-amount'
📋 Field Reference
Field Description
timeout Timeout in ms, auto-cancels when expired, default 60000
start Action list executed when entering catch mode (usually close + tell prompt)
cancel Action list executed when player inputs the cancel keyword
end Action executed after player input, supports condition branching
{meta:input} The text the player typed, available in end.deny

Use "input == xxx" in end.condition to check if the typed text matches the cancel keyword.


🧩 Developer API

Kotlin
import org.example.xplistgui.api.XPApi

XPApi.openGUI(player, "shop")
XPApi.openGUISilent(player, "vip_menu")
XPApi.openGUIPage(player, "players", 3)
val guis: List<String> = XPApi.getGuiList()
Java
import org.example.xplistgui.api.XPApi;

XPApi.INSTANCE.openGUI(player, "shop");
XPApi.INSTANCE.openGUISilent(player, "vip_menu");

📡 PAPI Placeholders

📋 Expand for placeholder list
Placeholder Description Example Output
%xplistgui_gui_count% Number of registered GUIs 5
%xplistgui_gui_list% GUI name list example, shop
%xplistgui_has_gui_<name>% Whether a GUI exists true
%xplistgui_online_count% Server online player count 12
%xplistgui_head_count_<name>% Total head count in a GUI 28

🔨 Build

📦 Expand for build commands
# Release version
./gradlew build
# Output: build/libs/XPListGUI-1.2.jar

# Development version
./gradlew taboolibBuildApi -PDeleteCode

License

This project is open-sourced under the CC BY-NC-ND 4.0 license. See LICENSE for details.


GitHub

Made with ❤️ by XyLuoDys

About

用GUI展示玩家列表,自定义在GUI中与玩家的互动事件

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages