Kits

Configurable item kits with per-kit cooldowns, one-time claims, max-claim caps, first-join auto-give, and optional cross-server sync.

Overview

Kits are defined in kits.yml and tracked in a dedicated SQLite database (kits.db). Each kit stores a claim history per player — last claimed timestamp and a running claim count — so cooldowns, one-time limits, and max-claim caps all work independently per kit.

Kit permissions are registered at startup from the names defined in kits.yml, so you don't have to manually add them to plugin.yml. Every kit gets an auto-generated node: essentialsc.kit.<name>.

Commands

/kit
List all kits you have access to, with a ready/on-cooldown indicator next to each one.
/kit <name>
Shorthand for claiming a kit directly by name. Equivalent to /kit claim <name>.
/kit claim <name>
Claim a kit. Checks permission, one-time status, max-claims, and cooldown before giving items. Overflow items are dropped at the player's feet.
/kit cooldown <name>
Check how long until a specific kit is claimable again. Respects network-sync if enabled.
/kit debug <name>
Print kit internals: permission node, item count, cooldown, one-time flag, first-join flag, network-sync flag, and max-claims. Requires essentialsc.kits.admin.
/kits
Alias for /kit — shows the available kit list.

kits.yml Structure

All kits live under the kits: root key. Each entry's YAML key becomes the kit's internal name (lowercased).

kits:
  starter:
    # Display name — supports full MiniMessage formatting.
    display-name: "<green>Starter Kit"

    # Optional description shown in the kit list or editor.
    description: "Gear for new players."

    # Cooldown in seconds between claims. 0 = no cooldown.
    cooldown: 86400

    # If true, the kit can only ever be claimed once per player.
    one-time: false

    # If true, the kit is given automatically to players on their very first join.
    first-join: false

    # Maximum total times a player can claim this kit. 0 = unlimited.
    max-claims: 0

    # If true, cooldown is enforced across all servers via the MySQL Expansion.
    network-sync: false

    items:
      - type: IRON_SWORD
        amount: 1
        name: "<gray>Iron Sword"
        lore:
          - "<dark_gray>From the Starter Kit"
        enchantments:
          sharpness: 2
          unbreaking: 3
        flags:
          - HIDE_ENCHANTS
        unbreakable: false
        custom-model-data: 0

      - type: BREAD
        amount: 16
Reloading Run /essc reload after editing kits.yml. This clears the in-memory cache and re-reads the file. Online players have their kit data reloaded automatically.

Item Properties

Every entry in a kit's items list supports the following fields. Only type is required; everything else is optional.

type required
Bukkit material name, e.g. DIAMOND_SWORD, GOLDEN_APPLE. Case-insensitive.
amount
Stack size. Capped automatically at the material's max stack size. Defaults to 1.
name
Custom item display name. Full MiniMessage formatting supported. Italic is stripped automatically.
lore
List of lore lines. Each line is a MiniMessage string. Italic is stripped automatically.
enchantments
Map of enchantment name to level. Names are the Bukkit enum names (e.g. sharpness, protection). Unsafe levels are allowed.
flags
List of ItemFlag names to apply, e.g. HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_UNBREAKABLE.
unbreakable
Set to true to make the item unbreakable. Defaults to false.
custom-model-data
Integer custom model data value for resource pack compatibility.
nbt
Map of key-value pairs written to the item's PersistentDataContainer. Supported value types: string, integer, double, and long.

Permissions

Kit Access

Each kit gets an auto-registered permission node based on its name. The default is op — grant it to the relevant group in LuckPerms to make kits available to players.

essentialsc.kit.<name> op
Access to claim the named kit. Generated automatically for every kit in kits.yml.

Admin & Bypass

essentialsc.kits.admin op
Bypasses cooldowns, one-time limits, and max-claim caps. Unlocks /kit debug and /kiteditor. Also grants access to all kits regardless of individual kit permissions.
essentialsc.kits.networksync.bypass op
Skips the cross-server cooldown check for network-synced kits, falling back to local cooldown only.

LuckPerms Example

# Grant the "vip" kit to all members
/lp group default permission set essentialsc.kit.starter true

# Grant a VIP-exclusive kit
/lp group vip permission set essentialsc.kit.vip true

# Give staff full kit admin access
/lp group staff permission set essentialsc.kits.admin true

Claiming Rules

When a player runs /kit claim <name>, these checks run in order:

1

Permission

The player must have essentialsc.kit.<name> or essentialsc.kits.admin.

2

One-time check

If one-time: true, the kit is blocked once the player's claim count is greater than zero.

3

Max-claims check

If max-claims is set above zero, the player is blocked once their claim count reaches that cap.

4

Cooldown check

If cooldown is greater than zero and the player doesn't have essentialsc.kits.admin, the remaining time is checked. For network-synced kits, the cross-server cooldown is fetched asynchronously and the maximum of local vs network is applied.

5

Give items

Items are added to the player's inventory. Any overflow (full inventory) is dropped naturally at their feet. The claim is written to SQLite and the in-memory cache is updated.

First-Join Kits

Any kit with first-join: true is automatically given when a player joins for the very first time (checked via Player#hasPlayedBefore()). Cooldown and claim limits still apply going forward.

Network Sync

Setting network-sync: true on a kit causes cooldowns to be enforced across all servers on the network, not just the one the player is currently connected to. This requires the EssentialsC MySQL Expansion to be installed and configured.

When a player claims a network-synced kit, the timestamp is written to the shared network_kit_cooldowns table. On the next claim attempt (on any server), both the local cooldown and the network cooldown are fetched, and the larger remaining value is used.

Without the MySQL Expansion If network-sync: true is set but no network hook is registered, the kit falls back to local-only cooldown enforcement. No errors are thrown.
kits:
  weekly:
    display-name: "<gold>Weekly Kit"
    cooldown: 604800   # 7 days in seconds
    network-sync: true
    items:
      - type: GOLDEN_APPLE
        amount: 8

Database

Kit claim history is stored in plugins/EssentialsC/database/kits.db. The schema is a single table:

CREATE TABLE kit_claims (
    uuid         TEXT    NOT NULL,
    kit_name     TEXT    NOT NULL,
    last_claimed INTEGER DEFAULT 0,
    claim_count  INTEGER DEFAULT 0,
    PRIMARY KEY (uuid, kit_name)
)

Player data is loaded into memory on join and flushed from cache on quit. Claims are written asynchronously to avoid blocking the main thread.

Backing up kits is as simple as copying kits.db and kits.yml while the server is stopped.

Troubleshooting

"You don't have permission to claim this kit"
Grant essentialsc.kit.<name> via LuckPerms. Kit permissions default to op-only.

"You have already claimed this kit"
The kit has one-time: true and the player has already claimed it once. This is permanent and cannot be reset short of deleting the record from kits.db.

"You have reached the maximum number of claims"
The player hit max-claims. Grant essentialsc.kits.admin to bypass, or increase the cap in kits.yml.

Cooldown is longer than expected on a network-synced kit
The network cooldown from another server is higher than the local one. This is expected behavior. The larger of the two values always wins.

Kit items not loading / "Invalid material" in console
Check the type field. Material names must match Bukkit's enum exactly (e.g. GOLDEN_APPLE, not golden apple). Run /kit debug <name> to see the actual item count loaded.

First-join kit not given
Ensure first-join: true is set and the player genuinely hasn't played before. Player#hasPlayedBefore() returns true if any data files exist for that UUID, including from other plugins.