Skip to content

Add SelectCrate type for player-selectable prize crates - #20

Merged
SrBedrock merged 17 commits into
dev/select_rollfrom
copilot/add-select-crate-open-type
Dec 22, 2025
Merged

Add SelectCrate type for player-selectable prize crates#20
SrBedrock merged 17 commits into
dev/select_rollfrom
copilot/add-select-crate-open-type

Conversation

Copilot AI commented Dec 22, 2025

Copy link
Copy Markdown

Implements a new crate type that allows players to choose their prize from a GUI instead of random selection. Keys are validated twice and consumed only on confirmation to prevent loss from accidental closures or disconnects.

Implementation

New crate type: select_crate enum added to CrateType

Core classes:

  • SelectCrate - Extends CrateBuilder, renders prize GUI with confirmation button
  • SelectCrateListener - Handles click events, selection state, key validation/consumption
  • SelectCrateSession - Tracks player selection state per-session

Visual selection: Selected items receive enchantment glow + configurable lore marker

Key consumption logic:

// Validate on open (permission check only)
if (isCrateEventValid(type, checkHand)) return;

// Validate + consume on confirm
if (type == KeyType.physical_key && !hasPhysicalKey()) {
    player.sendMessage(Messages.no_keys);
    return;
}
boolean failed = !takeKeys(requiredKeys, uuid, crateName, type, hand);
if (failed) {
    MiscUtils.failedToTakeKey(player, crate);
    return;
}
givePrize(player, selectedPrize, crate);

Configuration:

CrateType: SelectCrate
SelectCrate:
  GUI:
    Size: 54
    Title: '&6Select Your Prize!'
  Confirm:
    Slot: 49
    Item: {Material: LIME_CONCRETE, Name: '&aConfirm Choice'}
  SelectionMarker:
    Name: '&e&l✓ SELECTED'
  Messages:
    NoSelection: '&cPlease select a prize before confirming!'

Safety

  • All inventory interactions (drag, shift-click) cancelled
  • Session cleanup on disconnect/quit/plugin disable
  • No key consumption on GUI close without confirmation
  • Dual key validation (open + confirm) prevents race conditions

Integration

Follows existing patterns: extends CrateBuilder, uses PersistentDataContainer for prize identification, integrates with PrizeManager for delivery. Compatible with all prize types (items, commands, economy) and existing features (holograms, broadcasts, PlaceholderAPI).

Files: SelectCrate.java (170L), SelectCrateListener.java (268L), SelectCrateSession.java (93L), example config and documentation included.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • jitpack.io
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
    • Triggering command: /usr/lib/jvm/temurin-21-jdk-amd64/bin/java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
  • repo.codemc.io
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
    • Triggering command: /usr/lib/jvm/temurin-21-jdk-amd64/bin/java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
  • repo.crazycrew.us
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
    • Triggering command: /usr/lib/jvm/temurin-21-jdk-amd64/bin/java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
  • repo.extendedclip.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
    • Triggering command: /usr/lib/jvm/temurin-21-jdk-amd64/bin/java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
  • repo.oraxen.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
    • Triggering command: /usr/lib/jvm/temurin-21-jdk-amd64/bin/java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
  • repo.papermc.io
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
    • Triggering command: /usr/lib/jvm/temurin-21-jdk-amd64/bin/java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
  • repo.triumphteam.dev
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)
    • Triggering command: /usr/lib/jvm/temurin-21-jdk-amd64/bin/java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx3G -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.3-bin/cv11ve7ro1n3o1j4so8xd9n66/gradle-8.14.3/lib/gradle-daemon-main-8.14.3.jar (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

@copilot
Quero adicionar um novo tipo de abertura no plugin CrazyCrates chamado SelectCrate.

Objetivo:

  • Ao abrir uma crate do tipo SelectCrate, o jogador visualiza um GUI com os prêmios e escolhe qual item deseja receber.
  • O sistema deve exigir a quantidade correta de chaves antes de permitir a seleção/entrega.
  • O jogador marca visualmente o item selecionado (por exemplo, com uma NETHER_STAR) e depois confirma no botão de confirmação.
  • Ao confirmar, o plugin remove as chaves necessárias e entrega exatamente o prêmio selecionado.

Requisitos funcionais

  1. Novo tipo de abertura
  • Adicionar suporte no CrazyCrates para um novo CrateOpenType/CrateType chamado SelectCrate.
  • O tipo deve ser configurável por crate no arquivo de configuração (ex.: CrateType: SelectCrate).
  1. Validação de chaves ao abrir
  • Ao tentar abrir a crate:
    • Verificar se o jogador possui a quantidade necessária de chaves (reutilizar a lógica já existente de keys do CrazyCrates).
    • Se não possuir, bloquear abertura e enviar a mensagem padrão de “sem chave” (ou criar uma específica se necessário).
  • O consumo da chave NÃO deve acontecer no momento que abre o GUI.
    • Só deve consumir ao confirmar a escolha, para evitar perder key sem receber prêmio.
  1. GUI de seleção
  • Abrir um inventário GUI (size configurável, default 54) listando todos os prêmios daquela crate.
  • Cada item exibido deve representar o prêmio (usar a lógica já existente para construir ItemStack do prêmio).
  • O jogador clica em um item para selecioná-lo.
  1. Marcação de item selecionado
  • Quando o jogador selecionar um prêmio:
    • Marcar visualmente o item selecionado usando um “marker item” configurável (default NETHER_STAR).
    • Formas aceitáveis de marcar (escolher a mais compatível com a base do CrazyCrates):
      A) Adicionar o marker no lore (ex.: “Selecionado”) + glow
      B) Trocar o item por um clone com uma lore/enchanted glow
      C) Exibir um item marker em um slot fixo ao lado (ex.: slot de preview)
    • O marker precisa ser configurável no config da crate:
      • SelectionMarker.Material (default: NETHER_STAR)
      • SelectionMarker.Name
      • SelectionMarker.Lore

Importante: a marcação deve ser apenas visual, sem alterar o prêmio real entregue.

  1. Botão de confirmar
  • Adicionar um botão de confirmação:
    • Slot padrão: 49
    • Slot configurável por crate.
  • Ao clicar:
    • Validar novamente se o jogador ainda tem as chaves necessárias.
    • Se não tiver, cancelar e informar (ex.: ele gastou a key em outra crate).
    • Se estiver tudo ok:
      • Remover a quantidade de chaves necessária.
      • Entregar o prêmio selecionado ao jogador usando o fluxo padrão de give (respeitando comandos, items, money, etc.).
      • Fechar o inventário e enviar mensagem de sucesso.
  1. Regras e edge cases
  • Se o jogador fechar o inventário sem confirmar:
    • Não consumir chave.
    • Limpar sessão de seleção.
  • Se o jogador tentar confirmar sem ter selecionado um item:
    • Bloquear e enviar mensagem: “Selecione um prêmio primeiro”.
  • Não permitir exploits:
    • Bloquear shift-click/move items no inventário da crate.
    • Cancelar InventoryClickEvent e InventoryDragEvent no GUI.
  • Limpar sessão em:
    • Quit do jogador.
    • Kick.
    • Troca de mundo (opcional).
    • Plugin disable.

Configuração (por crate)

Adicionar no arquivo da crate algo como:

CrateType: SelectCrate
SelectCrate:
  GUI:
    Size: 54
    Title: "&6Selecione seu prêmio!"
  Confirm:
    Slot: 49
    Item:
      Material: LIME_CONCRETE
      Name: "&aConfirmar escolha"
      Lore:
        - "&7Clique para receber o prêmio selecionado."
  SelectionMarker:
    Material: NETHER_STAR
    Name: "&eSelecionado"
    Lore:
      - "&7Este prêmio está selecionado."
  Messages:
    NoSelection: "&cSelecione um prêmio antes de confirmar."

Estrutura e integração com o código existente

  • Reusar as classes e padrões do CrazyCrates:
    • Sistema de Crate, Prize/Reward, CrateManager, KeyManager.
    • Fluxo padrão de entrega (itens/comandos/economia).
  • Criar componentes novos de forma coesa:
    • SelectCrateOpenHandler (lógica do tipo SelectCrate)
    • SelectCrateSession (armazenar crate, player, seleção atual)
    • SelectCrateGui (montagem do inventário + handlers)
  • Registrar o novo tipo na enum/registry onde os tipos de abertura são definidos.

Critério de pronto

  • Crate com CrateType: SelectCrate abre um GUI de seleção.
  • Jogador só consegue receber prêmio após selecionar e confirmar.
  • Chaves são removidas apenas na confirmação.
  • Marca visual do item selecionado funciona e é configurável.
  • Sem exploits de movimentação de itens e sem consumo indevido de chaves.

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 6 commits December 22, 2025 02:28
Co-authored-by: SrBedrock <51332006+SrBedrock@users.noreply.github.com>
Co-authored-by: SrBedrock <51332006+SrBedrock@users.noreply.github.com>
Co-authored-by: SrBedrock <51332006+SrBedrock@users.noreply.github.com>
Co-authored-by: SrBedrock <51332006+SrBedrock@users.noreply.github.com>
Co-authored-by: SrBedrock <51332006+SrBedrock@users.noreply.github.com>
Co-authored-by: SrBedrock <51332006+SrBedrock@users.noreply.github.com>
Copilot AI changed the title [WIP] Add new SelectCrate opening type to CrazyCrates plugin Add SelectCrate type for player-selectable prize crates Dec 22, 2025
Copilot AI requested a review from SrBedrock December 22, 2025 02:49
Added 'final' modifiers to method parameters and local variables in SelectCrateListener and SelectCrate for improved code clarity and immutability. Minor formatting and code style improvements were also made for consistency.
Updated the 'clean' task in build.gradle.kts to remove the 'jars' directory during project cleanup.
Added documentation links and updated comments in bukkit.yml and spigot.yml. Updated paper-global.yml and paper-world-defaults.yml with new configuration options, including anticheat, management server, and entity behavior settings. Refreshed server.properties with new management server and status options, and synchronized config files with latest PaperMC documentation and features.
Updated WarCrateListener to use 'final' for local variables in event handler methods, improving code clarity and enforcing immutability where possible.
Introduced info-level logging throughout the SelectCrateListener to provide better visibility into inventory interactions, including non-player clicks, invalid inventory holders, crate state checks, and prize selection. This will help with debugging and monitoring crate selection events.
Replaced direct logger calls with the plugin's debug method in SelectCrateListener for consistency and improved logging control. Also added an overloaded debug method in CrazyCrates for simplified info-level logging.
Replaces direct prize awarding and event firing with a new PrizeManager.givePrizeAndCallEvent method across crate types and listeners. This centralizes the logic for awarding prizes and firing related events, improving maintainability and reducing code duplication. Also updates method signatures for consistency and adds final modifiers for parameters in several classes.
Eliminated the code that sent success messages to players after selecting a crate prize. This streamlines the crate selection process and prevents duplicate or unnecessary messaging.
@SrBedrock
SrBedrock marked this pull request as ready for review December 22, 2025 05:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a new SelectCrate type for the CrazyCrates plugin, enabling players to manually choose their prize from a GUI instead of receiving a randomly selected reward. The implementation follows existing plugin patterns and includes comprehensive safety measures to prevent key loss from accidental closures or disconnects.

Key changes include:

  • New select_crate enum value added to the CrateType enumeration
  • Three new core classes implementing the selection GUI, event handling, and session management
  • Integration with existing crate infrastructure for key validation and prize delivery
  • Visual selection feedback via enchantment glow and configurable lore markers
  • Comprehensive example configuration and user documentation

Reviewed changes

Copilot reviewed 20 out of 22 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
api/src/main/java/us/crazycrew/crazycrates/api/enums/types/CrateType.java Adds select_crate enum value to enable the new crate type
paper/src/main/java/com/badbones69/crazycrates/tasks/crates/types/SelectCrate.java Core crate builder implementation that creates the selection GUI with prizes and confirmation button
paper/src/main/java/com/badbones69/crazycrates/tasks/crates/other/SelectCrateSession.java Session management class tracking player selections per-crate-opening
paper/src/main/java/com/badbones69/crazycrates/listeners/crates/SelectCrateListener.java Event listener handling GUI clicks, selection state, key validation, and consumption logic
paper/src/main/java/com/badbones69/crazycrates/tasks/crates/CrateManager.java Integrates SelectCrate instantiation into the existing crate opening flow
paper/src/main/java/com/badbones69/crazycrates/CrazyCrates.java Registers SelectCrateListener and adds debug method overload
paper/src/main/java/com/badbones69/crazycrates/api/PrizeManager.java Renames givePrize to givePrizeAndCallEvent for clarity across crate types
paper/src/main/resources/crates/SelectCrateExample.yml Complete example configuration demonstrating all SelectCrate features
paper/src/main/resources/crates/CrateExample.yml Updates documentation comment to include SelectCrate in available types
docs/SELECT_CRATE.md Comprehensive user documentation with configuration reference and examples
IMPLEMENTATION_SUMMARY.md Technical implementation summary detailing all changes and safety features
paper/src/main/java/com/badbones69/crazycrates/tasks/crates/types/WheelCrate.java Style consistency: adds final modifiers to match codebase standards
paper/src/main/java/com/badbones69/crazycrates/tasks/crates/types/RouletteCrate.java Style consistency: adds final modifiers and updates to use givePrizeAndCallEvent
paper/src/main/java/com/badbones69/crazycrates/tasks/crates/types/CsgoCrate.java Updates to use renamed givePrizeAndCallEvent method
paper/src/main/java/com/badbones69/crazycrates/listeners/crates/WarCrateListener.java Style consistency: adds final modifiers to match codebase standards
build.gradle.kts Adds clean task to delete jars directory
paper/run/* Configuration file updates (runtime/generated files, not core to feature)
gradlew Gradle wrapper script addition

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Removed unnecessary blank lines and redundant comments to improve readability and maintain consistency in the SelectCrateExample.yml configuration file. No functional changes were made.
Standardized spacing in debug log messages for better readability and removed unused imports from SelectCrateListener.java.
@SrBedrock
SrBedrock merged commit 5b07900 into dev/select_roll Dec 22, 2025
1 check passed
@SrBedrock
SrBedrock deleted the copilot/add-select-crate-open-type branch December 22, 2025 05:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants