> For the complete documentation index, see [llms.txt](https://docs.craftingtable.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.craftingtable.org/plugin-documentation/cubeeco.md).

# CubeEco

A modular, **unlimited‑currency** economy plugin for modern Minecraft servers. Define as many currencies as you like in simple YAML files — each gets its own command, leaderboard, withdrawable notes, tax rules, and formatting. CubeEco bridges to Vault, PlaceholderAPI, ShopGUI+, EconomyShopGUI, and Towny out of the box.

* **Version:** 1.1.0
* **Server:** Paper 1.21+ (Folia supported)
* **Java:** 21+
* **Storage:** SQLite (default), MySQL, or flat‑file YAML

## Features

* **Unlimited currencies** — every `.yml` file in `currencies/` becomes a fully‑featured currency.
* **Per‑currency commands** — `/<currency> balance | pay | withdraw | top`, registered at runtime.
* **Physical notes** — withdraw a balance into a right‑click‑to‑redeem item.
* **Leaderboards** — chat **and** chest‑GUI top lists, refreshed on a schedule.
* **Tax** — optional percentage + flat fee on payments, routed to void / a bank account / broadcast.
* **GUIs** — balance overview, leaderboard, and withdraw‑denomination menus.
* **Deep integrations** — Vault, PlaceholderAPI, ShopGUI+ (multi‑currency), EconomyShopGUI, Towny.
* **MiniMessage everywhere** — gradients, hover, colour, all configurable.
* **Async, cached storage** — balances are cached in memory and flushed off the main thread.
* **Hot reload** — add or edit currencies and reload without a restart (a couple of caveats below).

## Requirements

| Component       | Requirement                                                               |
| --------------- | ------------------------------------------------------------------------- |
| Server software | Paper **1.21+** (Spigot may work; Paper recommended). Folia is supported. |
| Java            | **21** or newer                                                           |
| PlaceholderAPI  | Optional — enables `%cubeeco_…%` placeholders                             |
| Vault           | Optional — exposes CubeEco as a Vault economy provider                    |
| ShopGUIPlus     | Optional — multi‑currency shop support                                    |
| EconomyShopGUI  | Optional — single‑currency shop support (via Vault)                       |
| Towny           | Optional — town/nation economy + join reward                              |

All third‑party plugins are **soft‑depends**: if one isn't installed, CubeEco starts normally and silently skips that integration. SQLite and MySQL drivers are bundled inside the jar — nothing extra to install.

## Installation

{% stepper %}
{% step %}

## Get the jar

**Download** the latest `CubeEco-<version>.jar`, **or build it yourself:**

```bash
git clone https://github.com/bumpier/CubeEco.git
cd CubeEco
mvn package
```

The built plugin is written to `target/CubeEco-1.1.0.jar`. (Ignore `original-CubeEco-1.1.0.jar` — that's the un‑shaded copy without the bundled database drivers.)
{% endstep %}

{% step %}

## Install

1. Stop your server.
2. Drop `CubeEco-1.1.0.jar` into your server's `plugins/` folder.
3. Start the server. CubeEco generates its config and a default `emeralds` currency on first run.
4. (Optional) Install PlaceholderAPI / Vault / ShopGUI+ / EconomyShopGUI / Towny to enable those integrations, then restart.
   {% endstep %}

{% step %}

## File layout

After first run:

```
plugins/CubeEco/
├── config.yml            # main settings
├── messages.yml          # all player-facing text (MiniMessage)
├── database.db           # SQLite data (only when storage.backend: sqlite)
├── balances.yml          # flat-file data (only when storage.backend: yaml)
├── transactions.log      # human-readable log (only when logging.log-to-file: true)
└── currencies/
    └── emeralds.yml       # bundled example currency
```

{% endstep %}
{% endstepper %}

## Quick Start

{% stepper %}
{% step %}

## Start the server

Start the server once to generate the files above.
{% endstep %}

{% step %}

## Edit a currency

Open `currencies/emeralds.yml` and tweak the name, symbol, command, and caps to taste — or copy it to `currencies/coins.yml` to make a second currency.
{% endstep %}

{% step %}

## Reload

Run `/cubeeco admin reload` (or restart) to apply changes.
{% endstep %}

{% step %}

## Give yourself currency

Give yourself some currency: `/cubeeco admin give <you> emeralds 1000`.
{% endstep %}

{% step %}

## Test it

Check it: `/emerald balance` — and try `/emerald top`, `/emerald withdraw`, `/cubeeco`.
{% endstep %}
{% endstepper %}

## Configuration — `config.yml`

```yaml
storage:
  # Options: yaml, sqlite, mysql
  backend: sqlite

  mysql:
    host: localhost
    port: 3306
    database: cubeeco
    username: root
    password: ""
    pool-size: 10
    use-ssl: false

# The currency that backs the Vault economy provider.
# Must match a file name (without .yml) in /currencies/
vault-currency: "emeralds"

# If true, players sitting at 0 still appear on leaderboards.
leaderboard-show-zero: false

# How often leaderboard snapshots refresh, in seconds (min 30).
leaderboard-refresh-interval: 300

cache:
  # How often dirty balances are flushed to storage for online players (seconds).
  flush-interval: 60

# GUI sounds (vanilla enum names). Leave a value blank to silence it.
gui:
  open-sound: "UI_BUTTON_CLICK"
  success-sound: "ENTITY_PLAYER_LEVELUP"
  error-sound: "ENTITY_VILLAGER_NO"

logging:
  # Record every transaction to the ce_transactions table (SQL backends only).
  log-transactions: true
  # Also append a human-readable line to a file.
  log-to-file: false
  log-file: "transactions.log"

towny:
  enabled: true
  # Informational only — Towny actually charges the vault-currency through Vault.
  # Set vault-currency to this same currency for consistency.
  bank-currency: "emeralds"
  join-reward:
    enabled: false
    currency: "emeralds"
    amount: 100.0
```

| Key                            | Purpose                                                                    |
| ------------------------------ | -------------------------------------------------------------------------- |
| `storage.backend`              | `sqlite` (default), `mysql`, or `yaml`. **Changing this needs a restart.** |
| `storage.mysql.*`              | Connection details when `backend: mysql`.                                  |
| `vault-currency`               | Which currency Vault‑aware plugins (and EconomyShopGUI / Towny) use.       |
| `leaderboard-show-zero`        | Show players with a 0 balance on leaderboards.                             |
| `leaderboard-refresh-interval` | Seconds between leaderboard snapshot refreshes (minimum 30).               |
| `cache.flush-interval`         | Seconds between background flushes of changed balances to storage.         |
| `gui.*-sound`                  | Sounds for opening GUIs, successful actions, and errors.                   |
| `logging.log-transactions`     | Write each transaction to the `ce_transactions` table (SQL only).          |
| `logging.log-to-file`          | Also append a readable line to `logging.log-file`.                         |
| `towny.enabled`                | Master switch for the Towny join‑reward feature.                           |
| `towny.join-reward`            | Grant new town residents a currency reward (off by default).               |

## Creating Currencies

Every `.yml` file in `plugins/CubeEco/currencies/` is loaded as an independent currency. The **file name** (without `.yml`) is the currency's `id` — used for permissions and placeholders. To add a currency, copy `emeralds.yml`, rename it, edit it, and run `/cubeeco admin reload`.

Here is the bundled `emeralds.yml`, annotated:

```yaml
# Display name (MiniMessage) + singular/plural forms used in messages.
name: "<green>Emeralds"
name-singular: "Emerald"
name-plural: "Emeralds"

# Symbol shown in formatted balances, and where it sits (prefix | suffix).
symbol: "E"
symbol-position: prefix

# Primary command + aliases. Defaults to the file name if omitted.
command: "emerald"
command-aliases:
  - "em"

# Starting balance for brand-new players.
starting-balance: 0.0

# Caps. Set max-balance to -1 for unlimited. allow-negative permits debt.
max-balance: 1000000000.0
allow-negative: false

features:
  pay:
    enabled: true
    permission: "cubeeco.emeralds.pay"   # optional override of the default node
    min-amount: 1.0
    max-amount: 1000000.0
    cooldown: 0                            # seconds between payments (0 = none)
    allow-offline: false                   # allow paying offline players

  balance:
    enabled: true
    check-others: true
    permission-check-others: "cubeeco.emeralds.balance.others"

  withdraw:
    enabled: true
    permission: "cubeeco.emeralds.withdraw"
    item:
      material: EMERALD
      name: "<green><bold>Emerald Note"
      lore:
        - "<gray>Worth: <white><amount></white> Emeralds"
        - ""
        - "<yellow>Right-click to redeem!"
      custom-model-data: 0                 # for resource packs (0 = off)
      glowing: true
    # GUI buttons. "custom" lets the player type any amount in chat.
    denominations: [1, 10, 100, 1000, 10000, custom]

  top:
    enabled: true
    entries-per-page: 10

leaderboard:
  type: both            # chat | gui | both
  size: 100             # number of ranked players tracked
  chat:
    per-page: 10
  gui:
    title: "<gradient:#00c9ff:#92fe9d>Emerald Leaderboard</gradient>"
    rows: 6
    entry-slots: [10,11,12,13,14,15,16,19,20,21,22,23,24,25,28,29,30,31,32,33,34]
    entry-item:
      name: "<yellow>#<rank> <white><player>"
      lore:
        - "<gray>Balance: <white><balance>"
    filler:
      enabled: true
      material: BLACK_STAINED_GLASS_PANE
    prev-page-slot: 45
    next-page-slot: 53
    close-slot: 49

tax:
  enabled: false
  rate: 5.0             # percent of the payment
  destination: void     # void | bank | broadcast
  bank-player: ""        # player name/UUID that receives tax when destination: bank
  flat-fee: 0.0          # flat amount added on top of the percentage

formatting:
  style: compact         # full | compact | symbol-compact
  compact-decimals: 1
  thousands-separator: ","
  decimal-separator: "."
```

{% hint style="info" %}
Placeholders inside an item's `name`/`lore` such as `<amount>` are replaced when a note is created. Display text supports the full MiniMessage syntax (gradients, hover, etc.).
{% endhint %}

{% hint style="info" %}
If a currency file has a missing or invalid field, CubeEco logs a warning and falls back to a safe default rather than failing to load. A malformed currency never crashes the plugin.
{% endhint %}

## Number Formatting

Each currency's `formatting.style` controls how balances appear:

| Style            | Example (1,234,567) | Notes                                                                                 |
| ---------------- | ------------------- | ------------------------------------------------------------------------------------- |
| `full`           | `1,234,567`         | Grouped digits using your `thousands-separator` / `decimal-separator`.                |
| `compact`        | `1.2M`              | Suffixes K, M, B, T. `compact-decimals` sets decimal places; trailing zeros stripped. |
| `symbol-compact` | `E1.2M`             | Compact plus the currency `symbol` (prefix or suffix).                                |

Compact values round **down** (so a balance never displays as more than the player has). Regardless of the chosen style, PlaceholderAPI still exposes every format individually (see [PlaceholderAPI](#placeholderapi)).

## Commands

In the tables below, `<currency>` is a currency's configured command (e.g. `emerald` for `emeralds.yml`) plus any aliases, and `<id>` is its file name (e.g. `emeralds`).

### Per‑currency commands

| Command                              | Permission                                              | Description                                           |
| ------------------------------------ | ------------------------------------------------------- | ----------------------------------------------------- |
| `/<currency>`                        | `cubeeco.<id>.balance`                                  | Show your own balance (shorthand for `balance`)       |
| `/<currency> balance [player]`       | `cubeeco.<id>.balance` (+ `.balance.others` for others) | Show a balance                                        |
| `/<currency> pay <player> <amount>`  | `cubeeco.<id>.pay`                                      | Pay another player (tax applies if enabled)           |
| `/<currency> withdraw [amount\|gui]` | `cubeeco.<id>.withdraw`                                 | Withdraw a note; no amount opens the denomination GUI |
| `/<currency> top [page\|gui]`        | `cubeeco.<id>.top`                                      | Leaderboard, in chat or as a head GUI                 |

Aliases: `balance` → `bal`, `withdraw` → `wd`, `top` → `baltop`, `leaderboard`.

### Base command — `/cubeeco`

Aliases: `/currencies`, `/ceco`.

| Command                                            | Permission      | Description                                                    |
| -------------------------------------------------- | --------------- | -------------------------------------------------------------- |
| `/cubeeco`                                         | `cubeeco.use`   | Open the Balance Overview GUI (players); help text for console |
| `/cubeeco list`                                    | `cubeeco.use`   | List loaded currencies                                         |
| `/cubeeco help`                                    | `cubeeco.use`   | Show help                                                      |
| `/cubeeco admin give <player> <currency> <amount>` | `cubeeco.admin` | Add balance                                                    |
| `/cubeeco admin take <player> <currency> <amount>` | `cubeeco.admin` | Remove balance                                                 |
| `/cubeeco admin set <player> <currency> <amount>`  | `cubeeco.admin` | Set balance to an exact value                                  |
| `/cubeeco admin reset <player> <currency>`         | `cubeeco.admin` | Reset a player to the starting balance                         |
| `/cubeeco admin resetall <currency>`               | `cubeeco.admin` | Reset **every** player                                         |
| `/cubeeco admin bulkgive <currency> <amount>`      | `cubeeco.admin` | Give to all online players                                     |
| `/cubeeco admin reload`                            | `cubeeco.admin` | Reload config, messages, and currencies                        |
| `/cubeeco admin info <currency>`                   | `cubeeco.admin` | Print a currency's config summary                              |

Admin `give`/`take`/`set`/`reset` work on **offline** players too (they're loaded, updated, and saved in the background).

## Permissions

Replace `<id>` with a currency's file name (e.g. `emeralds`).

| Node                          | Default | Grants                                                    |
| ----------------------------- | ------- | --------------------------------------------------------- |
| `cubeeco.use`                 | `true`  | `/cubeeco` overview GUI, `/cubeeco list`, `/cubeeco help` |
| `cubeeco.admin`               | `op`    | Every `/cubeeco admin …` subcommand                       |
| `cubeeco.<id>.balance`        | `true`  | Check your own `<id>` balance                             |
| `cubeeco.<id>.balance.others` | `op`    | Check another player's `<id>` balance                     |
| `cubeeco.<id>.pay`            | `true`  | Send `<id>` payments                                      |
| `cubeeco.<id>.withdraw`       | `true`  | Withdraw `<id>` as physical notes                         |
| `cubeeco.<id>.top`            | `true`  | View the `<id>` leaderboard (chat + GUI)                  |

* `cubeeco.use` and `cubeeco.admin` are declared in `plugin.yml`. The per‑currency nodes are registered programmatically at startup and re‑registered on `/cubeeco admin reload`.
* **Overrides:** a currency file may set its own permission string for `pay`, `balance.others`, and `withdraw` (the `permission` / `permission-check-others` keys). When set, that custom node replaces the `cubeeco.<id>.*` default for that feature.

## Withdraw Notes

A withdraw note is a physical item carrying a fixed amount of a currency.

**Creating one:**

* `/<currency> withdraw <amount>` — instantly withdraws that amount as a note.
* `/<currency> withdraw` (or `/<currency> withdraw gui`) — opens the **denomination GUI** with one button per value in the currency's `denominations` list. A `custom` entry lets the player type any amount in chat.

The balance is deducted when the note is created, and the note's name/lore come from the currency's `withdraw.item` config (with `<amount>` substituted). Notes can carry custom model data for resource packs and can be made to glow.

**Redeeming one:** hold the note and **right‑click**. The amount is credited back and the item is consumed. If the currency was deleted in the meantime, the player is told the note is invalid.

## Leaderboards

* Each currency tracks the top `leaderboard.size` players.
* Snapshots refresh every `leaderboard-refresh-interval` seconds (`config.yml`) and on demand when a player runs `/<currency> top` and the data is stale.
* `leaderboard.type` chooses how `/<currency> top` renders by default:
  * `chat` — paginated chat list
  * `gui` — chest GUI of player heads
  * `both` — GUI for players, chat for console (players can force chat with a page number, or the GUI with `gui`).
* Players at 0 are hidden unless `leaderboard-show-zero: true`.

## GUIs

| GUI                        | Opened by                    | Behaviour                                                                                |
| -------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------- |
| **Balance Overview**       | `/cubeeco`                   | One item per currency showing your balance. Click a currency to open its leaderboard.    |
| **Leaderboard**            | `/<currency> top` (GUI mode) | Player heads ranked by balance, with prev/next/close buttons. Fully styled per currency. |
| **Withdraw Denominations** | `/<currency> withdraw`       | One button per configured denomination; `custom` prompts for a chat amount.              |

Items can't be moved or dragged out of CubeEco GUIs. Open/success/error sounds are configurable in `config.yml`.

## Tax System

Tax applies **only to `/pay`** and is configured per currency under `tax`:

```yaml
tax:
  enabled: true
  rate: 5.0            # percent of the gross amount
  flat-fee: 0.0         # added on top
  destination: void     # void | bank | broadcast
  bank-player: ""        # required when destination: bank
```

* **Formula:** `tax = (amount × rate / 100) + flat-fee`.
* The **sender pays the full amount**; the **recipient receives `amount − tax`**.
* **Destinations:**
  * `void` — tax is removed from circulation.
  * `bank` — tax is credited to `bank-player`.
  * `broadcast` — tax is removed and a server‑wide message announces it.

The sender's confirmation shows both the amount sent and the tax deducted.

## PlaceholderAPI

Identifier: **`cubeeco`**. Install PlaceholderAPI to use these. `<id>` is the currency file name; `<n>` is a 1‑based leaderboard position.

| Placeholder                                | Output                                                      |
| ------------------------------------------ | ----------------------------------------------------------- |
| `%cubeeco_<id>_balance%`                   | Raw balance (e.g. `15230.5`)                                |
| `%cubeeco_<id>_balance_formatted%`         | Full, grouped (e.g. `15,230`)                               |
| `%cubeeco_<id>_balance_compact%`           | Compact (e.g. `15.2K`)                                      |
| `%cubeeco_<id>_balance_symbol%`            | Symbol + compact (e.g. `E15.2K`)                            |
| `%cubeeco_<id>_rank%`                      | Player's leaderboard rank (`-` if outside the cached top‑N) |
| `%cubeeco_<id>_top_<n>_name%`              | Name of player #n                                           |
| `%cubeeco_<id>_top_<n>_balance%`           | Raw balance of #n                                           |
| `%cubeeco_<id>_top_<n>_balance_formatted%` | Full balance of #n                                          |

{% hint style="info" %}
Balances read from the live cache, so **offline players resolve to `0`**. Rank and `top_<n>` placeholders read from the cached leaderboard snapshot.
{% endhint %}

## Integrations

All integrations are soft‑depends — missing plugins are skipped silently.

### Vault

CubeEco registers a Vault `Economy` provider (at `Highest` priority) backed by the currency named in `config.yml` → `vault-currency`. Any Vault‑aware plugin then reads and charges that single currency. This is the bridge that powers EconomyShopGUI and Towny.

### ShopGUI+ (multi‑currency)

ShopGUI+ is the one shop plugin where **every** CubeEco currency is usable independently. On ShopGUI+ post‑enable, CubeEco registers one custom economy provider per currency, named `cubeeco_<id>`.

```yaml
# In a ShopGUI+ shop file:
economy-type: CUSTOM
economy-type-custom: cubeeco_emeralds
```

{% hint style="warning" %}
**Reload caveat:** providers are registered once, at ShopGUI+ post‑enable, for the currencies loaded then. Adding a currency and running `/cubeeco admin reload` does **not** retroactively register it with ShopGUI+ — that needs a restart (or a ShopGUI+ reload that re‑fires its post‑enable event).
{% endhint %}

### EconomyShopGUI (via Vault)

EconomyShopGUI has no custom‑provider API. Point its economy provider at `Vault`; its shops then transact against CubeEco's `vault-currency` (single currency only).

### Towny (via Vault + join reward)

Towny's core economy (town/nation banks, plot claims, taxes) runs through Vault — leave Towny on its Vault economy and set CubeEco's `vault-currency` to the currency you want Towny to use. CubeEco adds an optional **join reward** on top:

```yaml
towny:
  enabled: true
  join-reward:
    enabled: true
    currency: "emeralds"
    amount: 100.0
```

## Storage Backends

| Backend              | When to use            | Notes                                                   |
| -------------------- | ---------------------- | ------------------------------------------------------- |
| `sqlite` *(default)* | Single server          | Stored in `database.db`. Driver bundled.                |
| `mysql`              | Networks / shared data | Configure `storage.mysql.*`. Driver + HikariCP bundled. |
| `yaml`               | Tiny servers / testing | Stored in `balances.yml`. **No transaction log.**       |

* Balances are cached in memory; reads/writes hit the cache and are flushed asynchronously every `cache.flush-interval` seconds and on quit.
* SQL backends use the tables `ce_balances` and (when `log-transactions: true`) `ce_transactions`.
* **Switching `storage.backend` requires a restart** (it is not hot‑reloadable) and does not migrate existing data between backends.

## Reloading

`/cubeeco admin reload`:

1. Re‑reads `config.yml` and `messages.yml`.
2. Rescans `currencies/` for new, changed, or removed files.
3. Unregisters commands/permissions for removed currencies and registers them for new ones.
4. Flushes dirty cache entries to storage.
5. Refreshes leaderboard snapshots.
6. Reports the currency count and elapsed time.

**Not** hot‑reloadable (require a restart):

* The **storage backend** (`storage.backend`).
* **ShopGUI+ economy providers** (registered once at ShopGUI+ post‑enable).

## Customising Messages

All player‑facing text lives in `messages.yml` and supports **MiniMessage** (colours, `<gradient>`, `<hover>`, etc.) plus PlaceholderAPI. Each message exposes context tokens like `<player>`, `<currency>`, `<amount>`, `<balance>`, `<tax>`, `<rank>`, and `<page>`. The `prefix` value is prepended to most messages.

```yaml
prefix: "<green><bold>CubeEco</bold></green> <dark_gray>»</dark_gray> "
balance-self: "<gray>Your <white><currency></white> balance is <white><balance></white>."
pay-sent: "<gray>You paid <white><player></white> <white><amount></white> <white><currency></white>. (Tax: <white><tax></white>)"
```

Edit the values, keep the `<tokens>` intact, and run `/cubeeco admin reload`.

## Troubleshooting

| Symptom                                              | Fix                                                                                                        |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Per‑currency command doesn't exist                   | Currency failed to load — check console for a warning, fix the `.yml`, then `/cubeeco admin reload`.       |
| New currency missing from ShopGUI+                   | ShopGUI+ providers register only at its post‑enable. **Restart** the server.                               |
| Balances not saving                                  | Confirm `storage.backend` and (for MySQL) the connection details; check console for DB errors.             |
| Placeholders show literally                          | Install PlaceholderAPI; confirm the `<id>` matches the currency file name.                                 |
| `%cubeeco_<id>_balance%` is `0` for an online player | The cache may still be loading right after join; it resolves momentarily. Offline players always read `0`. |
| Vault plugins use the wrong currency                 | Set `vault-currency` to the desired currency id and restart.                                               |
| Changed `storage.backend` did nothing                | Backend changes need a restart and do not migrate existing data.                                           |
