Developer Guide
Table of contents
- Architecture overview
- Key classes
- Jaloquent integration
- Tax sink routing
- Building
- Adding a new tax type
- Contribution
Architecture overview
EzTax is structured around a bootstrap-component pattern:
EzTaxPlugin
└── PluginBootstrap
├── ConfigComponent ← loads TaxConfig from config.yml
├── MetricsComponent ← registers bStats
├── StatsComponent ← wires Jaloquent storage + StatsService
├── ExemptionService ← permission-based exemptions
├── EconomyComponent ← hooks Vault + registers TaxedEconomy wrapper
├── TaxEngineComponent ← builds TaxEngine
├── ListenerComponent ← registers death/command listeners
├── SchedulerComponent ← schedules wealth/inactivity cycles
└── CommandComponent ← registers /tax subcommands
Each component implements Component (start(), stop(), reload()).
Key classes
| Class | Package | Purpose |
|---|---|---|
TaxEngine | service | Applies wealth, inactivity, death, and transaction taxes |
StatsService | service | In-memory stats with periodic save via repository |
TaxConfig | config | Typed wrapper over Bukkit FileConfiguration |
SinkDestination | service | Enum for tax routing: BURN, PLAYER, POOL, COMMAND |
VaultHook | economy | Vault economy/permissions bridge |
TaxedEconomy | economy | Vault Economy proxy that intercepts withdraw/deposit |
StatsModel | storage | Jaloquent Model representing persisted stats |
BukkitYamlDataStore | storage | Jaloquent DataStore adapter for Bukkit YAML files |
JaloquentStatsRepository | repository | StatsRepository backed by ModelRepository<StatsModel> |
Jaloquent integration
EzTax uses Jaloquent (com.github.EzFramework:jaloquent:1.1.0) as its persistence layer. Jaloquent is shaded and relocated into com.skyblockexp.eztax.libs.jaloquent.
Data model
StatsModel extends Model holds all aggregated statistics as named attributes:
model.setTotalRemoved(1234.56);
model.setSinkTotal(TaxSink.WEALTH, 500.0);
model.getDailyResetDate(); // ISO date string
The model is always stored with ID "stats" (singleton pattern).
YAML store
BukkitYamlDataStore implements DataStore wraps a Bukkit YAML file. Jaloquent paths are converted to YAML keys by replacing / with .:
path: eztax_stats/stats
yaml key: eztax_stats.stats.total_removed
MySQL store
When storage.type: mysql is configured:
TableRegistry.register("eztax_stats", tableName, StatsModel.COLUMN_DEFS)registers the schema.DataSourceJdbcStore(dataSource)is passed toJaloquentStatsRepository.ModelRepositorydetects theTableRegistryentry and routes all operations through SQL.
Repository wiring
StatsComponent.start() selects the appropriate DataStore and constructs the repository:
DataStore store = "mysql".equals(type)
? new DataSourceJdbcStore(ds) // with TableRegistry.register(...)
: new BukkitYamlDataStore(file);
StatsRepository repo = new JaloquentStatsRepository(store, "eztax_stats");
Tax sink routing
After a successful economy.withdrawPlayer() call, TaxEngine.distributeTax(amount) routes money to the configured tax-sink.destination:
| Destination | Behaviour |
|---|---|
burn | Nothing — money is already removed from the economy |
player | economy.depositPlayer(target, amount) |
pool | Split amount / onlinePlayers.size() and deposit to each |
command | Bukkit.dispatchCommand(console, cmd.replace("%amount%", ...)) |
Building
# Compile
mvn compile
# Run tests
mvn test
# Package (shaded JAR)
mvn package -DskipTests
The parent POM (com.skyblockexp:skyblockexp-parent) must be installed in the local Maven repository. Clone the skyblock-experience monorepo and run mvn install -N in its root.
Adding a new tax type
- Add a value to
TaxSinkenum. - Add
COLUMN_DEFSentries inStatsModelfor the new sink key. - Implement the tax logic in
TaxEngineand callwithdrawSafely(player, amount, TaxSink.YOUR_SINK). - Add config keys to
TaxConfigandconfig.yml. - Register the listener or scheduler in the appropriate bootstrap component.
Contribution
- Follow existing code style (no Lombok, minimal dependencies).
- Write JUnit 5 tests for new service logic under
src/test/. - Format: 4-space indentation, Allman braces for new classes.
- Open a pull request against the
mainbranch with a clear description.