Cài đặt
Tải jar, thả vào plugins/, khởi động lại server — xong. Phần dưới giải thích chi tiết từng bước và toàn bộ file cấu hình được sinh ra.
Yêu cầu hệ thống#2>
| Thành phần | Yêu cầu |
|---|---|
| Server | Paper (khuyến nghị) — 1.21.11+. Có hỗ trợ Folia. |
| Java | Java 21+ (theo yêu cầu của Paper 1.21+). |
| Kết nối mạng | Khuyến nghị có internet: TabooLib runtime được nạp khi khởi động lần đầu. |
| Khuyến nghị thêm | PlaceholderAPI — gần như mọi menu đều dùng biến PAPI. |
Không dùng hot-reload. ShinnUI không hỗ trợ mọi hình thức reload nóng:
PlugMan (hoặc plugin tương tự), /reload confirm của Bukkit… đều có thể gây lỗi không lường trước.
Luôn khởi động lại server.
Các bước cài đặt#2>
- Tải file
ShinnUI-1.0-beta.jar từ trang GitHub Releases (hoặc tự build bằng gradlew :plugin:build -x test).
- Đặt jar vào thư mục
plugins/.
- Khởi động lại server (không dùng
/reload).
- Chạy
/shinnui list để kiểm tra các menu demo đã nạp thành công.
- Thử mở menu:
/shinnui open Example.
Cấu trúc thư mục sau khi cài#2>
plugins/ShinnUI/
├── settings.yml # Cấu hình chính của plugin
├── lang/
│ └── vi_VN.yml # Ngôn ngữ plugin (bundle tiếng Việt)
├── menus/ # Thư mục menu mặc định — mọi file .yml ở đây (kể cả con) được tự nạp
│ ├── Example.yml
│ ├── Input-Demo.yml
│ ├── Book-Demo.yml
│ └── ... # Menu con theo thư mục cũng được nạp
└── data/
├── globalData.yml # Dữ liệu global (set-global-data) — đừng sửa khi server đang chạy
└── database # SQLite (hoặc MySQL theo settings.yml)
Tên file (không tính đuôi .yml) chính là ID của menu, dùng trong
/shinnui open <ID> và action open:. Hai file trùng ID vẫn nạp được nhưng
lệnh mở menu sẽ chỉ tìm thấy một.
settings.yml — giải thích từng mục#2>
ShinnUI-1.0-beta.jar từ trang GitHub Releases (hoặc tự build bằng gradlew :plugin:build -x test).plugins/./reload)./shinnui list để kiểm tra các menu demo đã nạp thành công./shinnui open Example.plugins/ShinnUI/
├── settings.yml # Cấu hình chính của plugin
├── lang/
│ └── vi_VN.yml # Ngôn ngữ plugin (bundle tiếng Việt)
├── menus/ # Thư mục menu mặc định — mọi file .yml ở đây (kể cả con) được tự nạp
│ ├── Example.yml
│ ├── Input-Demo.yml
│ ├── Book-Demo.yml
│ └── ... # Menu con theo thư mục cũng được nạp
└── data/
├── globalData.yml # Dữ liệu global (set-global-data) — đừng sửa khi server đang chạy
└── database # SQLite (hoặc MySQL theo settings.yml)
Tên file (không tính đuôi .yml) chính là ID của menu, dùng trong
/shinnui open <ID> và action open:. Hai file trùng ID vẫn nạp được nhưng
lệnh mở menu sẽ chỉ tìm thấy một.
settings.yml — giải thích từng mục#2>
Đây là file cấu hình chính. Nội dung dưới đây khớp 1:1 với source của ShinnUI:
Options#3>
Options:
Running-Performance: Normal # HIGH / NORMAL / LOW — số thread pool = CPUs / mức
Multi-Thread: true # Bật đa luồng cho các tác vụ nội bộ
Async-Load-Menus: true # Nạp menu async khi khởi động
Load-Menu-Concurrent: false # Nạp menu song song (có thể làm multi-level capturer sai thứ tự)
Static-Inventory: # Dùng inventory thật thay vì packet (Java/Bedrock)
Java: false
Bedrock: false
Packet-Inventory:
Create-Id: false
Click-Limit: 40 # Trần click/giây mỗi người chơi trên mọi menu (chặn spam packet). 0 = tắt
Proxy: AUTO # BUNGEE / VELOCITY / AUTO — kênh proxy để action `server:`
Bedrock-Open-Delay: 20 # Trễ mở menu cho người chơi Bedrock (ticks)
Placeholders:
JavaScript-Parse: false # Cho phép %shinnui_js_...% trong PAPI expansion
Jexl-Parse: false # Cho phép %shinnui_jexl_...%
| Key | Ý nghĩa |
|---|---|
Running-Performance | Điều chỉnh số thread: HIGH = CPUs, NORMAL = CPUs/2, LOW = CPUs/3. |
Click-Limit | Áp cho mọi đường click, kể cả menu Input — chặn client hack spam click packet làm ngập buffer. Mặc định 40 click/s. |
Static-Inventory | Bật nếu dùng mod/client tương thích kém với packet inventory (Java) hoặc cho người chơi Bedrock (Geyser). |
Database#3>
Database:
Index:
Player: USERNAME # UUID hoặc USERNAME
SQL:
enable: false # true = MySQL, false = SQLite
host: localhost
port: 3306
user: root
password: ''
database: minecraft
prefix: shinnui # prefix bảng: shinnui_data, shinnui_global_data
Join-Load-Delay: 40 # Trễ nạp dữ liệu sau khi join (ticks)
Global-Data-Sync: 200 # Chu kỳ sync GlobalData giữa các server (ticks)
Database.SQL.enable quyết định backend: false → SQLite local,
true → MySQL. Bảng được tạo với prefix cấu hình được (mặc định shinnui).
Loader — thư mục menu#3>
Loader:
Listen-Files: true # Theo dõi file, nạp lại menu khi file thay đổi
Menu-Files:
- 'plugins/CustomMenusFolder' # Thêm bất kỳ thư mục nào bạn muốn
Menu — tùy chỉnh icon#3>
Menu:
Settings:
Bound-Item-Interval: 2000 # Chống spam khi click item được bind menu (ms)
Icon:
Inherit: false # Mặc định sub-icon có kế thừa main icon không
Item:
Default-Name-Color: "&7" # Màu mặc định khi name không khai báo màu
Default-Lore-Color: "&7"
Pre-Color: false # true = tô màu TRƯỚC khi parse function variable
Head-Connect-Timeout: 500
Head-Read-Timeout: 2500
Book:
Token-Expire-Seconds: 60 # Render-Type BOOK — thời gian sống của click-token (one-shot, gắn UUID)
Hand-Restore-Seconds: 30 # Fallback hoàn trả tay trái khi không nhận được tín hiệu đóng sách
Effect-Packs#3>
# Gói hiệu ứng đặt tên, dùng qua action `effect:`
Effect-Packs:
shop-buy:
sound: 'ENTITY_PLAYER_LEVELUP-1-1'
particle: 'HAPPY_VILLAGER; 10 0.3 0.3 0.3 0.01'
Database.SQL.enable quyết định backend: false → SQLite local,
true → MySQL. Bảng được tạo với prefix cấu hình được (mặc định shinnui).
Loader:
Listen-Files: true # Theo dõi file, nạp lại menu khi file thay đổi
Menu-Files:
- 'plugins/CustomMenusFolder' # Thêm bất kỳ thư mục nào bạn muốn
Menu — tùy chỉnh icon#3>
Menu:
Settings:
Bound-Item-Interval: 2000 # Chống spam khi click item được bind menu (ms)
Icon:
Inherit: false # Mặc định sub-icon có kế thừa main icon không
Item:
Default-Name-Color: "&7" # Màu mặc định khi name không khai báo màu
Default-Lore-Color: "&7"
Pre-Color: false # true = tô màu TRƯỚC khi parse function variable
Head-Connect-Timeout: 500
Head-Read-Timeout: 2500
Book:
Token-Expire-Seconds: 60 # Render-Type BOOK — thời gian sống của click-token (one-shot, gắn UUID)
Hand-Restore-Seconds: 30 # Fallback hoàn trả tay trái khi không nhận được tín hiệu đóng sách
Effect-Packs#3>
# Gói hiệu ứng đặt tên, dùng qua action `effect:`
Effect-Packs:
shop-buy:
sound: 'ENTITY_PLAYER_LEVELUP-1-1'
particle: 'HAPPY_VILLAGER; 10 0.3 0.3 0.3 0.01'
# Gói hiệu ứng đặt tên, dùng qua action `effect:`
Effect-Packs:
shop-buy:
sound: 'ENTITY_PLAYER_LEVELUP-1-1'
particle: 'HAPPY_VILLAGER; 10 0.3 0.3 0.3 0.01'
Chi tiết ở trang Action (mục Effect).
Action & Inputer#3>
Action:
Using-Component: true # Gửi tin nhắn dạng component (đủ màu hex, click event)
Title-Using-Component: true
Inputer:
Cancel-Words: # Từ khóa hủy catcher (regex)
- 'cancel|quit|end'
- 'q'
Shortcuts#3>
Shortcuts:
Offhand: [ ] # Phím F
Sneaking-Offhand: # Shift + F
- condition: 'perm *shinnui.shortcut'
execute: 'open: Example'
deny: 'return'
Right-Click-Player: 'open: Profile' # Click phải vào người chơi khác
Sneaking-Right-Click-Player: [ ]
PlayerInventory-Border-Left: [ ] # Click biên inventory trong GUI
PlayerInventory-Border-Right: [ ]
PlayerInventory-Border-Middle: [ ]
Shortcuts:
Offhand: [ ] # Phím F
Sneaking-Offhand: # Shift + F
- condition: 'perm *shinnui.shortcut'
execute: 'open: Example'
deny: 'return'
Right-Click-Player: 'open: Profile' # Click phải vào người chơi khác
Sneaking-Right-Click-Player: [ ]
PlayerInventory-Border-Left: [ ] # Click biên inventory trong GUI
PlayerInventory-Border-Right: [ ]
PlayerInventory-Border-Middle: [ ]
Các shortcut là reaction — cho phép mở menu nhanh theo thao tác người chơi.
RegisterCommands#3>
RegisterCommands:
openMenus:
aliases: [ ]
permission: null
execute:
- 'tell: &7Argument `example` Required!'
arguments:
example: 'open: example'
Đăng ký lệnh Bukkit thật — chi tiết ở trang Lệnh & Quyền.
Scripts#3>
Scripts:
Export-Hook-Plugin: true # Export plugin hook cho script (ItemsAdder, MMOItems... gọi được từ JS)
Enable-GraalJS: false # true = dùng GraalJS (cần plugin GraalJS), mặc định Nashorn
Binding-Map: {} # Map biến/bind tùy chỉnh cho JS
Nếu máy chủ đã có plugin khác nạp Nashorn/Kotlin stdlib của riêng nó,
cân nhắc bật Enable-GraalJS để tránh xung đột classpath.
Nếu máy chủ đã có plugin khác nạp Nashorn/Kotlin stdlib của riêng nó,
cân nhắc bật Enable-GraalJS để tránh xung đột classpath.