Description
CannaTaleEconomy
CannaTaleEconomy is the economy backbone for the CannaTale Hytale server ecosystem. It provides a persistent SQLite-backed balance system, player and admin commands, a configurable paycheck system (including a VIP tier), and a public API that other mods can call.
Features
Core
- Persistent balances stored in SQLite (
economy.db) - Whole-number currency (
Long) to avoid floating point rounding issues - Atomic transfers using database transactions
- Leaderboard queries for
/baltop
Commands
- Player:
/balance,/baltop,/pay,/paycheck - Admin:
/money set|give|take(single permission node)
Paycheck System (VIP Override)
- Configurable interval and amounts
- VIP permission node:
cannatale.economy.vip - VIP players receive only
paycheckAmountVipwhen using/paycheck(normalpaycheckAmountis ignored)
Public API Hooks
- Other mods can call
EconomyApito read/modify balances, transfers, leaderboards, formatting, and paycheck claims - Intended to be called from the server thread (same as commands/events)
Installation
- Build the plugin jar (see Build section).
- Copy the non-plain jar from
build/libs/into your server mods folder (example:HytaleServer/mods/). - Start the server.
- On first run, Economy will generate its data files in the plugin data directory:
config.jsoneconomy.db
Configuration (config.json)
Economy creates config.json on first run.
Current config keys:
startingBalance(Long)
Starting balance for brand-new players.paycheckAmount(Long)
Default paycheck amount (non-VIP).paycheckAmountVip(Long)
VIP paycheck amount. Only used if player hascannatale.economy.vip.paycheckIntervalMinutes(Long)
Shared paycheck cooldown (minutes) for both tiers.balTopLimit(Int)
Number of entries shown in/baltop.schemaVersion(Int)
Internal version used for future migrations.
VIP behavior
If a player has cannatale.economy.vip, /paycheck pays only paycheckAmountVip and ignores paycheckAmount.
Permissions
Admin (all /money commands)
cannatale.economy.admin
VIP paycheck tier
cannatale.economy.vip
Commands
Root help
/economy/ec(alias)
Shows the formatted command list.
Player commands
/balance
Shows your balance.
/balance [player]
Shows another player's balance.
Examples:
/balance/balance Xion28080
/baltop
Shows the top balances (default top 10, configurable via balTopLimit).
Example:
/baltop
/pay <player> <amount>
Pays another player.
- Amount must be > 0
- Sender must have enough balance
- Transfer is atomic
Example:
/pay Bob 250
/paycheck
Claims your paycheck.
- Enforced by cooldown:
paycheckIntervalMinutes - VIP players receive
paycheckAmountViponly
Example:
/paycheck
If not ready, you will see a message showing the remaining time until the next claim.
Admin commands (require cannatale.economy.admin)
/money set <player> <amount>
Sets a player's balance.
/money give <player> <amount>
Adds to a player's balance.
/money take <player> <amount>
Removes from a player's balance (money is deleted, not transferred).
- Clamped at 0 (no negative balances)
Examples:
/money set Bob 1000/money give Bob 250/money take Bob 500
Online-player note (ArgTypes.PLAYER_REF)
Several commands use ArgTypes.PLAYER_REF, which typically resolves to online players:
/pay/money set|give|take/balance --player=<name>(if the argument is resolved as PLAYER_REF)
If you want offline support (setting/checking players who are not online), Economy can be extended to resolve UUIDs via a profile store or name→UUID cache.
Database
SQLite file:
economy.db
Schema (conceptual):
- Table
balancesuuid(TEXT PRIMARY KEY)name(TEXT)balance(INTEGER)last_paycheck_claim_ms(INTEGER)
Notes:
- Amounts are stored as integers (Long)
- Transfers use a transaction to avoid partial updates
Public API Hooks (Declared)
Where the API lives
Package:
org.omeganode.cannataleeconomy.api
Primary interface:
EconomyApi
Registry:
EconomyApiRegistry
How other mods obtain the API
import org.omeganode.cannataleeconomy.api.EconomyApiRegistry
val econ = EconomyApiRegistry.get() ?: return // Economy not loaded / not registered
EconomyApi — Methods and Hooks (exact)
All currency amounts are whole-number Long values.
Most methods accept nameForCreate so the account can be created on demand if missing.
package org.omeganode.cannataleeconomy.api
import org.omeganode.cannataleeconomy.data.EconomyConfig
import org.omeganode.cannataleeconomy.db.TopBalanceEntry
import org.omeganode.cannataleeconomy.services.PaycheckService
import java.util.UUID
interface EconomyApi {
fun getConfig(): EconomyConfig
fun ensure(uuid: UUID, nameForCreate: String)
/** Returns starting balance if the account doesn't exist (does NOT create an account). */
fun getBalance(uuid: UUID): Long
/** Returns balance and creates account if needed. */
fun getBalance(uuid: UUID, nameForCreate: String): Long
fun setBalance(uuid: UUID, nameForCreate: String, amount: Long)
fun give(uuid: UUID, nameForCreate: String, amount: Long)
/**
* Takes up to [amount] from the player's balance (clamped at 0).
* @return the new balance after the take.
*/
fun take(uuid: UUID, nameForCreate: String, amount: Long): Long
/**
* Transfers [amount] from one player to another.
* @return true if success, false if sender lacks funds or amount <= 0.
*/
fun transfer(fromUuid: UUID, fromName: String, toUuid: UUID, toName: String, amount: Long): Boolean
fun top(limit: Int): List<TopBalanceEntry>
/** Formats a number with commas using the server's locale rules used by Economy. */
fun format(amount: Long): String
/** Claim paycheck. If isVip=true, uses paycheckAmountVip only. */
fun claimPaycheck(uuid: UUID, nameForCreate: String, isVip: Boolean): PaycheckService.ClaimResult
}
API Examples for other mods
Read balance (no account creation)
val bal = econ.getBalance(playerUuid)
Read balance (create account if missing)
val bal = econ.getBalance(playerUuid, playerName)
Give / take / set
econ.give(playerUuid, playerName, 500)
val newBal = econ.take(playerUuid, playerName, 250)
econ.setBalance(playerUuid, playerName, 1000)
Transfer
val ok = econ.transfer(fromUuid, fromName, toUuid, toName, 200)
Leaderboard
val top = econ.top(10)
Formatting
val formatted = econ.format(1234567) // "1,234,567"
Paycheck claim (VIP-aware)
val isVip = sender.hasPermission("cannatale.economy.vip")
val result = econ.claimPaycheck(playerUuid, playerName, isVip)
Troubleshooting
SQLite driver error at runtime
If you see:
No suitable driver found for jdbc:sqlite:...
You likely deployed the wrong jar.
Fix:
- Deploy the non-plain jar from
build/libs/ - Remove older Economy jars from the server mods folder
- Restart the server


