Skip to main content

Nexal Taxes

A tax system for Minecraft servers: land taxes on GriefPrevention claims, wealth taxes with progressive brackets, a government treasury, debt with optional interest, evasion detection on money transfers, and cron-scheduled collections.

Features​

  1. Land Ownership Tax - Tax per claimed block via GriefPrevention, with free blocks before taxing starts
  2. Wealth Tax - Tax on the balance above a threshold, with progressive brackets
  3. Government Treasury - Every collected tax goes into a central account that admins can deposit into and withdraw from
  4. Tax Debt - Unpaid taxes become debt (or are dropped, in "collect" mode). Debt can carry daily interest, is paid with /tax pay, and can be deducted automatically at the next collection when the player has money left
  5. Max Debt Actions - Warn the player, run commands, and optionally block money transfers once a player's debt reaches the limit
  6. Tax Evasion Detection - Watches transfer commands such as /pay and alerts admins about large transfers and rapid series of transfers
  7. Cron Scheduling - Collections on any cron schedule, in a configurable timezone
  8. Offline Collection - Taxes are also collected from offline players
  9. Tax Exemptions - Exempt players by command, or by the nexaltaxes.exempt permission (also honoured while the player is offline)
  10. Tax History GUI - Players browse their payment history
  11. Admin Panel - /tax admin opens a hub with the settings screen, a dashboard (treasury, debt, top taxpayers, evasion alerts), forced collection, export and import
  12. PlaceholderAPI Support - 13 placeholders for tax stats and treasury information
  13. Dual Storage - JSON or MySQL/MariaDB, with export and import to migrate between them

Technologies​

  • Java 17 with Paper API 1.20.1, Spigot compatible
  • nexal-core for storage (JSON and SQL) and the help menu
  • Utilizer for config, messages, tasks, and GUIs
  • ACF (Aikar Command Framework) for commands
  • cron4j for scheduling
  • Vault for economy integration
  • GriefPrevention for land claim tracking (optional)
  • PlaceholderAPI for placeholders (optional)

Commands​

Player Commands​

CommandPermissionDescription
/tax or /tax help [page]nexaltaxes.useShow the help menu
/tax infonexaltaxes.useShow your estimated taxes, balance, debt and the next collection
/tax historynexaltaxes.historyOpen your tax history GUI
/tax pay [amount]nexaltaxes.payPay off your tax debt (all of it, or the amount given)

/taxes is an alias of /tax.

Admin Commands​

CommandPermissionDescription
/tax adminnexaltaxes.adminOpen the admin panel (the console gets the admin help)
/tax admin help [page]nexaltaxes.adminShow the admin commands
/tax admin alertsnexaltaxes.adminOpen the dashboard: treasury, debt, top taxpayers and evasion alerts
/tax admin exempt \<player>nexaltaxes.adminToggle a player's tax exemption
/tax admin treasurynexaltaxes.adminShow the treasury balance, total collected, last and next collection
/tax admin treasury withdraw \<amount>nexaltaxes.adminWithdraw from the treasury to your balance
/tax admin treasury deposit \<amount>nexaltaxes.adminDeposit from your balance into the treasury
/tax admin collectnexaltaxes.adminCollect taxes from everyone now
/tax admin reloadnexaltaxes.adminReload config.yml and messages.yml
/tax admin exportnexaltaxes.adminExport all data to plugins/NexalTaxes/export/
/tax admin importnexaltaxes.adminImport the files in plugins/NexalTaxes/export/

Admin Panel​

/tax admin opens a hub with:

  • Configuration - The settings screen, grouped into Collection (schedule, timezone, offline collection, treasury), Taxes (land and wealth rates), Debt (mode, max debt, interest, automatic deduction, max debt actions) and Evasion Detection (alerts and thresholds). Changes are saved to config.yml at once. Wealth brackets are shown there but edited in config.yml.
  • Dashboard - Treasury, debt overview, statistics, the top five taxpayers and the unresolved evasion alerts. Click an alert to resolve it.
  • Treasury - Balance, total collected, last and next collection.
  • Collect Now, Export Data and Import Data.

Permissions​

PermissionDescriptionDefault
nexaltaxes.useView tax info and statustrue
nexaltaxes.historyView personal tax historytrue
nexaltaxes.payPay off tax debttrue
nexaltaxes.exemptExempt from all taxesfalse
nexaltaxes.adminAccess to admin commands and the admin panelop
nexaltaxes.alertsReceive evasion alertsop

Permissions cannot be read for offline players, so for collections from offline players the plugin uses whether the player had nexaltaxes.exempt when they last left the server. A permission granted while the player is offline takes effect once they have joined and left again.

How a Collection Works​

At each scheduled collection (or /tax admin collect), for every player who is not exempt:

  1. Interest - With debt-interest above 0, existing debt grows by that daily percentage for the time since the player's previous collection.
  2. Taxes - Land tax (claimed blocks above the free blocks, times the cost per block; for offline players, the claimed blocks counted when they last joined or left) and wealth tax (by bracket) are taken from the balance. If the balance does not cover them, what is missing becomes debt in debt mode, or is dropped in collect mode.
  3. Older debt - With auto-deduct on, debt from earlier collections is paid from whatever balance is left. It is on by default.
  4. Max debt - When the debt grew and has reached max-debt, the max debt actions run.

Everything collected goes into the treasury (when enabled) and appears in the player's history.

Evasion Detection​

The commands in transfer-commands (by default /pay and /epay, with or without a namespace such as /essentials:pay) are watched. A transfer counts once the sender's balance has actually dropped, so refused transfers are ignored, and it works with any economy plugin whose pay command takes \<player> \<amount>.

  • A single transfer of at least large-transfer-alert raises a Large Transfer alert.
  • rapid-transfer-threshold transfers within rapid-transfer-window seconds raise a Rapid Transfers alert.

Alerts are logged, stored, shown on the dashboard and, with alert-admins, sent to online players with nexaltaxes.alerts.

Placeholders​

Requires PlaceholderAPI. The identifier is nexaltaxes.

PlaceholderDescription
%nexaltaxes_debt%Player's current tax debt
%nexaltaxes_total_paid%Player's lifetime taxes paid
%nexaltaxes_has_debt%Whether player has debt (true/false)
%nexaltaxes_is_exempt%Whether player is exempted by an admin (true/false)
%nexaltaxes_land_blocks%Player's claimed land blocks
%nexaltaxes_estimated_land_tax%Estimated land tax for next collection
%nexaltaxes_estimated_wealth_tax%Estimated wealth tax for next collection
%nexaltaxes_estimated_total_tax%Total estimated tax
%nexaltaxes_treasury_balance%Government treasury balance
%nexaltaxes_treasury_total%Total taxes ever collected
%nexaltaxes_next_collection%Next collection date/time
%nexaltaxes_total_taxpayers%Total registered taxpayers
%nexaltaxes_unresolved_alerts%Number of unresolved evasion alerts

Configuration​

config.yml​

# Storage configuration
storage:
type: json # json or sql
sql:
host: localhost
port: 3306
database: minecraft
username: root
password: ""

# Timezone the collection schedule runs in and times are shown in
timezone: "UTC"

# Cron expression for tax collection, in the timezone above
# Examples:
# "0 0 * * *" - Daily at midnight
# "0 */6 * * *" - Every 6 hours
# "0 0 * * 0" - Weekly on Sunday
collection-schedule: "0 0 * * *"

# Treasury settings
treasury:
enabled: true
starting-balance: 0.0

# Debt handling
debt-handling:
mode: debt # "debt" or "collect"
max-debt: 100000.0
debt-interest: 0.0 # daily %, 0 = off
auto-deduct: true # pay older debt from what is left at each collection
max-debt-actions:
warn: true
block-economy: false # block the transfer-commands for players at max debt
commands: [] # placeholders: %player%, %debt%, %uuid%

# How long history is kept; 0 keeps everything (the default)
retention:
tax-records-days: 0
resolved-alerts-days: 0 # unresolved alerts are always kept

# Collect from offline players
collect-offline: true

# Commands that send money as /\<command> \<player> \<amount>
transfer-commands:
- pay
- epay

# Tax settings
taxes:
land:
enabled: true
cost-per-block: 0.01
grace-blocks: 100

wealth:
enabled: true
threshold: 10000.0
brackets:
- max: 50000
rate: 1.0
- max: 100000
rate: 2.0
- max: -1
rate: 3.0

# Evasion detection (watches transfer-commands)
evasion-detection:
enabled: true
alert-admins: true
rapid-transfer-threshold: 5
rapid-transfer-window: 60
large-transfer-alert: 50000.0

messages.yml​

Every message is customizable in MiniMessage format (gradients, hex colors), with optional sounds and titles. The colors are listed at the top of the file for find-and-replace. Messages added in an update are used from the plugin's defaults until you add them to your file. time-unknown, time-never and unknown-player set the texts shown when the next collection is not scheduled, before the first collection, and for a player whose name is not known.

Database Schema​

With storage.type: sql these tables are created. With JSON the same collections are kept in plugins/NexalTaxes/data.json.

tax_payers​

ColumnTypeDescription
idVARCHAR(36)Player UUID (Primary Key)
nameVARCHAR(16)Player name
totalPaidDOUBLELifetime taxes paid
debtDOUBLECurrent unpaid debt
landBlocksINTCached land block count
lastCollectionBIGINTLast collection timestamp
exemptBOOLEANExempted by an admin
permissionExemptBOOLEANHad nexaltaxes.exempt when last online

tax_records​

ColumnTypeDescription
idVARCHAR(36)Record UUID (Primary Key)
player_idVARCHAR(36)Player UUID
tax_typeVARCHAR(20)LAND / WEALTH / DEBT_PAYMENT
amountDOUBLEAmount paid
timestampBIGINTPayment timestamp
descriptionVARCHAR(255)Transaction details

evasion_alerts​

ColumnTypeDescription
idVARCHAR(36)Alert UUID (Primary Key)
player_idVARCHAR(36)Suspect player UUID
player_nameVARCHAR(16)Player name
alert_typeVARCHAR(30)RAPID_TRANSFER / LARGE_TRANSFER
detailsTEXTAlert details
timestampBIGINTDetection timestamp
resolvedBOOLEANAdmin reviewed status
resolved_byVARCHAR(36)Admin who resolved

treasury​

ColumnTypeDescription
idVARCHAR(255)Always treasury (Primary Key)
balanceDOUBLECurrent balance
total_collectedDOUBLETotal ever deposited
last_collection_timeBIGINTWhen the last collection ran

Installation​

  1. Place the plugin JAR in your plugins folder
  2. Ensure Vault and an economy plugin are installed
  3. (Optional) Install GriefPrevention for land taxes
  4. (Optional) Install PlaceholderAPI for placeholders
  5. Start/restart the server
  6. Configure the plugin with /tax admin, or edit config.yml and messages.yml
  7. Use /tax admin reload to apply file changes (they are also picked up automatically)

Data Migration​

To switch from JSON to SQL storage:

  1. Export current data: /tax admin export
  2. Change storage.type to sql in config.yml
  3. Configure SQL connection settings
  4. Restart the server
  5. Import data: /tax admin import (this also restores the treasury)

Retention​

Tax records and resolved evasion alerts are kept forever by default. Set retention.tax-records-days or retention.resolved-alerts-days to remove older entries; they are removed at startup and after each collection. Unresolved alerts are never removed.