Compare commits
7 Commits
8675c3f4d6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| adc29bff0c | |||
| b162540450 | |||
| ac26b22379 | |||
| 4e549d8d7d | |||
| 259b173acb | |||
| 2f3390eaaa | |||
| 238ba6a86c |
70
README.md
Normal file
70
README.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# Backpack Infinita
|
||||||
|
|
||||||
|
Plugin para Minecraft que adiciona uma mochila infinita ao servidor, permitindo armazenar itens ilimitados com paginação e controle preciso de quantidades.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
## Instalação
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
1. Digite `/backpack` no chat para abrir sua mochila
|
||||||
|
2. **Para tirar itens da mochila**:
|
||||||
|
- Clique esquerdo: Pega 1 item
|
||||||
|
- Shift + clique esquerdo: Move stack todo diretamente pro inventário
|
||||||
|
3. **Para mover itens para a mochila**:
|
||||||
|
- Shift + clique esquerdo no item: Move diretamente para a mochila
|
||||||
|
4. **Shulker Boxes**: Sempre ficam separadas na mochila para preservar conteúdo
|
||||||
|
|
||||||
|
## Permissões
|
||||||
|
|
||||||
|
- `backpack.use`: Permite usar o comando /backpack (padrão: todos os jogadores)
|
||||||
|
|
||||||
|
## Desenvolvimento
|
||||||
|
|
||||||
|
### Pré-requisitos
|
||||||
|
- Java 21
|
||||||
|
- Maven
|
||||||
|
|
||||||
|
### Compilação
|
||||||
|
```bash
|
||||||
|
mvn clean package
|
||||||
|
```
|
||||||
|
|
||||||
|
O JAR será gerado em `target/backpack-infinita-1.1.jar`
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|
||||||
|
- 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.
|
||||||
@@ -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) {
|
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) {
|
for (ItemStack existingItem : internalContents) {
|
||||||
if (existingItem.isSimilar(item)) {
|
if (isSimilarIgnoringDisplayNameAndLore(existingItem, item)) {
|
||||||
existingItem.setAmount(existingItem.getAmount() + item.getAmount());
|
existingItem.setAmount(existingItem.getAmount() + item.getAmount());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -131,7 +159,7 @@ public class Backpack {
|
|||||||
Iterator<ItemStack> iterator = internalContents.iterator();
|
Iterator<ItemStack> iterator = internalContents.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
ItemStack existingItem = iterator.next();
|
ItemStack existingItem = iterator.next();
|
||||||
if (existingItem.isSimilar(itemToRemove)) {
|
if (isSimilarIgnoringDisplayNameAndLore(existingItem, itemToRemove)) {
|
||||||
if (existingItem.getAmount() <= itemToRemove.getAmount()) {
|
if (existingItem.getAmount() <= itemToRemove.getAmount()) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ public class BackpackCommand implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Player player = (Player) sender;
|
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 backpack = plugin.getPlayerBackpack(player);
|
||||||
backpack.open();
|
backpack.open();
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ public final class BackpackInfinita extends JavaPlugin {
|
|||||||
for (Map.Entry<UUID, Backpack> entry : playerBackpacks.entrySet()) {
|
for (Map.Entry<UUID, Backpack> entry : playerBackpacks.entrySet()) {
|
||||||
savePlayerBackpack(entry.getKey(), entry.getValue());
|
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() {
|
public Database getDatabase() {
|
||||||
@@ -51,8 +56,12 @@ public final class BackpackInfinita extends JavaPlugin {
|
|||||||
ResultSet resultSet = statement.executeQuery();
|
ResultSet resultSet = statement.executeQuery();
|
||||||
if (resultSet.next()) {
|
if (resultSet.next()) {
|
||||||
backpack.fromBase64(resultSet.getString("items"));
|
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) {
|
} catch (SQLException | IOException e) {
|
||||||
|
getLogger().severe("Erro ao carregar backpack para " + playerUUID + ": " + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
playerBackpacks.put(playerUUID, backpack);
|
playerBackpacks.put(playerUUID, backpack);
|
||||||
@@ -64,7 +73,9 @@ public final class BackpackInfinita extends JavaPlugin {
|
|||||||
statement.setString(1, playerUUID.toString());
|
statement.setString(1, playerUUID.toString());
|
||||||
statement.setString(2, backpack.toBase64());
|
statement.setString(2, backpack.toBase64());
|
||||||
statement.executeUpdate();
|
statement.executeUpdate();
|
||||||
|
getLogger().fine("Backpack salva para jogador: " + playerUUID);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
getLogger().severe("Erro ao salvar backpack para " + playerUUID + ": " + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,34 +78,93 @@ public class BackpackListener implements Listener {
|
|||||||
lore.removeIf(line -> line.startsWith("§7Quantidade:"));
|
lore.removeIf(line -> line.startsWith("§7Quantidade:"));
|
||||||
meta.setLore(lore);
|
meta.setLore(lore);
|
||||||
}
|
}
|
||||||
if (meta.hasDisplayName()) {
|
// Preserva o display name customizado
|
||||||
meta.setDisplayName(null);
|
|
||||||
}
|
|
||||||
itemToTransfer.setItemMeta(meta);
|
itemToTransfer.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
int amountToTransfer = itemToTransfer.getMaxStackSize();
|
int amountToTransfer = 1; // Clique normal: 1 item
|
||||||
if (event.isShiftClick()) {
|
if (event.isShiftClick()) {
|
||||||
amountToTransfer = trueItem.getAmount();
|
amountToTransfer = trueItem.getAmount(); // Shift-click: stack todo
|
||||||
}
|
}
|
||||||
|
amountToTransfer = Math.min(amountToTransfer, trueItem.getAmount());
|
||||||
|
|
||||||
itemToTransfer.setAmount(amountToTransfer);
|
itemToTransfer.setAmount(amountToTransfer);
|
||||||
|
|
||||||
// Tenta adicionar ao inventário do jogador
|
if (event.isShiftClick()) {
|
||||||
|
// Shift-click: move diretamente para o inventário
|
||||||
int remaining = player.getInventory().addItem(itemToTransfer).values().stream()
|
int remaining = player.getInventory().addItem(itemToTransfer).values().stream()
|
||||||
.mapToInt(ItemStack::getAmount).sum();
|
.mapToInt(ItemStack::getAmount).sum();
|
||||||
|
|
||||||
if (remaining < amountToTransfer) {
|
if (remaining < amountToTransfer) {
|
||||||
// Alguns itens foram transferidos
|
// 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();
|
ItemStack removedFromBackpack = trueItem.clone();
|
||||||
removedFromBackpack.setAmount(amountToTransfer - remaining);
|
removedFromBackpack.setAmount(amountToTransfer - remaining);
|
||||||
backpack.removeItem(removedFromBackpack);
|
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 {
|
} else {
|
||||||
// Clicado no inventário do jogador (movendo para a mochila)
|
// 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);
|
backpack.addItem(clickedItem);
|
||||||
event.getWhoClicked().getInventory().removeItem(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
|
// Atualiza a GUI da mochila
|
||||||
|
|||||||
@@ -38,4 +38,14 @@ public class Database {
|
|||||||
public Connection getConnection() {
|
public Connection getConnection() {
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void closeConnection() {
|
||||||
|
if (connection != null) {
|
||||||
|
try {
|
||||||
|
connection.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,3 +7,8 @@ commands:
|
|||||||
description: Mochila infinita pra você que fica sempre sem espaço no inventario.
|
description: Mochila infinita pra você que fica sempre sem espaço no inventario.
|
||||||
usage: /backpack
|
usage: /backpack
|
||||||
aliases: [bp]
|
aliases: [bp]
|
||||||
|
permission: backpack.use
|
||||||
|
permissions:
|
||||||
|
backpack.use:
|
||||||
|
description: Permite usar o comando /backpack
|
||||||
|
default: true
|
||||||
|
|||||||
Binary file not shown.
@@ -7,3 +7,8 @@ commands:
|
|||||||
description: Mochila infinita pra você que fica sempre sem espaço no inventario.
|
description: Mochila infinita pra você que fica sempre sem espaço no inventario.
|
||||||
usage: /backpack
|
usage: /backpack
|
||||||
aliases: [bp]
|
aliases: [bp]
|
||||||
|
permission: backpack.use
|
||||||
|
permissions:
|
||||||
|
backpack.use:
|
||||||
|
description: Permite usar o comando /backpack
|
||||||
|
default: true
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
/home/morpheus/Downloads/backpack Infinita/src/main/java/shop/morpheusnox/backpackInfinita/Backpack.java
|
/home/morpheus/Downloads/Projetos/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/Projetos/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/Projetos/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/Projetos/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/Database.java
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user