00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

GUI con Inventari

Introduzione alle GUI

Le GUI (Graphical User Interfaces) in Spigot/Paper si basano sugli inventari di Minecraft. Puoi creare menu interattivi, shop, configurazioni e molto altro usando inventari custom con item cliccabili.

Creare una GUI Semplice

```java public class SimpleGUI { private final Inventory inventory;

public SimpleGUI() {
    // Crea un inventario con 27 slot (3 righe)
    inventory = Bukkit.createInventory(null, 27, "§6Menu Principale");
    
    // Aggiungi item
    initializeItems();
}

private void initializeItems() {
    // Item di esempio
    ItemStack infoItem = new ItemStack(Material.BOOK);
    ItemMeta infoMeta = infoItem.getItemMeta();
    infoMeta.setDisplayName("§aInformazioni");
    infoMeta.setLore(Arrays.asList(
        "§7Clicca per vedere le info",
        "§7del server!"
    ));
    infoItem.setItemMeta(infoMeta);
    
    ItemStack closeItem = new ItemStack(Material.BARRIER);
    ItemMeta closeMeta = closeItem.getItemMeta();
    closeMeta.setDisplayName("§cChiudi");
    closeItem.setItemMeta(closeMeta);
    
    // Posiziona gli item
    inventory.setItem(13, infoItem); // Centro
    inventory.setItem(26, closeItem); // Angolo in basso a destra
}

public void open(Player player) {
    player.openInventory(inventory);
}

} ```

Gestire i Click

```java public class GUIListener implements Listener {

@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
    // Controlla se è la nostra GUI
    if (!event.getView().getTitle().equals("§6Menu Principale")) {
        return;
    }
    
    // Impedisci di spostare item
    event.setCancelled(true);
    
    Player player = (Player) event.getWhoClicked();
    ItemStack clickedItem = event.getCurrentItem();
    
    // Controlla se l'item è null
    if (clickedItem == null || clickedItem.getType() == Material.AIR) {
        return;
    }
    
    // Gestisci i click in base all'item
    if (clickedItem.getType() == Material.BOOK) {
        player.sendMessage("§aServer creato da TuoNome!");
        player.sendMessage("§aGiocatori online: " + Bukkit.getOnlinePlayers().size());
    } else if (clickedItem.getType() == Material.BARRIER) {
        player.closeInventory();
    }
}

} ```

GUI con Pagine

```java public class PagedGUI { private final Player player; private int page = 0; private final List items;

public PagedGUI(Player player, List<ItemStack> items) {
    this.player = player;
    this.items = items;
}

public void open() {
    Inventory inventory = Bukkit.createInventory(null, 54, "§6Shop - Pagina " + (page + 1));
    
    // Item per pagina (45 slot, lasciando 9 per navigazione)
    int startIndex = page * 45;
    int endIndex = Math.min(startIndex + 45, items.size());
    
    for (int i = startIndex; i < endIndex; i++) {
        inventory.setItem(i - startIndex, items.get(i));
    }
    
    // Bottoni di navigazione
    if (page > 0) {
        ItemStack previousPage = new ItemStack(Material.ARROW);
        ItemMeta meta = previousPage.getItemMeta();
        meta.setDisplayName("§aPagina Precedente");
        previousPage.setItemMeta(meta);
        inventory.setItem(48, previousPage);
    }
    
    if (endIndex < items.size()) {
        ItemStack nextPage = new ItemStack(Material.ARROW);
        ItemMeta meta = nextPage.getItemMeta();
        meta.setDisplayName("§aPagina Successiva");
        nextPage.setItemMeta(meta);
        inventory.setItem(50, nextPage);
    }
    
    // Chiudi
    ItemStack close = new ItemStack(Material.BARRIER);
    ItemMeta closeMeta = close.getItemMeta();
    closeMeta.setDisplayName("§cChiudi");
    close.setItemMeta(closeMeta);
    inventory.setItem(49, close);
    
    player.openInventory(inventory);
}

public void nextPage() {
    if ((page + 1) * 45 < items.size()) {
        page++;
        open();
    }
}

public void previousPage() {
    if (page > 0) {
        page--;
        open();
    }
}

} ```

GUI Manager Pattern

Per gestire multiple GUI in modo organizzato:

```java public class GUIManager { private final Map<UUID, GUI> activeGUIs = new HashMap<>();

public void openGUI(Player player, GUI gui) {
    activeGUIs.put(player.getUniqueId(), gui);
    gui.open(player);
}

public GUI getActiveGUI(Player player) {
    return activeGUIs.get(player.getUniqueId());
}

public void closeGUI(Player player) {
    activeGUIs.remove(player.getUniqueId());
}

}

public interface GUI { void open(Player player); void handleClick(InventoryClickEvent event); } ```

Implementazione GUI

```java public class ShopGUI implements GUI { private final Inventory inventory;

public ShopGUI() {
    inventory = Bukkit.createInventory(null, 27, "§6Shop");
    setupItems();
}

private void setupItems() {
    // Sword - 100 coins
    ItemStack sword = new ItemStack(Material.DIAMOND_SWORD);
    ItemMeta swordMeta = sword.getItemMeta();
    swordMeta.setDisplayName("§bSpada di Diamante");
    swordMeta.setLore(Arrays.asList("§7Prezzo: §e100 coins"));
    sword.setItemMeta(swordMeta);
    inventory.setItem(11, sword);
    
    // Armor - 200 coins
    ItemStack armor = new ItemStack(Material.DIAMOND_CHESTPLATE);
    ItemMeta armorMeta = armor.getItemMeta();
    armorMeta.setDisplayName("§bArmatura di Diamante");
    armorMeta.setLore(Arrays.asList("§7Prezzo: §e200 coins"));
    armor.setItemMeta(armorMeta);
    inventory.setItem(13, armor);
}

@Override
public void open(Player player) {
    player.openInventory(inventory);
}

@Override
public void handleClick(InventoryClickEvent event) {
    event.setCancelled(true);
    
    Player player = (Player) event.getWhoClicked();
    ItemStack clicked = event.getCurrentItem();
    
    if (clicked == null) return;
    
    if (clicked.getType() == Material.DIAMOND_SWORD) {
        // Logica acquisto spada
        if (hasCoins(player, 100)) {
            removeCoins(player, 100);
            player.getInventory().addItem(new ItemStack(Material.DIAMOND_SWORD));
            player.sendMessage("§aHai acquistato una spada!");
            player.closeInventory();
        } else {
            player.sendMessage("§cNon hai abbastanza coins!");
        }
    }
    // ... altri item
}

private boolean hasCoins(Player player, int amount) {
    // Implementa la logica per controllare i coins
    return true; // Placeholder
}

private void removeCoins(Player player, int amount) {
    // Implementa la logica per rimuovere coins
}

} ```

Listener Universale

```java public class UniversalGUIListener implements Listener { private final GUIManager guiManager;

public UniversalGUIListener(GUIManager guiManager) {
    this.guiManager = guiManager;
}

@EventHandler
public void onClick(InventoryClickEvent event) {
    Player player = (Player) event.getWhoClicked();
    GUI gui = guiManager.getActiveGUI(player);
    
    if (gui != null) {
        gui.handleClick(event);
    }
}

@EventHandler
public void onClose(InventoryCloseEvent event) {
    Player player = (Player) event.getPlayer();
    guiManager.closeGUI(player);
}

} ```

GUI con Input

Permettere al giocatore di inserire item:

```java public class TradeGUI implements GUI { private final Inventory inventory;

public TradeGUI() {
    inventory = Bukkit.createInventory(null, 27, "§6Scambia Item");
    setupBorders();
}

private void setupBorders() {
    ItemStack border = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
    ItemMeta meta = border.getItemMeta();
    meta.setDisplayName(" ");
    border.setItemMeta(meta);
    
    // Riempie i bordi
    for (int i = 0; i < 27; i++) {
        if (i < 9 || i >= 18 || i % 9 == 0 || i % 9 == 8) {
            inventory.setItem(i, border);
        }
    }
    
    // Bottone conferma
    ItemStack confirm = new ItemStack(Material.EMERALD);
    ItemMeta confirmMeta = confirm.getItemMeta();
    confirmMeta.setDisplayName("§aConferma");
    confirm.setItemMeta(confirmMeta);
    inventory.setItem(22, confirm);
}

@Override
public void open(Player player) {
    player.openInventory(inventory);
}

@Override
public void handleClick(InventoryClickEvent event) {
    int slot = event.getRawSlot();
    
    // Permetti di modificare solo slot 10-16 (area centrale)
    if (slot >= 10 && slot <= 16 && slot != 13) {
        // Permetti l'interazione
        return;
    }
    
    // Blocca altri slot
    event.setCancelled(true);
    
    if (slot == 22) { // Conferma
        Player player = (Player) event.getWhoClicked();
        processTradeItems(player);
        player.closeInventory();
    }
}

private void processTradeItems(Player player) {
    List<ItemStack> items = new ArrayList<>();
    
    for (int i = 10; i <= 16; i++) {
        if (i == 13) continue;
        ItemStack item = inventory.getItem(i);
        if (item != null && item.getType() != Material.AIR) {
            items.add(item);
        }
    }
    
    // Processa gli item (es. converti in coins)
    int totalValue = items.size() * 10; // Esempio semplificato
    player.sendMessage("§aHai scambiato " + items.size() + " item per " + totalValue + " coins!");
}

} ```

Best Practices

  • Cancella sempre i click: Usa event.setCancelled(true) per impedire modifiche indesiderate
  • Controlla null: Gli item possono essere null, controlla sempre prima di usarli
  • Usa titoli unici: Identifica le GUI tramite titoli univoci o usa un GUIManager
  • Chiudi al logout: Rimuovi le GUI attive quando un giocatore si disconnette
  • Ottimizza le texture: Usa GRAY_STAINED_GLASS_PANE per bordi/decorazioni

Errori Comuni

Non cancellare l’evento

// SBAGLIATO: permette di spostare item
@EventHandler
public void onClick(InventoryClickEvent event) {
    // ... logica ...
}

// CORRETTO
@EventHandler
public void onClick(InventoryClickEvent event) {
    event.setCancelled(true);
    // ... logica ...
}

Non controllare null

// SBAGLIATO
ItemStack item = event.getCurrentItem();
if (item.getType() == Material.DIAMOND) { } // NullPointerException!

// CORRETTO
ItemStack item = event.getCurrentItem();
if (item != null && item.getType() == Material.DIAMOND) { }

Identificare GUI solo per titolo

// PROBLEMATICO: più GUI con lo stesso titolo
if (event.getView().getTitle().equals("Menu")) { }

// MEGLIO: usa un GUIManager
GUI gui = guiManager.getActiveGUI(player);
if (gui instanceof ShopGUI) { }

Conclusione

Le GUI basate su inventari sono uno strumento potente per creare interfacce intuitive in Spigot/Paper. Con un buon design e gestione degli eventi, puoi creare shop, menu di configurazione, sistemi di trading e molto altro.