ShinnUI wiki
Trang chủ/Fork/Input Menu

Input Menu — kéo vật phẩm vào GUI

Tính năng đặc trưng của ShinnUI: người chơi shift-click kéo vật phẩm từ inventory của mình vào GUI, menu "góp" chúng vào các slot khai báo sẵn, và chỉ trừ đồ thật khi bạn chạy action input (commit).

🧺 Buffer-pure 🎯 required per slot 🔁 Overflow & withdraw 🔎 Item Matcher filter

Model "buffer thuần": đồ trong inventory thật không bao giờ bị trừ khi nạp vào — đóng menu = mất gì đâu. Trừ đồ chỉ xảy ra đúng một lần, đồng bộ, tại action input.

Cách hoạt động (luồng người chơi)#2>
  1. Shift-click vật phẩm trong inventory dưới (kể cả hotbar) → đồ được "nạp" vào slot Input trong GUI chấp nhận nó. GUI hiển thị số đã nạp và mục tiêu dạng {current}/{goal} trong lore của slot.
  2. Shift-click tiếp vào cùng loại đồ → gộp tiếp, tới khi slot đầy (max-amount).
  3. Overflow: nếu slot đang nhận đã đầy mà còn slot khác cùng nhận, số dư tự tràn sang slot tiếp theo.
  4. Withdraw: shift-click vào một slot Input đang có buffer → rút toàn bộ buffer của slot đó (đồ "quay về" — thực ra chưa bao giờ rời inventory thật, chỉ là bỏ hiển thị buffer).
  5. Click nút Confirm → chạy action input → trừ đúng số lượng khỏi inventory thật → grant phần thưởng theo logic menu của bạn.

Vì buffer chỉ là hiển thị (không di chuyển đồ thật), người chơi không thể dup: một stack thật chỉ được buffer đúng một lần (plugin theo dõi sourceRemainder từng slot gốc), và lúc commit plugin quét lại inventory thật theo matcher/isSimilar để trừ — số trừ là số thật có trên người, không phải con số client báo.

Khai báo slot Input#2>

Node Input: cấp menu, mỗi phần tử là một slot:

Input:
  - slot: 10            # Slot tĩnh (0-53) trong GUI — bắt buộc
    material: IRON_INGOT # (tùy chọn) chỉ nhận material này
    required: 4          # (tùy chọn) phải đủ 4 mới được commit; 0 = tùy chọn
    max-amount: 8        # (tùy chọn, mặc định 64) buffer tối đa
    # --- hoặc lọc bằng matcher thay cho material:
    # matcher: 'enchant:sharpness ; !lore:rusty'
    # --- hoặc item của Nexo:
    # nexo-id: ruby
KeyBắt buộcÝ nghĩa
slotVị trí slot trong cửa sổ chest (0–53). Có thể dùng cú pháp slot tĩnh của TrMenu (range '10-14'…) — mỗi slot sinh một InputSlot riêng.
materialChỉ nhận đúng Material vanilla. Không đặt material/matcher/nexo-id → nhận mọi đồ.
matcherItem Matcher đầy đủ — conjunctive (mọi trait phải đúng). Ưu tiên dùng khi cần lọc enchant/PDC/NBT.
nexo-idChỉ nhận Nexo item theo id. Nếu Nexo không cài → slot không nhận gì.
requiredSố lượng bắt buộc trước khi commit được phép. Commit sẽ trừ đúng required, phần dư buffer (và dư trong inventory) giữ nguyên.
max-amountTrần buffer của slot. required <= max-amount.

Khi khai báo nhiều filter (ví dụ cả materialmatcher), item phải thỏa tất cả. Slot display (placeholder) trong layout nên set Hide-Player-Inventory: false để người chơi thấy và kéo được đồ từ inventory dưới.

Action input — commit#2>
'D':
  display:
    material: Lime Dye
    name: '&a&lConfirm'
  actions:
    all:
      # input là EVAL action: chạy ĐỒNG BỘ ngay khi gặp, trước condition phía sau
      - 'input'
      - 'condition: js: funInt("meta:input_taken") >= 10'
        actions:
          - 'msg: &aĐã đủ nguyên liệu! Chế tạo thành công.'
          - 'sound: ENTITY_PLAYER_LEVELUP-1-1'
          - 'give-item: material:DIAMOND_PICKAXE'
          - 'close'
        deny:
          - 'msg: &cChưa đủ đồ. Thiếu: ${formatMissing}'
          - 'close'

Hành vi của action input (alias input-take):

  • Yêu cầu quyền shinnui.use — không có quyền thì không trừ gì cả.
  • Gate: nếu bất kỳ slot có required > 0 chưa đủ số → không trừ gì, buffer giữ nguyên, set input_taken = 0input_missing (chuỗi dạng "IRON_INGOT x4, GOLD_INGOT x1"), rồi không dừng chuỗi action — để condition/deny phía sau tự hiển thị phản hồi.
  • Commit thành công: trừ đúng required mỗi slot (slot không required thì trừ toàn bộ buffer). Nếu inventory thật không còn đủ số, phần thiếu được re-buffer lại slot đó (safe-commit) — ý định của người chơi không bị âm thầm mất đi.
  • Set meta input_taken = tổng số thực trừ được — dùng con số này để grant thưởng (đúng theo thực tế, không theo buffer client).
  • ActionEval nên nó chạy ngay lập tức trong danh sách action — việc này bảo đảm condition phía sau đọc được giá trị input_taken mới (action thường bị hoãn chạy cuối chuỗi).
  • Nếu gọi từ thread async, action tự chuyển sang main thread (menu/bukkit bắt buộc main thread).

Meta & placeholder của Input#2>
Meta / PlaceholderGiá trị
%shinnui_meta_input% / {meta:input}Tổng số đồ đang buffer (mọi slot).
%shinnui_meta_input_<slot>%Số đồ buffer trong slot cụ thể — %shinnui_meta_input_10%.
%shinnui_meta_input_count%Số slot Input đang có đồ.
%shinnui_meta_input_taken%Số đồ thực trừ ở lần commit gần nhất.
%shinnui_meta_input_missing%Danh sách thiếu dạng ITEM xN sau commit fail — màu hóa từng món qua JS helper (xem Functions).
# Lore động hiển thị tiến độ trên chính slot Input / nút Confirm
lore:
  - '&7Buffered: &b&l%shinnui_meta_input_10%&7 / &f4'
  - '&7Total: &b&l%shinnui_meta_input%'
  - '&7Taken: &a&l%shinnui_meta_input_taken%'

Mục tiêu hiển thị {current}/{goal} trên slot buffer: goal là required nếu slot khai báo, ngược lại là max-amount. Icon trong layout hiển thị số bằng %shinnui_meta_input_<slot>% được tự refresh ngay sau mỗi lần deposit/commit.

Ví dụ hoàn chỉnh — công thức craft#2>

File menus/Input-Demo.yml kèm plugin là ví dụ mẫu: 4 sắt + 4 vàng + 2 kim cương. Tóm tắt cấu trúc:

Title: 'an Input Demo'
Options:
  Hide-Player-Inventory: false    # BẮT BUỘC false để kéo được đồ
Bindings:
  Commands: [ '(?i)input(-)?(demo)?' ]
Input:
  - { slot: 10, material: IRON_INGOT, required: 4, max-amount: 8 }
  - { slot: 12, material: GOLD_INGOT, required: 4, max-amount: 8 }
  - { slot: 14, material: DIAMOND,    required: 2, max-amount: 4 }
Icons:
  'A':   # placeholder slot 10 — lore hiển thị %shinnui_meta_input_10% / 4
    ...
  'D':   # nút Confirm — actions: [input, condition..., deny: msg+close]
    ...
  'X':   # nút Close — actions: 'close' (buffer tự drop, không mất gì)

Lọc nâng cao bằng matcher#2>

File Input-Matcher-Demo.yml demo slot không giới hạn material mà lọc theo đặc trưng:

Input:
  - slot: 10
    material: DIAMOND_SWORD
    matcher: 'enchant:sharpness ; !lore:rusty'   # có Sharpness, KHÔNG có lore "rusty"
    required: 1
  - slot: 12
    matcher: 'pdc:trmenu:quest:done'             # item có tag PDC = "done"
    required: 1
  - slot: 14
    matcher: 'nbt:custom:rarity:legendary'       # NBT custom.rarity = legendary (cần NBTAPI)
    required: 1
  - slot: 16
    nexo-id: ruby                                # Nexo item "ruby"
    required: 1

Chi tiết cú pháp matcher ở trang Item Matcher.

FAQ#2>
Người chơi đóng menu giữa chừng thì sao?

Buffer bị drop, không trừ gì. Đó chính là ưu điểm buffer-pure: đóng = hủy an toàn. Chỉ action input mới trừ đồ.

Đổi trang layout có mất buffer không?

Không — buffer được "vẽ lại" vào slot tương ứng khi đổi trang/refresh (những slot Input không thuộc layout mới thì buffer vẫn nằm trong session).

Tại sao nút Confirm của tôi luôn báo thiếu đồ?

Nếu bạn dùng condition ngay sau input, hãy chắc chắn dùng cú pháp reaction (condition nằm trong element riêng, ví dụ - 'input' rồi - condition: ...; actions: ...; deny: ...). Vì input là eval action chạy sync, input_taken luôn mới; nhưng nếu bạn đọc meta trước khi chạy input thì chắc chắn là giá trị cũ.

Chặn spam click?

Mọi click (kể cả deposit Input) đi qua Options.Click-Limit trong settings.yml (mặc định 40 click/s) và Min-Click-Delay của menu — client hack spam packet sẽ bị chặn.