diff --git a/README.md b/README.md index bd77d6c..a84056c 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,75 @@ -[![Arch Linux](https://img.shields.io/badge/Arch_Linux-1793D1?style=for-the-badge&logo=arch-linux&logoColor=white)](https://archlinux.org) +# Backpack Infinita - 🧳 **Backpack Infinita** +Plugin para Minecraft que adiciona uma mochila infinita ao servidor, permitindo armazenar itens ilimitados com paginação e controle preciso de quantidades. -Um plugin simples e eficiente para servidores **Spigot/Paper/Purpur**, que adiciona **mochilas infinitas** ao Minecraft. -Os jogadores podem armazenar itens em mochilas virtuais, salvas automaticamente no banco de dados — sem limite físico de inventário! +## Funcionalidades ---- +- **Mochila Infinita**: Armazenamento ilimitado com paginação (45 itens por página) +- **Comando**: `/backpack` ou `/bp` para abrir a mochila +- **Controle de Quantidades**: + - Clique esquerdo: Move 1 item para o cursor (permite escolher onde colocar) + - Clique direito no inventário: Coloca 1 item do cursor no slot + - Shift + clique esquerdo: Move o stack todo diretamente +- **Suporte a Itens Renomeados**: Preserva nomes customizados +- **Shulker Boxes**: Tratamento especial - não mesclam para evitar duplicação de conteúdo +- **Limites de Segurança**: Máximo 1000 itens por mochila, validação contra itens inválidos +- **Persistência**: Dados salvos em SQLite, sobrevive reinícios +- **Sistema de Cursor**: Controle preciso ao mover itens entre mochila e inventário -✨ **Funcionalidades** +## Instalação -- 🎒 Mochila virtual infinita (sem limite de páginas físicas) -- 💾 Salvamento automático via **SQLite** -- 🔄 Itens persistem após reiniciar o servidor -- 🔐 Dados atrelados ao **UUID** do jogador -- ⚙️ Compatível com Minecraft 1.20+ +1. Baixe o JAR mais recente do plugin +2. Coloque o arquivo no diretório `plugins` do seu servidor Minecraft +3. Reinicie o servidor ou use `/reload` +4. Configure permissões se necessário ---- +## Como Usar -📦 **Comandos** +1. Digite `/backpack` no chat para abrir sua mochila +2. **Para tirar itens da mochila**: + - Clique esquerdo: Pega 1 item no cursor + - Shift + clique esquerdo: Move stack todo diretamente pro inventário +3. **Para colocar itens no inventário** (com item no cursor): + - Clique esquerdo no slot vazio: Coloca stack todo + - Clique direito no slot vazio: Coloca 1 item +4. **Para mover itens pro mochila**: + - Shift + clique esquerdo no item: Move diretamente + - Clique esquerdo no item: Move pro cursor +5. **Shulker Boxes**: Sempre ficam separadas na mochila para preservar conteúdo -| Comando | Descrição | Permissão | -|----------|------------|-----------| -| `/backpack` | Abre a mochila infinita do jogador | `backpack.use` | -| `/backpack reload` | Recarrega as configurações | `backpack.admin` | +## Permissões ---- +- `backpack.use`: Permite usar o comando /backpack (padrão: todos os jogadores) -🧠 **Como funciona** +## Desenvolvimento -O plugin cria uma mochila virtual personalizada para cada jogador. -Os itens são serializados em **Base64** e armazenados no banco de dados `backpack.db` localizado na pasta do plugin. -Quando o jogador entra ou usa o comando `/backpack`, o inventário é carregado instantaneamente. +### Pré-requisitos +- Java 21 +- Maven ---- +### Compilação +```bash +mvn clean package +``` -⚙️ **Instalação** +O JAR será gerado em `target/backpack-infinita-1.1.jar` -1. Baixe o arquivo `.jar` do plugin. -2. Coloque-o na pasta `plugins/` do servidor. -3. Reinicie o servidor. -4. Use `/backpack` dentro do jogo! +### Estrutura do Projeto +- `src/main/java/`: Código fonte +- `src/main/resources/`: Configurações (plugin.yml) +- `pom.xml`: Dependências Maven ---- +## Bugs Conhecidos e Fixes -📁 **Estrutura do projeto** +- Corrigido: Duplicação ao mover itens além do disponível +- Corrigido: Itens renomeados perdendo nome +- Corrigido: Shulker boxes mesclando incorretamente +- Corrigido: Problemas com sistema de cursor +## Suporte + +Para bugs ou sugestões, abra uma issue no repositório. + +## Licença + +Este projeto está sob a licença GNU Lesser General Public License v3.0. Veja LICENSE para detalhes. \ No newline at end of file diff --git a/src/main/java/shop/morpheusnox/backpackInfinita/Backpack.java b/src/main/java/shop/morpheusnox/backpackInfinita/Backpack.java index ed4babb..1f3d63c 100644 --- a/src/main/java/shop/morpheusnox/backpackInfinita/Backpack.java +++ b/src/main/java/shop/morpheusnox/backpackInfinita/Backpack.java @@ -117,9 +117,37 @@ public class Backpack { } } + private boolean isSimilarIgnoringDisplayNameAndLore(ItemStack item1, ItemStack item2) { + if (item1.getType() != item2.getType()) return false; + if (item1.getDurability() != item2.getDurability()) return false; + if (!item1.getEnchantments().equals(item2.getEnchantments())) return false; + // Ignora display name e lore para mesclar itens renomeados ou com lore customizada + ItemMeta meta1 = item1.getItemMeta(); + ItemMeta meta2 = item2.getItemMeta(); + if (meta1 != null && meta2 != null) { + // Compara apenas enchants e outros, ignorando display name e lore + return meta1.getEnchants().equals(meta2.getEnchants()) && + (meta1.getAttributeModifiers() == null ? meta2.getAttributeModifiers() == null : meta1.getAttributeModifiers().equals(meta2.getAttributeModifiers())); + } + return meta1 == null && meta2 == null; + } + public void addItem(ItemStack item) { + // Validação: rejeita itens inválidos ou ar + if (item == null || item.getType().isAir() || !item.getType().isItem()) { + return; // Ignora itens inválidos + } + // Limite total de itens (ex.: 1000 para evitar abuso) + if (internalContents.size() >= 1000) { + return; // Não adiciona se exceder limite + } + // Para shulker boxes, não mesclar para evitar problemas com conteúdo + if (item.getType().name().contains("SHULKER_BOX")) { + internalContents.add(item.clone()); + return; + } for (ItemStack existingItem : internalContents) { - if (existingItem.isSimilar(item)) { + if (isSimilarIgnoringDisplayNameAndLore(existingItem, item)) { existingItem.setAmount(existingItem.getAmount() + item.getAmount()); return; } @@ -131,7 +159,7 @@ public class Backpack { Iterator iterator = internalContents.iterator(); while (iterator.hasNext()) { ItemStack existingItem = iterator.next(); - if (existingItem.isSimilar(itemToRemove)) { + if (isSimilarIgnoringDisplayNameAndLore(existingItem, itemToRemove)) { if (existingItem.getAmount() <= itemToRemove.getAmount()) { iterator.remove(); } else { diff --git a/src/main/java/shop/morpheusnox/backpackInfinita/BackpackCommand.java b/src/main/java/shop/morpheusnox/backpackInfinita/BackpackCommand.java index f6bce4a..e11e5c2 100644 --- a/src/main/java/shop/morpheusnox/backpackInfinita/BackpackCommand.java +++ b/src/main/java/shop/morpheusnox/backpackInfinita/BackpackCommand.java @@ -26,6 +26,11 @@ public class BackpackCommand implements CommandExecutor { } Player player = (Player) sender; + if (!player.hasPermission("backpack.use")) { + player.sendMessage("Você não tem permissão para usar este comando."); + return true; + } + Backpack backpack = plugin.getPlayerBackpack(player); backpack.open(); diff --git a/src/main/java/shop/morpheusnox/backpackInfinita/BackpackInfinita.java b/src/main/java/shop/morpheusnox/backpackInfinita/BackpackInfinita.java index 298ae40..553019c 100644 --- a/src/main/java/shop/morpheusnox/backpackInfinita/BackpackInfinita.java +++ b/src/main/java/shop/morpheusnox/backpackInfinita/BackpackInfinita.java @@ -33,6 +33,11 @@ public final class BackpackInfinita extends JavaPlugin { for (Map.Entry entry : playerBackpacks.entrySet()) { savePlayerBackpack(entry.getKey(), entry.getValue()); } + // Fecha a conexão do banco de dados + if (database != null) { + database.closeConnection(); + } + getLogger().info("Backpack Infinita desabilitado com sucesso."); } public Database getDatabase() { @@ -51,8 +56,12 @@ public final class BackpackInfinita extends JavaPlugin { ResultSet resultSet = statement.executeQuery(); if (resultSet.next()) { backpack.fromBase64(resultSet.getString("items")); + getLogger().fine("Backpack carregada do DB para jogador: " + playerUUID); + } else { + getLogger().fine("Nova backpack criada para jogador: " + playerUUID); } } catch (SQLException | IOException e) { + getLogger().severe("Erro ao carregar backpack para " + playerUUID + ": " + e.getMessage()); e.printStackTrace(); } playerBackpacks.put(playerUUID, backpack); @@ -64,7 +73,9 @@ public final class BackpackInfinita extends JavaPlugin { statement.setString(1, playerUUID.toString()); statement.setString(2, backpack.toBase64()); statement.executeUpdate(); + getLogger().fine("Backpack salva para jogador: " + playerUUID); } catch (SQLException e) { + getLogger().severe("Erro ao salvar backpack para " + playerUUID + ": " + e.getMessage()); e.printStackTrace(); } } diff --git a/src/main/java/shop/morpheusnox/backpackInfinita/BackpackListener.java b/src/main/java/shop/morpheusnox/backpackInfinita/BackpackListener.java index 7b87805..952e9a2 100644 --- a/src/main/java/shop/morpheusnox/backpackInfinita/BackpackListener.java +++ b/src/main/java/shop/morpheusnox/backpackInfinita/BackpackListener.java @@ -78,34 +78,93 @@ public class BackpackListener implements Listener { lore.removeIf(line -> line.startsWith("§7Quantidade:")); meta.setLore(lore); } - if (meta.hasDisplayName()) { - meta.setDisplayName(null); - } + // Preserva o display name customizado itemToTransfer.setItemMeta(meta); } - int amountToTransfer = itemToTransfer.getMaxStackSize(); + int amountToTransfer = 1; // Clique normal: 1 item if (event.isShiftClick()) { - amountToTransfer = trueItem.getAmount(); + amountToTransfer = trueItem.getAmount(); // Shift-click: stack todo } + amountToTransfer = Math.min(amountToTransfer, trueItem.getAmount()); itemToTransfer.setAmount(amountToTransfer); - // Tenta adicionar ao inventário do jogador - int remaining = player.getInventory().addItem(itemToTransfer).values().stream() - .mapToInt(ItemStack::getAmount).sum(); + if (event.isShiftClick()) { + // Shift-click: move diretamente para o inventário + int remaining = player.getInventory().addItem(itemToTransfer).values().stream() + .mapToInt(ItemStack::getAmount).sum(); - if (remaining < amountToTransfer) { - // Alguns itens foram transferidos - ItemStack removedFromBackpack = trueItem.clone(); - removedFromBackpack.setAmount(amountToTransfer - remaining); - backpack.removeItem(removedFromBackpack); + if (remaining < amountToTransfer) { + // Alguns itens foram transferidos + if (trueItem.getType().name().contains("SHULKER_BOX")) { + // Para shulker boxes, remover por index para evitar remover a errada + backpack.getInternalContents().remove(internalIndex); + } else { + ItemStack removedFromBackpack = trueItem.clone(); + removedFromBackpack.setAmount(amountToTransfer - remaining); + backpack.removeItem(removedFromBackpack); + } + } + } else { + // Clique normal: move para o cursor + if (event.getCursor() == null || event.getCursor().getType().isAir()) { + event.getWhoClicked().setItemOnCursor(itemToTransfer); + // Remove da mochila + if (trueItem.getType().name().contains("SHULKER_BOX")) { + backpack.getInternalContents().remove(internalIndex); + } else { + ItemStack removedFromBackpack = trueItem.clone(); + removedFromBackpack.setAmount(amountToTransfer); + backpack.removeItem(removedFromBackpack); + } + } else { + // Se há item no cursor, adiciona ao inventário + int remaining = player.getInventory().addItem(itemToTransfer).values().stream() + .mapToInt(ItemStack::getAmount).sum(); + + if (remaining < amountToTransfer) { + if (trueItem.getType().name().contains("SHULKER_BOX")) { + backpack.getInternalContents().remove(internalIndex); + } else { + ItemStack removedFromBackpack = trueItem.clone(); + removedFromBackpack.setAmount(amountToTransfer - remaining); + backpack.removeItem(removedFromBackpack); + } + } + } } } else { - // Clicado no inventário do jogador (movendo para a mochila) - backpack.addItem(clickedItem); - event.getWhoClicked().getInventory().removeItem(clickedItem); + // Clicado no inventário do jogador + if (event.getCursor() != null && !event.getCursor().getType().isAir()) { + // Há item no cursor: colocar no slot clicado + ItemStack cursorItem = event.getCursor().clone(); + int amountToPlace = cursorItem.getAmount(); + if (event.getClick().name().contains("RIGHT")) { + amountToPlace = 1; // Clique direito: 1 item + } + cursorItem.setAmount(amountToPlace); + event.getClickedInventory().setItem(event.getSlot(), cursorItem); + // Reduz do cursor + ItemStack newCursor = event.getCursor().clone(); + newCursor.setAmount(newCursor.getAmount() - amountToPlace); + if (newCursor.getAmount() <= 0) { + newCursor = null; + } + event.getWhoClicked().setItemOnCursor(newCursor); + } else { + // Sem item no cursor: mover do inventário para mochila + if (event.isShiftClick()) { + // Shift-click: move diretamente + backpack.addItem(clickedItem); + event.getWhoClicked().getInventory().removeItem(clickedItem); + } else { + // Clique normal: move para o cursor + event.getWhoClicked().setItemOnCursor(clickedItem.clone()); + event.getWhoClicked().getInventory().removeItem(clickedItem); + } + } } // Atualiza a GUI da mochila diff --git a/src/main/java/shop/morpheusnox/backpackInfinita/Database.java b/src/main/java/shop/morpheusnox/backpackInfinita/Database.java index ba82ccc..2073c10 100644 --- a/src/main/java/shop/morpheusnox/backpackInfinita/Database.java +++ b/src/main/java/shop/morpheusnox/backpackInfinita/Database.java @@ -38,4 +38,14 @@ public class Database { public Connection getConnection() { return connection; } + + public void closeConnection() { + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 195fb4b..2abbf22 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -7,3 +7,8 @@ commands: description: Mochila infinita pra você que fica sempre sem espaço no inventario. usage: /backpack aliases: [bp] + permission: backpack.use +permissions: + backpack.use: + description: Permite usar o comando /backpack + default: true diff --git a/target/backpack-infinita-1.1.jar b/target/backpack-infinita-1.1.jar index 623937e..3901fb7 100644 Binary files a/target/backpack-infinita-1.1.jar and b/target/backpack-infinita-1.1.jar differ diff --git a/target/classes/plugin.yml b/target/classes/plugin.yml index 195fb4b..2abbf22 100644 --- a/target/classes/plugin.yml +++ b/target/classes/plugin.yml @@ -7,3 +7,8 @@ commands: description: Mochila infinita pra você que fica sempre sem espaço no inventario. usage: /backpack aliases: [bp] + permission: backpack.use +permissions: + backpack.use: + description: Permite usar o comando /backpack + default: true diff --git a/target/classes/shop/morpheusnox/backpackInfinita/Backpack.class b/target/classes/shop/morpheusnox/backpackInfinita/Backpack.class index 8e42a90..180b505 100644 Binary files a/target/classes/shop/morpheusnox/backpackInfinita/Backpack.class and b/target/classes/shop/morpheusnox/backpackInfinita/Backpack.class differ diff --git a/target/classes/shop/morpheusnox/backpackInfinita/BackpackCommand.class b/target/classes/shop/morpheusnox/backpackInfinita/BackpackCommand.class index c263102..9b54585 100644 Binary files a/target/classes/shop/morpheusnox/backpackInfinita/BackpackCommand.class and b/target/classes/shop/morpheusnox/backpackInfinita/BackpackCommand.class differ diff --git a/target/classes/shop/morpheusnox/backpackInfinita/BackpackInfinita.class b/target/classes/shop/morpheusnox/backpackInfinita/BackpackInfinita.class index dcf6c8f..0742093 100644 Binary files a/target/classes/shop/morpheusnox/backpackInfinita/BackpackInfinita.class and b/target/classes/shop/morpheusnox/backpackInfinita/BackpackInfinita.class differ diff --git a/target/classes/shop/morpheusnox/backpackInfinita/BackpackListener.class b/target/classes/shop/morpheusnox/backpackInfinita/BackpackListener.class index b586081..5166b88 100644 Binary files a/target/classes/shop/morpheusnox/backpackInfinita/BackpackListener.class and b/target/classes/shop/morpheusnox/backpackInfinita/BackpackListener.class differ diff --git a/target/classes/shop/morpheusnox/backpackInfinita/Database.class b/target/classes/shop/morpheusnox/backpackInfinita/Database.class index 68473c2..06e05c1 100644 Binary files a/target/classes/shop/morpheusnox/backpackInfinita/Database.class and b/target/classes/shop/morpheusnox/backpackInfinita/Database.class differ diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst index b3d45cc..68289c6 100644 --- a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -1,5 +1,5 @@ -/home/morpheus/Downloads/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/Backpack.java -/home/morpheus/Downloads/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/BackpackCommand.java -/home/morpheus/Downloads/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/BackpackInfinita.java -/home/morpheus/Downloads/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/BackpackListener.java -/home/morpheus/Downloads/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/Database.java +/home/morpheus/Downloads/Projetos/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/Backpack.java +/home/morpheus/Downloads/Projetos/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/BackpackCommand.java +/home/morpheus/Downloads/Projetos/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/BackpackInfinita.java +/home/morpheus/Downloads/Projetos/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/BackpackListener.java +/home/morpheus/Downloads/Projetos/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/Database.java diff --git a/target/original-backpack-infinita-1.1.jar b/target/original-backpack-infinita-1.1.jar index 1ca6367..fb1e7b7 100644 Binary files a/target/original-backpack-infinita-1.1.jar and b/target/original-backpack-infinita-1.1.jar differ