> For the complete documentation index, see [llms.txt](https://esmp-fun.gitbook.io/plugins/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://esmp-fun.gitbook.io/plugins/vault-crates/crates-yml.md).

# Configuring crates.yml

`crates.yml` is where every crate type is defined. It lives in `plugins/Vault Crates/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. Since 1.0.1, **the tier is selected by the key in the player's hand**, not by the block's visual state: if a crate has both tiers configured, either key opens the same vault and rolls its own tier's loot pool. (`/tcpvc set` still aligns the block's ominous flag to the configured tier when only one tier exists, so the visuals match.)

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

You can configure either or both tiers. If a player holds an ominous key for a crate that has only the normal tier configured, they'll see "This crate doesn't have an ominous tier. Try a normal key." 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 Wild Spawners 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 →**](/plugins/vault-crates/managing-keys.md) · [**The admin GUI →**](/plugins/vault-crates/admin-gui.md)
