# crates.yml

## Configuring `crates.yml`

`crates.yml` is where every crate type is defined. It lives in `plugins/TCP-VaultCrates/crates.yml`. The format is YAML — same indentation rules as every other plugin file. **Use spaces, never tabs** — a single tab character anywhere in the file will silently break parsing.

You can edit this file at runtime and apply changes with `/tcpvc reload` — no server restart needed.

### Top-level shape

```yaml
crates:
  <crate-id>:
    display-name: "..."
    reset-mode: per-player | server-wide | one-time
    reset-interval-seconds: 86400
    announce: false
    normal:
      key: { ... }
      loot: { ... }
    ominous:
      key: { ... }
      loot: { ... }
    hologram-overrides: { ... }
```

Every key under `crates:` is a **crate id** — lowercase letters, digits, `_`, and `-` only. The id appears in commands (`/tcpvc key give <player> <crate>`) and in shop plugins, so renaming an id is a breaking change for anything pointing at the old name.

### Display name

```yaml
display-name: "<gold>⚔ Common Crate</gold>"
```

Raw [MiniMessage](https://docs.advntr.dev/minimessage/format.html) — gradients, hover events, decorative chars all welcome. Shown in the hologram, in chat broadcasts, and on the GUI tile.

### Reset modes

| Mode          | Behaviour                                                                                                                                              |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `per-player`  | Each player has their own cooldown timer. After opening, that player can't open again for `reset-interval-seconds` — but everyone else can still open. |
| `server-wide` | After **anyone** opens, the vault is locked for **everyone** until the shared timer expires. Useful for shared event crates.                           |
| `one-time`    | The vault never resets. Each player gets exactly one open, ever. Perfect for milestone rewards or staff-issued one-shot loot.                          |

`reset-interval-seconds` is required for `per-player` and `server-wide` (must be > 0). It's ignored for `one-time`.

### announce: true

```yaml
announce: false
```

When true, **every successful open** triggers a server-wide broadcast. This is *separate* from the per-loot-entry `announce` flag (which broadcasts only when a specific rare prize hits) — set this to `true` only if you want every open of this crate type to be announced (rare for common crates, sometimes desired for a Legendary tier).

### Two tiers: normal and ominous

A vault block is either *normal* or *ominous* in vanilla — the ominous variant has a different texture and is what spawns from ominous trial chambers. The plugin reads this state from the block and uses the matching tier's loot pool + key.

```yaml
common:
  normal:
    key: { ... }
    loot: { ... }
  ominous:
    key: { ... }
    loot: { ... }
```

You can configure either or both tiers. If a player tries to open an ominous vault belonging to a crate that has only the normal tier configured, they'll see "This crate isn't configured for the ominous tier." A clean rejection — no key consumed.

### Defining a key

```yaml
key:
  material: AMETHYST_SHARD
  display-name: "<gray>Common Key</gray>"
  lore:
    - "<dark_gray>Right-click a Common Crate</dark_gray>"
    - "<dark_gray>to open it.</dark_gray>"
  custom-model-data: 1001       # optional
```

| Field               | What it does                                           |
| ------------------- | ------------------------------------------------------ |
| `material`          | Any Bukkit material name. The actual ItemStack type.   |
| `display-name`      | MiniMessage. Shown when hovering the key in inventory. |
| `lore`              | List of MiniMessage lines. Optional.                   |
| `custom-model-data` | Optional integer for resource-pack model selection.    |

The plugin tags every key with two PDC entries (`tcpvc:crate_id` and `tcpvc:key_tier`) so it can recognise the key at vault-open time regardless of how the key got into the player's inventory.

### Defining a loot pool

```yaml
loot:
  rolls: "1-3"                  # how many random draws per open
  guaranteed:                   # always given regardless of rolls
    - { type: vanilla, material: COBBLESTONE, amount: "16-32" }
  entries:                      # weighted random pool
    - { type: vanilla, material: IRON_INGOT, amount: "2-5", weight: 30 }
    - { type: vanilla, material: DIAMOND,    amount: "1-2", weight: 8  }
    - { type: vanilla, material: EXPERIENCE_BOTTLE, amount: "4-4", weight: 15 }
```

#### `rolls`

How many random draws to do per open. Can be a single number (`3` = always 3 prizes) or a range (`"1-3"` = 1, 2, or 3 prizes, chosen uniformly).

#### `guaranteed`

A list of entries that **always** drop on every open. Their `weight` field is ignored — they're outside the random draw. Use this for "every Common crate gives at least 16 cobblestone" floors.

#### `entries`

The weighted random pool. Each draw picks one entry by weight; weights are relative (an entry with weight 30 is 3× as likely to drop as one with weight 10). Multiple draws can hit the same entry — they're independent.

### Loot entry types

Every entry has a `type` field that decides what happens on roll.

#### `type: vanilla`

A regular Minecraft item.

```yaml
- type: vanilla
  material: NETHERITE_INGOT
  amount: "1-2"
  weight: 5
  display-name: "<gradient:gold:yellow>★ Special Netherite</gradient>"   # optional rename
  lore:                                                                  # optional
    - "<dark_gray>From the Common Crate</dark_gray>"
  custom-model-data: 42                                                  # optional
  announce: true                                                         # optional
```

#### `type: command`

Run a console command on roll. The command runs as the server console (so any privileged operation you can do as op works).

```yaml
- type: command
  command: "minecraft:effect give {player} minecraft:hero_of_the_village 600 1"
  description: "10min Hero of the Village"
  weight: 10
  amount: 1   # rarely matters for commands; defaults to 1
```

`{player}` is replaced with the opener's name. The `description` field is shown in the chat summary and the loot preview GUI — pick something players will recognise.

#### `type: key-reward`

Mint another crate's key. The key the player receives is a complete key item ready to use — exactly what `/tcpvc key give` would issue.

```yaml
- type: key-reward
  crate-id: legendary
  tier: ominous
  amount: 1
  weight: 1
  announce: true
```

`crate-id` must reference a real crate already configured in this file. If it doesn't, the entry is logged as a warning at load and skipped at give-time.

#### `type: wild-spawner`

Drop a TCP-WildSpawners spawner item. Requires the WildSpawners plugin module — if it isn't installed, the entry logs a one-time warning and is skipped.

```yaml
- type: wild-spawner
  preset-id: dungeon_guardian
  amount: 1
  weight: 2
  announce: true
```

The preset id must exist in WildSpawners' `wild-presets.yml`.

#### `type: custom`

Items from soft-depend plugins (Nexo / ItemsAdder / Oraxen / MythicCrucible). The structured reference is stored:

```yaml
- type: custom
  provider: nexo                # or itemsadder / oraxen / mythic
  item-id: mythic_sword
  amount: 1
  weight: 5
```

**v1.0 note:** the schema is in place but the actual provider integrations ship in **v1.1**. In v1.0, custom-item entries log a one-time message and are skipped at give-time. They don't break anything; they just don't drop yet.

### Common fields across all entry types

| Field      | Default | Meaning                                                                          |
| ---------- | ------- | -------------------------------------------------------------------------------- |
| `weight`   | 1.0     | Relative draw weight. Must be > 0. Ignored for `guaranteed:` entries.            |
| `amount`   | 1       | Single integer or `"lo-hi"` range. Per-roll randomised within the range.         |
| `announce` | false   | When true, broadcasts a `★ <player> just won X from Y` line server-wide on roll. |

### Per-crate hologram overrides

```yaml
hologram-overrides:
  last-opener: false
  cooldown: false
```

Override the global `holograms.lines.*` toggles for this specific crate. Useful when you want, say, every crate to show its cooldown *except* the milestone "one-time" rewards, where the cooldown line would be misleading.

Valid keys: `title`, `key-required`, `prizes-count`, `last-opener`, `cooldown`.

### A complete worked example

```yaml
crates:

  common:
    display-name: "<gray>Common Crate</gray>"
    reset-mode: per-player
    reset-interval-seconds: 86400         # 24h
    announce: false
    normal:
      key:
        material: AMETHYST_SHARD
        display-name: "<gray>Common Key</gray>"
        lore:
          - "<dark_gray>Right-click a Common Crate</dark_gray>"
      loot:
        rolls: "1-3"
        guaranteed:
          - { type: vanilla, material: COBBLESTONE, amount: "16-32" }
        entries:
          - { type: vanilla, material: IRON_INGOT,    amount: "2-5",  weight: 30 }
          - { type: vanilla, material: GOLD_INGOT,    amount: "1-3",  weight: 20 }
          - { type: vanilla, material: DIAMOND,       amount: "1-2",  weight: 8  }
          - { type: vanilla, material: ENCHANTED_BOOK, amount: 1,     weight: 5  }
          - { type: vanilla, material: EXPERIENCE_BOTTLE, amount: "4-4", weight: 15 }
          - { type: key-reward, crate-id: legendary, tier: normal, weight: 1, announce: true }

  legendary:
    display-name: "<gradient:gold:yellow><b>Legendary Crate</b></gradient>"
    reset-mode: one-time
    announce: true
    ominous:
      key:
        material: ECHO_SHARD
        display-name: "<gradient:gold:yellow><b>Legendary Key</b></gradient>"
        lore:
          - "<dark_gray>The rarest of keys.</dark_gray>"
        custom-model-data: 1001
      loot:
        rolls: 3
        guaranteed:
          - { type: vanilla, material: NETHERITE_INGOT, amount: 1 }
        entries:
          - { type: vanilla, material: ELYTRA, amount: 1, weight: 5 }
          - { type: vanilla, material: TOTEM_OF_UNDYING, amount: "1-2", weight: 15 }
          - { type: vanilla, material: HEAVY_CORE, amount: 1, weight: 8 }
```

### Validation

The loader is **lenient** — a single bad entry doesn't kill the whole file. Errors are logged with the offending crate or entry path so you can find them:

```
[WARNING] crates.yml: crates.legendary.ominous.entries[2] rejected — material 'NEHERITE_INGOT' is not a known Bukkit material.
```

The rest of the file still loads. Fix the typo and `/tcpvc reload`.

***

Next: **Managing keys →** · **The admin GUI →**


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://darkstarworks.gitbook.io/plugins/mc/tcp-documentation/tcp-vaultcrates/installation/crates.yml.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
